test: harden champion/manager spec against post-login session timing
All checks were successful
Build and Push Docker Image / build (push) Successful in 23s

ensureAuth() probes an auth-required endpoint after each login() and re-logs-in
if the session hasn't settled (occasionally needed under slowMo after rapid
role swaps). Also observes the HTTP status of every second-pass POST so any
auth bounce is visible. App logic unchanged (verified via the test client).
This commit is contained in:
ismail 2026-06-14 15:37:54 +03:00
parent ef53f69833
commit 17981fdf82

View File

@ -70,6 +70,25 @@ async function postForm(page: import('@playwright/test').Page, url: string, data
});
}
/** POST and observe the HTTP status (used where we need to see a step's outcome). */
async function postObs(page: import('@playwright/test').Page, url: string, data: Record<string, string>, step: string, role?: string) {
const r = await postForm(page, url, data);
const loc = r.headers()['location'] || '';
const loginBounce = loc.includes('/accounts/login');
observe(M, step, r.status() < 400 && !loginBounce ? 'PASS' : 'FAIL',
`HTTP ${r.status()}${loc ? ` -> ${loc.slice(0, 60)}` : ''}${loginBounce ? ' (auth bounce!)' : ''}`, { role, http: r.status() });
return r;
}
/** Ensure the page is actually authenticated as `role` before POSTing; re-login if bounced. */
async function ensureAuth(page: import('@playwright/test').Page, role: RoleName) {
// probe an auth-required page via the APIRequestContext
const probe = await page.context().request.get(`${BASE_URL}/complaints/?__probe=1`, { maxRedirects: 0 });
if (probe.status() === 302 && (probe.headers()['location'] || '').includes('/accounts/login')) {
await login(page, role); // re-establish session
}
}
async function login(page: import('@playwright/test').Page, role: RoleName) {
await page.context().clearCookies();
await loginAndScope(page, role, M);
@ -265,13 +284,13 @@ test.describe('Champion/Manager workflow', () => {
`after reject: response_submitted=${sAfterReject.idept_response_submitted} (want False)`, { role: MGR });
// champion re-responds -> manager approves -> PX accepts -> resolve
await login(page, CHAMP);
await postForm(page, `${BASE_URL}/complaints/departments/${ideptId}/response/`, { response_notes_en: 'C1 revised response' });
await login(page, MGR);
await postForm(page, `${BASE_URL}/organizations/departments/${seed.deptId}/manager-review/${ideptId}/`, { review_action: 'approve' });
await login(page, PXT);
await postForm(page, `${BASE_URL}/complaints/departments/${ideptId}/review-response/`, { acceptance_status: 'acceptable' });
await postForm(page, `${BASE_URL}/complaints/${cid}/change-status/`, { status: 'resolved', resolution: 'C1 resolved' });
await login(page, CHAMP); await ensureAuth(page, CHAMP);
await postObs(page, `${BASE_URL}/complaints/departments/${ideptId}/response/`, { response_notes_en: 'C1 revised response' }, 'C1-re-response', CHAMP);
await login(page, MGR); await ensureAuth(page, MGR);
await postObs(page, `${BASE_URL}/organizations/departments/${seed.deptId}/manager-review/${ideptId}/`, { review_action: 'approve' }, 'C1-re-approve', MGR);
await login(page, PXT); await ensureAuth(page, PXT);
await postObs(page, `${BASE_URL}/complaints/departments/${ideptId}/review-response/`, { acceptance_status: 'acceptable' }, 'C1-accept', PXT);
await postObs(page, `${BASE_URL}/complaints/${cid}/change-status/`, { status: 'resolved', resolution: 'C1 resolved' }, 'C1-resolve', PXT);
assertState(cid, { complaint_status: 'resolved', idept_acceptance_status: 'acceptable' }, 'C1-final-state', PXT);
} catch (e) {
observe(M, 'C1-flow', 'FAIL', `exception: ${(e as Error).message}`, { role: MGR });
@ -308,13 +327,13 @@ test.describe('Champion/Manager workflow', () => {
`after not-acceptable: response_submitted=${sAfterNA.idept_response_submitted} (want False)`, { role: PXT });
// champion re-responds -> manager approves -> PX accepts -> resolve
await login(page, CHAMP);
await postForm(page, `${BASE_URL}/complaints/departments/${ideptId}/response/`, { response_notes_en: 'C2 revised response' });
await login(page, MGR);
await postForm(page, `${BASE_URL}/organizations/departments/${seed.deptId}/manager-review/${ideptId}/`, { review_action: 'approve' });
await login(page, PXT);
await postForm(page, `${BASE_URL}/complaints/departments/${ideptId}/review-response/`, { acceptance_status: 'acceptable' });
await postForm(page, `${BASE_URL}/complaints/${cid}/change-status/`, { status: 'resolved', resolution: 'C2 resolved' });
await login(page, CHAMP); await ensureAuth(page, CHAMP);
await postObs(page, `${BASE_URL}/complaints/departments/${ideptId}/response/`, { response_notes_en: 'C2 revised response' }, 'C2-re-response', CHAMP);
await login(page, MGR); await ensureAuth(page, MGR);
await postObs(page, `${BASE_URL}/organizations/departments/${seed.deptId}/manager-review/${ideptId}/`, { review_action: 'approve' }, 'C2-re-approve', MGR);
await login(page, PXT); await ensureAuth(page, PXT);
await postObs(page, `${BASE_URL}/complaints/departments/${ideptId}/review-response/`, { acceptance_status: 'acceptable' }, 'C2-accept', PXT);
await postObs(page, `${BASE_URL}/complaints/${cid}/change-status/`, { status: 'resolved', resolution: 'C2 resolved' }, 'C2-resolve', PXT);
assertState(cid, { complaint_status: 'resolved', idept_acceptance_status: 'acceptable' }, 'C2-final-state', PXT);
} catch (e) {
observe(M, 'C2-flow', 'FAIL', `exception: ${(e as Error).message}`, { role: PXT });