feat(tests): Jest backend (38 tests), Jest RTL frontend (28 tests), Playwright E2E spec
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import ExperimentForm from '../src/components/ExperimentForm';
|
||||
import * as client from '../src/api/client';
|
||||
|
||||
jest.mock('../src/api/client', () => ({
|
||||
experimentsApi: {
|
||||
create: jest.fn(),
|
||||
update: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const onSuccess = jest.fn();
|
||||
const onCancel = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('ExperimentForm', () => {
|
||||
it('renders title input and submit button', () => {
|
||||
render(<ExperimentForm onSuccess={onSuccess} onCancel={onCancel} />);
|
||||
expect(screen.getByLabelText(/experiment title/i)).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: /create experiment/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows validation error when submitting empty title', async () => {
|
||||
render(<ExperimentForm onSuccess={onSuccess} onCancel={onCancel} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /create experiment/i }));
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent(/title is required/i);
|
||||
expect(client.experimentsApi.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shows error when title exceeds 255 chars', async () => {
|
||||
render(<ExperimentForm onSuccess={onSuccess} onCancel={onCancel} />);
|
||||
await userEvent.type(screen.getByLabelText(/experiment title/i), 'x'.repeat(256));
|
||||
fireEvent.click(screen.getByRole('button', { name: /create experiment/i }));
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent(/255/i);
|
||||
expect(client.experimentsApi.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls create API with trimmed title and calls onSuccess', async () => {
|
||||
const experiment = { id: 'abc-123', title: 'New Study' };
|
||||
client.experimentsApi.create.mockResolvedValue(experiment);
|
||||
|
||||
render(<ExperimentForm onSuccess={onSuccess} onCancel={onCancel} />);
|
||||
await userEvent.type(screen.getByLabelText(/experiment title/i), 'New Study');
|
||||
fireEvent.click(screen.getByRole('button', { name: /create experiment/i }));
|
||||
|
||||
await waitFor(() => expect(client.experimentsApi.create).toHaveBeenCalledWith({ title: 'New Study' }));
|
||||
await waitFor(() => expect(onSuccess).toHaveBeenCalledWith(experiment));
|
||||
});
|
||||
|
||||
it('shows "Save Changes" button for existing experiment', () => {
|
||||
render(
|
||||
<ExperimentForm
|
||||
existing={{ id: 'abc', title: 'Old Title' }}
|
||||
onSuccess={onSuccess}
|
||||
onCancel={onCancel}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByRole('button', { name: /save changes/i })).toBeInTheDocument();
|
||||
expect(screen.getByDisplayValue('Old Title')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls update API for existing experiment', async () => {
|
||||
const updated = { id: 'abc', title: 'Updated Title' };
|
||||
client.experimentsApi.update.mockResolvedValue(updated);
|
||||
|
||||
render(
|
||||
<ExperimentForm
|
||||
existing={{ id: 'abc', title: 'Old Title' }}
|
||||
onSuccess={onSuccess}
|
||||
onCancel={onCancel}
|
||||
/>
|
||||
);
|
||||
|
||||
const input = screen.getByDisplayValue('Old Title');
|
||||
await userEvent.clear(input);
|
||||
await userEvent.type(input, 'Updated Title');
|
||||
fireEvent.click(screen.getByRole('button', { name: /save changes/i }));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(client.experimentsApi.update).toHaveBeenCalledWith('abc', { title: 'Updated Title' })
|
||||
);
|
||||
await waitFor(() => expect(onSuccess).toHaveBeenCalledWith(updated));
|
||||
});
|
||||
|
||||
it('calls onCancel when Cancel is clicked', () => {
|
||||
render(<ExperimentForm onSuccess={onSuccess} onCancel={onCancel} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /cancel/i }));
|
||||
expect(onCancel).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shows API error when create fails', async () => {
|
||||
client.experimentsApi.create.mockRejectedValue({ message: 'Server error', details: null });
|
||||
|
||||
render(<ExperimentForm onSuccess={onSuccess} onCancel={onCancel} />);
|
||||
await userEvent.type(screen.getByLabelText(/experiment title/i), 'Test');
|
||||
fireEvent.click(screen.getByRole('button', { name: /create experiment/i }));
|
||||
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent(/server error/i);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user