Use structured CV sections in tailoring and test profile parsing

This commit is contained in:
cesnimda
2026-03-23 23:56:27 +01:00
parent c33640986e
commit a710d63bb7
2 changed files with 157 additions and 3 deletions
+110
View File
@@ -0,0 +1,110 @@
import React from 'react';
import '@testing-library/jest-dom';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { ToastProvider } from './toast';
import { I18nProvider } from './i18n/I18nProvider';
import ProfilePage from './pages/ProfilePage';
import { api } from './api';
jest.mock('./api', () => ({
api: {
get: jest.fn(),
post: jest.fn(),
put: jest.fn(),
patch: jest.fn(),
delete: jest.fn(),
interceptors: { request: { use: jest.fn() }, response: { use: jest.fn() } },
},
}));
jest.mock('./components/GoogleAuthCard', () => () => null);
jest.mock('./components/CropImageDialog', () => () => null);
const mockedApi = api as jest.Mocked<typeof api>;
function renderPage() {
return render(
<ToastProvider>
<I18nProvider>
<ProfilePage />
</I18nProvider>
</ToastProvider>,
);
}
beforeEach(() => {
mockedApi.get.mockImplementation((url: string) => {
if (url === '/auth/me') {
return Promise.resolve({
data: {
provider: 'local',
email: 'demo@example.com',
userName: 'demo',
firstName: 'Demo',
lastName: 'User',
displayName: 'Demo User',
profileCvText: 'Professional Summary\nBuilt backend systems',
profileCvStructureJson: JSON.stringify([
{ name: 'Professional Summary', content: 'Built backend systems', wordCount: 3 },
]),
googleLink: { linked: false },
},
} as any);
}
return Promise.resolve({ data: {} } as any);
});
mockedApi.post.mockImplementation((url: string) => {
if (url === '/profile-cv/parse') {
return Promise.resolve({
data: {
sections: [
{ name: 'Professional Summary', content: 'Built backend systems', wordCount: 3 },
{ name: 'Core Skills', content: '.NET\nSQL\nAzure', wordCount: 3 },
],
},
} as any);
}
return Promise.resolve({ data: {} } as any);
});
mockedApi.put.mockResolvedValue({ data: {} } as any);
window.localStorage.clear();
});
afterEach(() => {
jest.clearAllMocks();
});
test('profile page loads persisted cv sections and can re-parse them', async () => {
renderPage();
expect(await screen.findByText(/cv ready/i)).toBeInTheDocument();
expect(screen.getByText(/cv structure overview/i)).toBeInTheDocument();
expect(screen.getAllByText(/professional summary/i).length).toBeGreaterThan(0);
const analyzeButton = screen.getByRole('button', { name: /analyze sections/i });
await waitFor(() => expect(analyzeButton).toBeEnabled());
fireEvent.click(analyzeButton);
await waitFor(() => {
expect(mockedApi.post).toHaveBeenCalledWith('/profile-cv/parse', { text: 'Professional Summary\nBuilt backend systems' });
});
expect(await screen.findByText(/core skills/i)).toBeInTheDocument();
});
test('saving profile persists structured cv json', async () => {
renderPage();
expect(await screen.findByText(/cv ready/i)).toBeInTheDocument();
const saveButton = screen.getByRole('button', { name: /save changes/i });
await waitFor(() => expect(saveButton).toBeEnabled());
fireEvent.click(saveButton);
await waitFor(() => {
expect(mockedApi.put).toHaveBeenCalledWith('/auth/profile', expect.objectContaining({
profileCvStructureJson: JSON.stringify([
{ name: 'Professional Summary', content: 'Built backend systems', wordCount: 3 },
]),
}));
});
});