Harden CV rewrite diagnostics and preview PDFs

This commit is contained in:
2026-04-11 21:36:45 +02:00
parent fcccecefa3
commit 534534b333
4 changed files with 371 additions and 48 deletions
+30 -1
View File
@@ -6,6 +6,17 @@ import { I18nProvider } from './i18n/I18nProvider';
import ProfilePage from './pages/ProfilePage';
import { api } from './api';
const createObjectURLMock = jest.fn(() => 'blob:mock-pdf');
const revokeObjectURLMock = jest.fn();
Object.defineProperty(window.URL, 'createObjectURL', {
writable: true,
value: createObjectURLMock,
});
Object.defineProperty(window.URL, 'revokeObjectURL', {
writable: true,
value: revokeObjectURLMock,
});
jest.mock('./api', () => ({
api: {
get: jest.fn(),
@@ -22,6 +33,8 @@ jest.mock('./components/CropImageDialog', () => () => null);
const mockedApi = api as jest.Mocked<typeof api>;
const REWRITE_TEMPLATES_COUNT = 6;
const structuredCv = {
version: '1',
metadata: {
@@ -131,7 +144,7 @@ beforeEach(() => {
}
return Promise.resolve({ data: {} } as any);
});
mockedApi.post.mockImplementation((url: string) => {
mockedApi.post.mockImplementation((url: string, payload?: any, config?: any) => {
if (url === '/profile-cv/parse') {
return Promise.resolve({
data: {
@@ -149,6 +162,9 @@ beforeEach(() => {
if (url === '/profile-cv/rewrite-preview') {
return Promise.resolve({ data: { templateId: 'harvard', html: '<html><body>Preview</body></html>', suggestedFileName: 'harvard-preview.pdf', fullText: 'Professional Summary\nClearer, sharper positioning for backend platform roles.', rewrittenText: 'Professional Summary\nClearer, sharper positioning for backend platform roles.', structuredCv, sectionName: null, jobApplicationId: 42, targetRole: 'Senior Backend Engineer' } } as any);
}
if (url === '/profile-cv/export-pdf') {
return Promise.resolve({ data: new Blob([`pdf-${payload?.templateId ?? 'ats-minimal'}`], { type: 'application/pdf' }), config } as any);
}
if (url === '/profile-cv/reprocess') {
return Promise.resolve({ data: { reprocessed: true } } as any);
}
@@ -160,6 +176,8 @@ beforeEach(() => {
afterEach(() => {
jest.clearAllMocks();
createObjectURLMock.mockClear();
revokeObjectURLMock.mockClear();
});
test('profile page loads persisted structured cv and can re-parse it', async () => {
@@ -247,6 +265,17 @@ test('profile page rewrite tools use selected template and saved job context', a
expect(await screen.findByText(/preview ready/i)).toBeInTheDocument();
expect(screen.getByText(/clearer, sharper positioning for backend platform roles/i)).toBeInTheDocument();
expect(screen.getByRole('heading', { name: /pdf carousel/i })).toBeInTheDocument();
const buildCarouselButton = screen.getByRole('button', { name: /build pdf carousel/i });
fireEvent.click(buildCarouselButton);
await waitFor(() => {
const exportCalls = mockedApi.post.mock.calls.filter(([url]) => url === '/profile-cv/export-pdf');
expect(exportCalls.length).toBe(REWRITE_TEMPLATES_COUNT);
});
await waitFor(() => expect(createObjectURLMock).toHaveBeenCalledTimes(REWRITE_TEMPLATES_COUNT));
});
test('saving profile persists structured cv json', async () => {