fix(rd21): retain draft revisions and qualify conflict recovery
This commit is contained in:
@@ -13,7 +13,7 @@ const password = 'E2ePassword123!';
|
||||
type Owner = { id: string; headers: Record<string, string> };
|
||||
type Sample = { language: 'en' | 'nb'; theme: 'light' | 'dark'; width: number; height: number };
|
||||
type Subsection = 'cv' | 'letter' | 'answers' | 'submission';
|
||||
type Job = { id: number; jobTitle: string; notes: string | null };
|
||||
type Job = { id: number; jobTitle: string; notes: string | null; version: number };
|
||||
type RequestRecord = { method: string; path: string; body: unknown };
|
||||
type Session = { owner: Owner; admin: APIRequestContext; administrator: Owner; requests: RequestRecord[] };
|
||||
const desktop: Sample = { language: 'en', theme: 'light', width: 1440, height: 900 };
|
||||
@@ -86,7 +86,7 @@ function profile(headline = 'Original reviewed career evidence') {
|
||||
summary: ['Canonical owner-reviewed evidence — æøå'], skills: ['C#', 'SQL'] };
|
||||
}
|
||||
async function source(api: APIRequestContext, owner: Owner, headline?: string) {
|
||||
return json(await api.put(`${apiUrl}/career/profile`, { headers: owner.headers, data: { profile: profile(headline), cvText: 'Exact owner-reviewed source — æøå' } }));
|
||||
return json(await api.put(`${apiUrl}/career/profile`, { headers: owner.headers, data: { expectedVersion: (await (await api.get(`${apiUrl}/career/profile`)).json()).revision, profile: profile(headline), cvText: 'Exact owner-reviewed source — æøå' } }));
|
||||
}
|
||||
async function createJob(api: APIRequestContext, owner: Owner, title = 'Recorded application material — æøå') {
|
||||
const company = await json<{ id: number }>(await api.post(`${apiUrl}/companies`, { headers: owner.headers, data: { name: 'Recorded application company — æøå', source: 'User' } }), 201);
|
||||
@@ -100,10 +100,10 @@ async function variant(api: APIRequestContext, owner: Owner, name: string) {
|
||||
} }));
|
||||
}
|
||||
async function saveLetter(api: APIRequestContext, owner: Owner, id: number, text: string) {
|
||||
return json<CoverLetter>(await api.put(`${jobUrl(id)}/cover-letter`, { headers: owner.headers, data: { text, source: 'manual' } }));
|
||||
return json<CoverLetter>(await api.put(`${jobUrl(id)}/cover-letter`, { headers: owner.headers, data: { expectedVersion: (await (await api.get(`${jobUrl(id)}/cover-letter`)).json()).revision, text, source: 'manual' } }));
|
||||
}
|
||||
async function saveDrafts(api: APIRequestContext, owner: Owner, id: number, answer: string, message: string) {
|
||||
expect((await api.put(`${jobUrl(id)}/application-drafts`, { headers: owner.headers, data: { applicationAnswerDraft: answer, recruiterMessageDraft: message } })).status()).toBe(204);
|
||||
expect((await api.put(`${jobUrl(id)}/application-drafts`, { headers: owner.headers, data: { expectedVersion: (await (await api.get(`${jobUrl(id)}`)).json()).version, applicationAnswerDraft: answer, recruiterMessageDraft: message } })).status()).toBe(204);
|
||||
}
|
||||
async function upload(api: APIRequestContext, owner: Owner, id: number) {
|
||||
const bytes = Buffer.from('Exact archived application evidence — æøå\nOriginal bytes retained.\n', 'utf8');
|
||||
@@ -186,7 +186,7 @@ test('[P7-06 PRES-W01 W04 W10] same-route job navigation waits for owned answers
|
||||
await expect(drafts(page).message).toHaveCount(0);
|
||||
expect(count(session, 'PUT', `/api/jobapplications/${second.id}/application-drafts`)).toHaveLength(0);
|
||||
await capture(page, info, desktop, 'held-second-job-aggregate-no-foreign-drafts');
|
||||
const loaded = response(page, 'GET', workspaceUrl); held.release(); await loaded;
|
||||
const loaded = response(page, 'GET', workspaceUrl); held.release(); const loadedOverview = await json<WorkspaceOverview>(await loaded);
|
||||
await expect(drafts(page).answer).toHaveValue(secondAnswer);
|
||||
await expect(drafts(page).message).toHaveValue(secondMessage);
|
||||
const reviewed = 'Edited second-job answer only — æøå';
|
||||
@@ -201,7 +201,7 @@ test('[P7-06 PRES-W01 W04 W10] same-route job navigation waits for owned answers
|
||||
const persistedFirst = await json<WorkspaceOverview>(await page.request.get(`${jobUrl(first.job.id)}/workspace`));
|
||||
expect(persistedFirst.applicationAnswerDraft).toBe(first.answer);
|
||||
expect(persistedFirst.recruiterMessageDraft).toBe(first.message);
|
||||
expect(count(session, 'PUT', `/api/jobapplications/${second.id}/application-drafts`)).toEqual([{ method: 'PUT', path: `/api/jobapplications/${second.id}/application-drafts`, body: { applicationAnswerDraft: reviewed, recruiterMessageDraft: secondMessage } }]);
|
||||
expect(count(session, 'PUT', `/api/jobapplications/${second.id}/application-drafts`)).toEqual([{ method: 'PUT', path: `/api/jobapplications/${second.id}/application-drafts`, body: { applicationAnswerDraft: reviewed, recruiterMessageDraft: secondMessage, expectedVersion: loadedOverview.revision } }]);
|
||||
await capture(page, info, desktop, 'second-job-answer-saved-first-job-preserved');
|
||||
} finally { held.release(); await page.unroute(workspaceUrl); }
|
||||
});
|
||||
@@ -302,7 +302,7 @@ test('[P7-06 forms] long letter failed held Save retains snapshot and dirty rest
|
||||
await keyboard(page, body.getByRole('button', { name: translations.en.save, exact: true })); await expect.poll(() => saves).toBe(1);
|
||||
await expect(letter(page)).toBeDisabled(); await expect(childFocus(page, translations.en.workspaceCoverLetter)).toBeFocused();
|
||||
await expect(body.getByRole('button', { name: translations.en.assetsDiscardChanges, exact: true })).toBeDisabled();
|
||||
expect(count(session, 'PUT', `/api/jobapplications/${seeded.job.id}/cover-letter`).map(value => value.body)).toEqual([{ text: draft, source: 'manual' }]);
|
||||
expect(count(session, 'PUT', `/api/jobapplications/${seeded.job.id}/cover-letter`).map(value => value.body)).toEqual([{ text: draft, source: 'manual', expectedVersion: before.revision }]);
|
||||
await capture(page, info, desktop, 'held-letter-save'); gate.release();
|
||||
await expect(body.getByRole('alert')).toContainText(translations.en.assetsCoverSaveFailed); await expect(letter(page)).toHaveValue(draft);
|
||||
expect(await json<CoverLetter>(await page.request.get(url))).toEqual(before); expect(saves).toBe(1);
|
||||
@@ -337,7 +337,7 @@ test('[P7-06 forms] failed held Answers save preserves both drafts and ordinary
|
||||
const body = section(page, translations.en.assetsApplicationDrafts);
|
||||
await keyboard(page, body.getByRole('button', { name: translations.en.assetsSaveDrafts, exact: true }));
|
||||
await expect.poll(() => writes).toBe(1); await expect(fields.answer).toBeDisabled(); await expect(fields.message).toBeDisabled(); await expect(childFocus(page, translations.en.assetsApplicationDrafts)).toBeFocused();
|
||||
expect(count(session, 'PUT', `/api/jobapplications/${seeded.job.id}/application-drafts`).map(value => value.body)).toEqual([{ applicationAnswerDraft: answer, recruiterMessageDraft: message }]);
|
||||
expect(count(session, 'PUT', `/api/jobapplications/${seeded.job.id}/application-drafts`).map(value => value.body)).toEqual([{ applicationAnswerDraft: answer, recruiterMessageDraft: message, expectedVersion: original.version }]);
|
||||
await capture(page, info, desktop, 'held-two-draft-save'); gate.release();
|
||||
await expect(body.getByRole('alert')).toContainText(translations.en.assetsDraftsSaveFailed); await expect(fields.answer).toHaveValue(answer); await expect(fields.message).toHaveValue(message);
|
||||
expect((await json<WorkspaceOverview>(await page.request.get(`${jobUrl(seeded.job.id)}/workspace`))).applicationAnswerDraft).toBe(seeded.answer); expect(writes).toBe(1);
|
||||
|
||||
Reference in New Issue
Block a user