mirror of
https://github.com/portainer/portainer.git
synced 2025-07-19 13:29:41 +02:00
feat(editor): provide yaml validation for docker compose in the portainer web editor [BE-11697] (#526)
This commit is contained in:
parent
0ebfe047d1
commit
81c5f4acc3
27 changed files with 2046 additions and 36 deletions
115
app/react/components/CodeEditor.test.tsx
Normal file
115
app/react/components/CodeEditor.test.tsx
Normal file
|
@ -0,0 +1,115 @@
|
|||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { CodeEditor } from './CodeEditor';
|
||||
|
||||
vi.mock('yaml-schema', () => ({}));
|
||||
|
||||
const defaultProps = {
|
||||
id: 'test-editor',
|
||||
onChange: vi.fn(),
|
||||
value: '',
|
||||
'data-cy': 'test-editor',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test('should render with basic props', () => {
|
||||
render(<CodeEditor {...defaultProps} />);
|
||||
expect(screen.getByRole('textbox')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should display placeholder when provided', async () => {
|
||||
const placeholder = 'Enter your code here';
|
||||
const { findByText } = render(
|
||||
<CodeEditor {...defaultProps} placeholder={placeholder} />
|
||||
);
|
||||
|
||||
const placeholderText = await findByText(placeholder);
|
||||
expect(placeholderText).toBeVisible();
|
||||
});
|
||||
|
||||
test('should show copy button and copy content', async () => {
|
||||
const testValue = 'test content';
|
||||
const { findByText } = render(
|
||||
<CodeEditor {...defaultProps} value={testValue} />
|
||||
);
|
||||
|
||||
const mockClipboard = {
|
||||
writeText: vi.fn(),
|
||||
};
|
||||
Object.assign(navigator, {
|
||||
clipboard: mockClipboard,
|
||||
});
|
||||
|
||||
const copyButton = await findByText('Copy to clipboard');
|
||||
expect(copyButton).toBeVisible();
|
||||
|
||||
await userEvent.click(copyButton);
|
||||
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(testValue);
|
||||
});
|
||||
|
||||
test('should handle read-only mode', async () => {
|
||||
const { findByRole } = render(<CodeEditor {...defaultProps} readonly />);
|
||||
const editor = await findByRole('textbox');
|
||||
// the editor should not editable
|
||||
await userEvent.type(editor, 'test');
|
||||
expect(editor).not.toHaveValue('test');
|
||||
});
|
||||
|
||||
test('should show version selector when versions are provided', async () => {
|
||||
const versions = [1, 2, 3];
|
||||
const onVersionChange = vi.fn();
|
||||
const { findByRole } = render(
|
||||
<CodeEditor
|
||||
{...defaultProps}
|
||||
versions={versions}
|
||||
onVersionChange={onVersionChange}
|
||||
/>
|
||||
);
|
||||
|
||||
const selector = await findByRole('combobox');
|
||||
expect(selector).toBeVisible();
|
||||
});
|
||||
|
||||
test('should handle YAML indentation correctly', async () => {
|
||||
const onChange = vi.fn();
|
||||
const yamlContent = 'services:';
|
||||
|
||||
const { findByRole } = render(
|
||||
<CodeEditor
|
||||
{...defaultProps}
|
||||
value={yamlContent}
|
||||
onChange={onChange}
|
||||
type="yaml"
|
||||
/>
|
||||
);
|
||||
|
||||
const editor = await findByRole('textbox');
|
||||
await userEvent.type(editor, '{enter}');
|
||||
await userEvent.keyboard('database:');
|
||||
await userEvent.keyboard('{enter}');
|
||||
await userEvent.keyboard('image: nginx');
|
||||
await userEvent.keyboard('{enter}');
|
||||
await userEvent.keyboard('name: database');
|
||||
|
||||
// Wait for the debounced onChange to be called
|
||||
setTimeout(() => {
|
||||
expect(onChange).toHaveBeenCalledWith(
|
||||
'services:\n database:\n image: nginx\n name: database'
|
||||
);
|
||||
// debounce timeout is 300ms, so 500ms is enough
|
||||
}, 500);
|
||||
});
|
||||
|
||||
test('should apply custom height', async () => {
|
||||
const customHeight = '300px';
|
||||
const { findByRole } = render(
|
||||
<CodeEditor {...defaultProps} height={customHeight} />
|
||||
);
|
||||
|
||||
const editor = (await findByRole('textbox')).parentElement?.parentElement;
|
||||
expect(editor).toHaveStyle({ height: customHeight });
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue