test(e2e): isolate administrator roles and locale between journeys
This commit is contained in:
@@ -61,6 +61,8 @@ for (const [language, mode] of [['en', 'light'], ['nb', 'dark']] as const) {
|
||||
args: ['--window-size=1280,900', `--disable-extensions-except=${extension}`, `--load-extension=${extension}`],
|
||||
});
|
||||
const admin = await playwright.request.newContext();
|
||||
let adminHeaders: Record<string, string> | undefined;
|
||||
let createdAdminId: string | undefined;
|
||||
const records: unknown[] = [];
|
||||
try {
|
||||
await context.route('**/*', route => {
|
||||
@@ -98,9 +100,12 @@ for (const [language, mode] of [['en', 'light'], ['nb', 'dark']] as const) {
|
||||
await zoom(factor);
|
||||
records.push({ area: 'Authentication', route: '/login', language, mode, zoom: factor, geometry: await geometry(page) });
|
||||
}
|
||||
const adminHeaders = await login(admin, 'e2e@example.test');
|
||||
adminHeaders = await login(admin, 'e2e@example.test');
|
||||
const email = `zoom-${language}-${Date.now()}@example.test`;
|
||||
expect((await admin.post(`${apiUrl}/users`, { headers: adminHeaders, data: { email, password, roles: ['Admin'] } })).status()).toBe(200);
|
||||
const created = await admin.post(`${apiUrl}/users`, { headers: adminHeaders, data: { email, password, roles: ['Admin'] } });
|
||||
expect(created.status()).toBe(200);
|
||||
createdAdminId = (await created.json()).id;
|
||||
expect(createdAdminId).toEqual(expect.any(String));
|
||||
const headers = await login(page.request, email);
|
||||
expect((await page.request.put(`${apiUrl}/auth/preferences/language`, { headers, data: { language: language === 'nb' ? 'nb-NO' : 'en' } })).status()).toBe(204);
|
||||
const profile = { version: '1', contact: { fullName: 'Åse Zoom Fixture', headline: 'Documented application workflows', location: 'Oslo' }, summary: ['Supported source summary.'], skills: ['C#', 'React'], jobs: [{ id: 'zoom-role', title: 'Engineer', company: 'Synthetic company', bullets: ['Built and maintained internal web applications.'] }] };
|
||||
@@ -153,9 +158,13 @@ for (const [language, mode] of [['en', 'light'], ['nb', 'dark']] as const) {
|
||||
expect(await (await page.request.get(`${apiUrl}/career/profile`)).json()).toEqual(source);
|
||||
expect(await (await page.request.get(`${apiUrl}/cv/variants/${cv.id}`)).json()).toEqual(cv);
|
||||
} finally {
|
||||
await info.attach('actual-browser-zoom-observations', { body: JSON.stringify({ method: 'chrome.tabs.setZoom; viewport:null; dpr and actual zoom asserted; not human acceptance', browser: context.browser()?.version(), records }, null, 2), contentType: 'application/json' });
|
||||
await admin.dispose();
|
||||
await context.close();
|
||||
try {
|
||||
if (createdAdminId) expect((await admin.put(`${apiUrl}/users/${createdAdminId}/roles`, { headers: adminHeaders, data: { roles: [] } })).status()).toBe(204);
|
||||
} finally {
|
||||
await info.attach('actual-browser-zoom-observations', { body: JSON.stringify({ method: 'chrome.tabs.setZoom; viewport:null; dpr and actual zoom asserted; not human acceptance', browser: context.browser()?.version(), records }, null, 2), contentType: 'application/json' });
|
||||
await admin.dispose();
|
||||
await context.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,10 +90,18 @@ for (const identity of ['anonymous', 'normal', 'admin'] as const) {
|
||||
test(`[P5-15-01 E02 E07 A01] all 33 routes retain native entry, refresh and ${identity} permissions`, async ({ page, playwright }, info) => {
|
||||
test.setTimeout(300_000);
|
||||
const admin = await playwright.request.newContext();
|
||||
let adminHeaders: Record<string, string> | undefined;
|
||||
let createdAdminId: string | undefined;
|
||||
const evidence: { pattern: string; mode: string; destination: string; status?: number }[] = [];
|
||||
try {
|
||||
const adminHeaders = await login(admin, 'e2e@example.test');
|
||||
const email = await createAccount(admin, adminHeaders, identity === 'admin' ? ['Admin'] : []);
|
||||
adminHeaders = await login(admin, 'e2e@example.test');
|
||||
const email = `acceptance-${Date.now()}-${Math.random().toString(36).slice(2)}@example.test`;
|
||||
const created = await admin.post(`${apiUrl}/users`, { headers: adminHeaders, data: { email, password, roles: identity === 'admin' ? ['Admin'] : [] } });
|
||||
expect(created.status()).toBe(200);
|
||||
if (identity === 'admin') {
|
||||
createdAdminId = (await created.json()).id;
|
||||
expect(createdAdminId).toEqual(expect.any(String));
|
||||
}
|
||||
let jobId = 2147483647;
|
||||
let cvId = 2147483647;
|
||||
if (identity !== 'anonymous') {
|
||||
@@ -163,8 +171,12 @@ for (const identity of ['anonymous', 'normal', 'admin'] as const) {
|
||||
await expect(page.getByTestId('admin-version-badge')).toHaveCount(identity === 'admin' ? 1 : 0);
|
||||
}
|
||||
} finally {
|
||||
await info.attach(`route-census-${identity}`, { body: JSON.stringify(evidence, null, 2), contentType: 'application/json' });
|
||||
await admin.dispose();
|
||||
try {
|
||||
if (createdAdminId) expect((await admin.put(`${apiUrl}/users/${createdAdminId}/roles`, { headers: adminHeaders, data: { roles: [] } })).status()).toBe(204);
|
||||
} finally {
|
||||
await info.attach(`route-census-${identity}`, { body: JSON.stringify(evidence, null, 2), contentType: 'application/json' });
|
||||
await admin.dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ async function login(records: RequestRecord[], api: APIRequestContext, email: st
|
||||
expect((await call(records, api, 'POST', '/auth/login', undefined, { email, password })).status()).toBe(200);
|
||||
const me = await json<{ id: string; sessionContext: string }>(await call(records, api, 'GET', '/auth/me'));
|
||||
const token = (await api.storageState()).cookies.find(value => value.name === 'XSRF-TOKEN'); expect(token).toBeDefined();
|
||||
return { id: me.id, email, headers: { 'X-CSRF-TOKEN': token!.value, 'X-Session-Context': me.sessionContext } };
|
||||
const headers = { 'X-CSRF-TOKEN': token!.value, 'X-Session-Context': me.sessionContext };
|
||||
if (email === 'e2e@example.test') expect((await call(records, api, 'PUT', '/auth/preferences/language', headers, { language: 'en' })).status()).toBe(204);
|
||||
return { id: me.id, email, headers };
|
||||
}
|
||||
async function createOwner(records: RequestRecord[], admin: APIRequestContext, headers: Headers) {
|
||||
const email = `p710-audit-${Date.now()}-${Math.random().toString(36).slice(2)}@example.test`;
|
||||
|
||||
@@ -21,7 +21,9 @@ async function login(records: RequestRecord[], api: APIRequestContext, email: st
|
||||
expect((await call(records, api, 'POST', '/auth/login', undefined, { email, password })).status()).toBe(200);
|
||||
const me = await json<{ id: string; sessionContext: string }>(await call(records, api, 'GET', '/auth/me'));
|
||||
const token = (await api.storageState()).cookies.find(value => value.name === 'XSRF-TOKEN'); expect(token).toBeDefined();
|
||||
return { id: me.id, email, headers: { 'X-CSRF-TOKEN': token!.value, 'X-Session-Context': me.sessionContext } };
|
||||
const headers = { 'X-CSRF-TOKEN': token!.value, 'X-Session-Context': me.sessionContext };
|
||||
if (email === 'e2e@example.test') expect((await call(records, api, 'PUT', '/auth/preferences/language', headers, { language: 'en' })).status()).toBe(204);
|
||||
return { id: me.id, email, headers };
|
||||
}
|
||||
async function createOwner(records: RequestRecord[], admin: APIRequestContext, headers: Headers) {
|
||||
const email = `p710-system-${Date.now()}-${Math.random().toString(36).slice(2)}@example.test`;
|
||||
|
||||
@@ -21,7 +21,9 @@ async function login(records: RequestRecord[], api: APIRequestContext, email: st
|
||||
expect((await call(records, api, 'POST', '/auth/login', undefined, { email, password })).status()).toBe(200);
|
||||
const me = await json<{ id: string; sessionContext: string }>(await call(records, api, 'GET', '/auth/me'));
|
||||
const token = (await api.storageState()).cookies.find(value => value.name === 'XSRF-TOKEN'); expect(token).toBeDefined();
|
||||
return { id: me.id, email, headers: { 'X-CSRF-TOKEN': token!.value, 'X-Session-Context': me.sessionContext } };
|
||||
const headers = { 'X-CSRF-TOKEN': token!.value, 'X-Session-Context': me.sessionContext };
|
||||
if (email === 'e2e@example.test') expect((await call(records, api, 'PUT', '/auth/preferences/language', headers, { language: 'en' })).status()).toBe(204);
|
||||
return { id: me.id, email, headers };
|
||||
}
|
||||
async function createOwner(records: RequestRecord[], admin: APIRequestContext, headers: Headers) {
|
||||
const email = `p710-admin-${Date.now()}-${Math.random().toString(36).slice(2)}@example.test`;
|
||||
@@ -68,6 +70,9 @@ function response(page: Page, method: string, path: string) { return page.waitFo
|
||||
|
||||
test('[P7-10 Users A01 E09] real admin creation/role persistence revoke sessions while final-admin and disabled deletion remain protected', async ({ page, playwright, session }) => {
|
||||
const administrator=await login(session.requests, page.request, 'e2e@example.test');
|
||||
const administrators=(await json<Array<{ id: string; roles: string[] }>>(await call(session.requests, page.request, 'GET', '/users'))).filter(value => value.roles.includes('Admin'));
|
||||
// A contaminated fixture must fail before a successful self-demotion can break later suites.
|
||||
expect(administrators.map(value => value.id)).toEqual([administrator.id]);
|
||||
expect((await call(session.requests, page.request, 'PUT', `/users/${administrator.id}/roles`, administrator.headers, { roles: [] })).status()).toBe(409);
|
||||
await start(page, '/admin/users', 390);
|
||||
const email=`p710-created-${Date.now()}@example.test`;
|
||||
@@ -90,7 +95,11 @@ test('[P7-10 Users A01 E09] real admin creation/role persistence revoke sessions
|
||||
expect((await call(session.requests, other, 'GET', '/auth/me')).status()).toBe(401);
|
||||
expect((await page.request.delete(`${apiUrl}/users/${created.id}`, { headers: { ...administrator.headers, 'X-Confirm-Account-Deletion': email } })).status()).toBe(503);
|
||||
expect((await json<Array<{ id: string }>>(await call(session.requests, page.request, 'GET', '/users'))).some(value => value.id===created.id)).toBe(true);
|
||||
} finally { await other.dispose(); }
|
||||
} finally {
|
||||
try {
|
||||
expect((await call(session.requests, session.admin, 'PUT', `/users/${created.id}/roles`, session.adminHeaders, { roles: [] })).status()).toBe(204);
|
||||
} finally { await other.dispose(); }
|
||||
}
|
||||
});
|
||||
|
||||
test('[P7-10 Users A01 E08] unavailable user list recovers by GET without fabricating empty state', async ({ page, session }, info) => {
|
||||
|
||||
Reference in New Issue
Block a user