fix(cv): expose editor errors and controls
CI and Deploy / test (pull_request) Failing after 1m29s
CI and Deploy / deploy (pull_request) Has been skipped

This commit is contained in:
cesnimda
2026-08-09 21:06:11 +02:00
parent a5b74e0ab8
commit 20433491db
2 changed files with 58 additions and 12 deletions
@@ -1,6 +1,6 @@
import React from 'react';
import '@testing-library/jest-dom';
import { fireEvent, render, screen } from '@testing-library/react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { createMemoryRouter, RouterProvider } from 'react-router-dom';
import CvBuilderEditor from './views/CvBuilderEditor';
@@ -56,11 +56,11 @@ beforeEach(() => {
mockedApi.post.mockResolvedValue({ data: { themeId: 'nordic', html: '<p>cv</p>', suggestedFileName: 'cv.pdf' } } as any);
});
function routeGet(onVariant: () => Promise<any>) {
function routeGet(onVariant: () => Promise<any>, outline: any = { sections: [] }) {
mockedApi.get.mockImplementation((url: string) => {
if (url === '/cv/variants/3') return onVariant();
if (url === '/cv/themes') return Promise.resolve({ data: [] } as any);
if (url === '/cv/outline') return Promise.resolve({ data: { sections: [] } } as any);
if (url === '/cv/outline') return Promise.resolve({ data: outline } as any);
return Promise.resolve({ data: [] } as any);
});
}
@@ -173,3 +173,42 @@ test('custom entries can be added, edited, reordered and deleted with confirmati
expect(screen.queryByLabelText('Custom section title')).not.toBeInTheDocument();
confirm.mockRestore();
});
test('profile-backed sections expand, reorder, hide and persist variant-only overrides', async () => {
routeGet(() => Promise.resolve({ data: variant } as any), {
sections: [{
key: 'experience', title: 'Experience', kind: 'entries', bullets: [], tags: [], entries: [
{ key: 'job-1', title: 'Engineer', subtitle: 'First Co', bullets: ['Built APIs'], tags: [] },
{ key: 'job-2', title: 'Lead', subtitle: 'Second Co', bullets: ['Led teams'], tags: [] },
],
}],
});
mockedApi.put.mockResolvedValue({ data: variant } as any);
renderAt(3);
fireEvent.click(await screen.findByRole('button', { name: 'Expand Experience entries' }));
expect(screen.getByRole('button', { name: 'Collapse Experience entries' })).toHaveAttribute('aria-expanded', 'true');
fireEvent.click(screen.getByRole('button', { name: 'Move Engineer entry down' }));
fireEvent.click(screen.getByRole('button', { name: 'Hide Lead entry' }));
fireEvent.click(screen.getByRole('button', { name: 'Move Experience section down' }));
fireEvent.click(screen.getByRole('button', { name: 'Save now' }));
expect(await screen.findByText('Saved')).toBeInTheDocument();
expect(mockedApi.put).toHaveBeenLastCalledWith('/cv/variants/3', expect.objectContaining({
settings: expect.objectContaining({
sections: expect.arrayContaining([expect.objectContaining({ key: 'experience', itemOrder: ['job-2', 'job-1'] })]),
overrides: expect.objectContaining({ 'job-2': expect.objectContaining({ hidden: true }) }),
}),
}));
});
test('preview failure is visible and retryable without leaving the editor', async () => {
routeGet(() => Promise.resolve({ data: variant } as any));
mockedApi.post.mockRejectedValueOnce(new Error('preview offline')).mockResolvedValueOnce({ data: { themeId: 'modern', html: '<p>retry</p>', suggestedFileName: 'cv.pdf' } } as any);
renderAt(3);
expect(await screen.findByText('Preview unavailable')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Retry preview' }));
await waitFor(() => expect(screen.getByTitle('CV preview')).toHaveAttribute('srcdoc', '<p>retry</p>'));
await waitFor(() => expect(screen.queryByText('Preview unavailable')).not.toBeInTheDocument());
});