78 lines
2.5 KiB
TypeScript
78 lines
2.5 KiB
TypeScript
|
|
import { describe, it, expect, afterEach, vi } from 'vitest';
|
||
|
|
import { screen, fireEvent, waitFor } from '@testing-library/react';
|
||
|
|
import { EngagementCreateDialog } from './EngagementCreateDialog';
|
||
|
|
import { installFetchMock, renderWithProviders } from '@/test/testUtils';
|
||
|
|
|
||
|
|
describe('EngagementCreateDialog', () => {
|
||
|
|
let fetchMock: ReturnType<typeof installFetchMock>;
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
fetchMock?.restore();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('rejects empty name client-side without calling the backend', () => {
|
||
|
|
fetchMock = installFetchMock([]);
|
||
|
|
renderWithProviders(<EngagementCreateDialog onClose={vi.fn()} />);
|
||
|
|
fireEvent.click(screen.getByRole('button', { name: /arm engagement/i }));
|
||
|
|
expect(screen.getByText(/nom requis/i)).toBeInTheDocument();
|
||
|
|
expect(fetchMock.calls).toHaveLength(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('maps 422 Pydantic errors to per-field messages', async () => {
|
||
|
|
fetchMock = installFetchMock([
|
||
|
|
{
|
||
|
|
status: 422,
|
||
|
|
body: {
|
||
|
|
detail: [
|
||
|
|
{
|
||
|
|
loc: ['body', 'name'],
|
||
|
|
msg: 'String should have at least 3 characters',
|
||
|
|
type: 'string_too_short',
|
||
|
|
},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
},
|
||
|
|
]);
|
||
|
|
renderWithProviders(<EngagementCreateDialog onClose={vi.fn()} />);
|
||
|
|
|
||
|
|
fireEvent.change(screen.getByLabelText(/engagement name/i), { target: { value: 'AB' } });
|
||
|
|
fireEvent.click(screen.getByRole('button', { name: /arm engagement/i }));
|
||
|
|
|
||
|
|
await waitFor(() => {
|
||
|
|
expect(screen.getByText(/at least 3 characters/i)).toBeInTheDocument();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('invalidates the engagements query and closes on success', async () => {
|
||
|
|
const onClose = vi.fn();
|
||
|
|
fetchMock = installFetchMock([
|
||
|
|
{
|
||
|
|
status: 201,
|
||
|
|
body: {
|
||
|
|
id: 'eng_new',
|
||
|
|
name: 'OPERATION ZETA',
|
||
|
|
client_name: null,
|
||
|
|
description: null,
|
||
|
|
status: 'planning',
|
||
|
|
c2_type: null,
|
||
|
|
start_date: null,
|
||
|
|
end_date: null,
|
||
|
|
created_at: '2026-05-23T08:00:00Z',
|
||
|
|
},
|
||
|
|
},
|
||
|
|
]);
|
||
|
|
renderWithProviders(<EngagementCreateDialog onClose={onClose} />);
|
||
|
|
|
||
|
|
fireEvent.change(screen.getByLabelText(/engagement name/i), {
|
||
|
|
target: { value: 'OPERATION ZETA' },
|
||
|
|
});
|
||
|
|
fireEvent.click(screen.getByRole('button', { name: /arm engagement/i }));
|
||
|
|
|
||
|
|
await waitFor(() => {
|
||
|
|
expect(onClose).toHaveBeenCalledTimes(1);
|
||
|
|
});
|
||
|
|
expect(fetchMock.calls[0]?.url).toBe('/api/v1/engagements');
|
||
|
|
expect(fetchMock.calls[0]?.init?.method).toBe('POST');
|
||
|
|
});
|
||
|
|
});
|