feat(cv): harden multi-page builder
Wrap pathological content, paginate oversized entries, measure A4 and Letter previews correctly, unify section ordering, and gate stored-output actions on saved state.
This commit is contained in:
@@ -7,6 +7,8 @@ import CvBuilderPage from './views/CvBuilderPage';
|
||||
import { I18nProvider } from './i18n/I18nProvider';
|
||||
import { ToastProvider } from './toast';
|
||||
import { api } from './api';
|
||||
import { ConfirmProvider } from './confirm';
|
||||
import { PromptProvider } from './prompt';
|
||||
|
||||
const mockNavigate = jest.fn();
|
||||
jest.mock('react-router-dom', () => ({
|
||||
@@ -33,7 +35,11 @@ function renderPage() {
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
|
||||
<ToastProvider>
|
||||
<I18nProvider>
|
||||
<CvBuilderPage />
|
||||
<ConfirmProvider>
|
||||
<PromptProvider>
|
||||
<CvBuilderPage />
|
||||
</PromptProvider>
|
||||
</ConfirmProvider>
|
||||
</I18nProvider>
|
||||
</ToastProvider>
|
||||
</MemoryRouter>,
|
||||
@@ -71,3 +77,25 @@ test('shows the empty state and creates a CV then navigates to the editor', asyn
|
||||
await waitFor(() => expect(mockedApi.post).toHaveBeenCalledWith('/cv/variants', expect.objectContaining({ name: 'Untitled CV' })));
|
||||
await waitFor(() => expect(mockNavigate).toHaveBeenCalledWith('/career/builder/42'));
|
||||
});
|
||||
|
||||
test('CV deletion requires confirmation and supports cancellation', async () => {
|
||||
mockedApi.get.mockResolvedValueOnce({ data: [
|
||||
{ id: 1, name: 'Frontend CV', themeId: 'modern', publicSlug: 'abc', isPublic: false, version: 2, jobApplicationId: null, updatedAtUtc: new Date().toISOString() },
|
||||
] } as any);
|
||||
mockedApi.delete.mockResolvedValue({ data: null } as any);
|
||||
renderPage();
|
||||
|
||||
await screen.findByText('Frontend CV');
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Actions for Frontend CV' }));
|
||||
fireEvent.click(await screen.findByRole('menuitem', { name: 'Delete' }));
|
||||
expect(await screen.findByRole('dialog', { name: 'Delete CV' })).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Cancel' }));
|
||||
await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument());
|
||||
expect(mockedApi.delete).not.toHaveBeenCalled();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Actions for Frontend CV' }));
|
||||
fireEvent.click(await screen.findByRole('menuitem', { name: 'Delete' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: 'Delete CV' }));
|
||||
await waitFor(() => expect(mockedApi.delete).toHaveBeenCalledWith('/cv/variants/1'));
|
||||
await waitFor(() => expect(screen.queryByText('Frontend CV')).not.toBeInTheDocument());
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user