feat(cv): harden multi-page builder
CI and Deploy / test (pull_request) Failing after 3m0s
CI and Deploy / deploy (pull_request) Has been skipped

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:
cesnimda
2026-08-15 14:09:51 +02:00
parent d424633f95
commit 5203ddea72
19 changed files with 508 additions and 206 deletions
+29 -1
View File
@@ -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());
});