Files
TREK/client/src/components/Planner/BookingNotesFilesCosts.test.tsx
T
Maurice e8fbba236d refactor(bookings): hand the notes and link to the shared lower part as form fields
The booking and transport dialogs each spelled out the notes and the link
as four value and change props, and with the saving flag the two calls
became one copied block. The shared lower part now takes the form and its
setter, as the dialogs hold them, and writes the two fields itself.
2026-10-29 15:50:09 +01:00

108 lines
3.5 KiB
TypeScript

// FE-PLANNER-NOTESFILESCOSTS-001 to FE-PLANNER-NOTESFILESCOSTS-004
import { createRef, type ComponentProps } from 'react';
import { describe, expect, it, vi } from 'vitest';
import { fireEvent, render, screen } from '../../../tests/helpers/render';
import { BookingNotesFilesCosts } from './BookingNotesFilesCosts';
const linkAndFiles = vi.fn();
const costs = vi.fn();
vi.mock('./BookingLinkAndFiles', () => ({
BookingLinkAndFiles: (props: Record<string, unknown>) => {
linkAndFiles(props);
return <div data-testid="link-and-files" />;
},
}));
vi.mock('./BookingCostsSection', () => ({
BookingCostsSection: (props: Record<string, unknown>) => {
costs(props);
return <div data-testid="costs" />;
},
}));
type Props = ComponentProps<typeof BookingNotesFilesCosts>;
function setup(overrides: Partial<Props> = {}) {
linkAndFiles.mockClear();
costs.mockClear();
const props: Props = {
form: { notes: 'Gate B', url: 'https://example.com' },
set: vi.fn(),
reservationId: 9,
tripFiles: [],
pendingFiles: [],
fileInputRef: createRef<HTMLInputElement>(),
attach: {
handleFileChange: vi.fn(),
attachedFiles: [],
removePending: vi.fn(),
linkFile: vi.fn(),
detachFile: vi.fn(),
},
canAttach: true,
saving: false,
showCosts: true,
pendingExpense: null,
expense: { reset: vi.fn(), take: vi.fn(), create: vi.fn(), edit: vi.fn(), remove: vi.fn() },
...overrides,
};
render(<BookingNotesFilesCosts {...props} />);
return props;
}
describe('BookingNotesFilesCosts', () => {
it('FE-PLANNER-NOTESFILESCOSTS-001: shows the notes and reports an edit', () => {
const props = setup();
const area = screen.getByPlaceholderText('Additional notes...');
expect(area).toHaveValue('Gate B');
fireEvent.change(area, { target: { value: 'Gate C' } });
expect(props.set).toHaveBeenCalledWith('notes', 'Gate C');
});
it('FE-PLANNER-NOTESFILESCOSTS-002: hands the link, the files and the costs their parts of the booking', () => {
const props = setup();
expect(linkAndFiles).toHaveBeenCalledWith(
expect.objectContaining({
url: 'https://example.com',
reservationId: 9,
canAttach: true,
uploading: false,
onFileChange: props.attach.handleFileChange,
onRemovePending: props.attach.removePending,
onLinked: props.attach.linkFile,
onDetached: props.attach.detachFile,
})
);
linkAndFiles.mock.calls[0][0].onUrlChange('https://example.org');
expect(props.set).toHaveBeenCalledWith('url', 'https://example.org');
expect(costs).toHaveBeenCalledWith(
expect.objectContaining({
reservationId: 9,
pendingExpense: null,
onCreate: props.expense.create,
onEdit: props.expense.edit,
onRemove: props.expense.remove,
customTooltips: true,
})
);
});
it('FE-PLANNER-NOTESFILESCOSTS-003: leaves the costs out without the budget, and passes no id for a new booking', () => {
setup({ showCosts: false, reservationId: undefined });
expect(screen.getByTestId('link-and-files')).toBeInTheDocument();
expect(screen.queryByTestId('costs')).toBeNull();
expect(linkAndFiles).toHaveBeenCalledWith(expect.objectContaining({ reservationId: undefined }));
});
it('FE-PLANNER-NOTESFILESCOSTS-004: shows the files as uploading while the booking saves', () => {
setup({ saving: true });
expect(linkAndFiles).toHaveBeenCalledWith(expect.objectContaining({ uploading: true }));
});
});