Complete S02 application package drafting loop

This commit is contained in:
2026-03-24 10:36:05 +01:00
parent 3e5f796326
commit b5b430947b
14 changed files with 864 additions and 152 deletions
@@ -46,7 +46,19 @@ beforeEach(() => {
mockedApi.get.mockImplementation((url: string) => {
if (url === '/jobapplications/42') {
return Promise.resolve({ data: { id: 42, jobTitle: 'Backend Developer', status: 'Applied', dateApplied: new Date().toISOString(), daysSince: 3, company: { name: 'Acme', recruiterEmail: 'recruiter@acme.test' }, tailoredCvText: '', shortSummary: 'summary' } } as any);
return Promise.resolve({ data: {
id: 42,
jobTitle: 'Backend Developer',
status: 'Applied',
dateApplied: new Date().toISOString(),
daysSince: 3,
company: { name: 'Acme', recruiterEmail: 'recruiter@acme.test' },
tailoredCvText: 'Saved CV',
coverLetterText: 'Saved cover letter',
recruiterMessageDraft: 'Saved recruiter message',
notes: 'Original notes\n\n<<<APPLICATION_ANSWER_DRAFT>>>\nSaved application answer\n<<<END_APPLICATION_ANSWER_DRAFT>>>',
shortSummary: 'summary'
} } as any);
}
if (url === '/auth/me') {
return Promise.resolve({ data: { roles: [], profileCvText: 'Master CV text' } } as any);
@@ -73,25 +85,40 @@ afterEach(() => {
jest.clearAllMocks();
});
test('generated application package can be edited and saved', async () => {
test('application package workspace reflects saved job material, generated drafts, and save state', async () => {
renderDialog();
fireEvent.click(await screen.findByRole('tab', { name: /tailored cv/i }));
expect(await screen.findByRole('button', { name: /generate application package/i })).toBeInTheDocument();
expect(await screen.findByDisplayValue('Saved CV')).toBeInTheDocument();
expect(await screen.findByDisplayValue('Saved cover letter')).toBeInTheDocument();
expect(await screen.findByDisplayValue('Saved application answer')).toBeInTheDocument();
expect(await screen.findByDisplayValue('Saved recruiter message')).toBeInTheDocument();
expect(await screen.findByText(/saved working material/i)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: /generate application package/i }));
expect(await screen.findByDisplayValue('Generated CV')).toBeInTheDocument();
expect(await screen.findByText(/cover letter variants/i)).toBeInTheDocument();
const coverLetter = await screen.findByDisplayValue('Draft letter');
fireEvent.change(coverLetter, { target: { value: 'Edited cover letter' } });
const applicationAnswer = await screen.findByDisplayValue('Draft answer');
const recruiterMessage = await screen.findByDisplayValue('Recruiter hello');
const saveButtons = await screen.findAllByRole('button', { name: /^save$/i });
fireEvent.click(saveButtons[0]);
fireEvent.change(coverLetter, { target: { value: 'Edited cover letter' } });
fireEvent.change(applicationAnswer, { target: { value: 'Edited answer' } });
fireEvent.change(recruiterMessage, { target: { value: 'Edited recruiter note' } });
fireEvent.click(screen.getByRole('button', { name: /save package to job/i }));
await waitFor(() => {
expect(mockedApi.put).toHaveBeenCalledWith('/jobapplications/42/application-drafts', { coverLetterText: 'Edited cover letter' });
expect(mockedApi.put).toHaveBeenCalledWith('/jobapplications/42/tailored-cv', { tailoredCvText: 'Generated CV' });
expect(mockedApi.put).toHaveBeenCalledWith('/jobapplications/42/application-drafts', {
coverLetterText: 'Edited cover letter',
notes: 'Original notes\n\n<<<APPLICATION_ANSWER_DRAFT>>>\nEdited answer\n<<<END_APPLICATION_ANSWER_DRAFT>>>',
recruiterMessageDraft: 'Edited recruiter note',
});
});
expect(await screen.findAllByText(/saved to job/i)).not.toHaveLength(0);
});
test('strategy snapshot can be generated from overview', async () => {