Files
Magent/scripts/review_feature_access_ui.cjs
Assclaw 4f7853b17b
Magent CI/CD / deploy-beta (push) Successful in 50s
Magent CI/CD / verify (push) Successful in 2m4s
Magent CI/CD / deploy-prod (push) Skipped
Align missing-episode searches and permit reviewed profile overrides
2026-09-11 20:26:57 +12:00

77 lines
5.3 KiB
JavaScript

const assert = require('node:assert/strict');
const { chromium } = require(process.env.PLAYWRIGHT_PACKAGE || 'playwright');
const base = process.env.REVIEW_BASE || 'http://localhost:3114';
(async () => {
const browser = await chromium.launch();
try {
const context = await browser.newContext();
await context.addCookies([{ name: 'magent_logged_in', value: '1', url: base }]);
const all = { stats: true, requests: true, new_requests: true, issues: true, invites: true, ignore_profile_limits: false };
const viewer = { id: 2, username: 'Georgia', role: 'user', email: 'georgia@example.test', features: { ...all }, stats: { total: 12, ready: 7, in_progress: 5 } };
const other = { ...viewer, id: 3, username: 'Other viewer', features: { ...all, issues: false } };
let signedIn = { username: 'Admin', role: 'admin', features: all };
const writes = [];
await context.route('**/api/**', async (route) => {
const request = route.request(), path = new URL(request.url()).pathname;
if (path === '/api/auth/me') return route.fulfill({ json: signedIn });
if (request.method() === 'PUT' && path.includes('/features')) {
writes.push({ path, payload: request.postDataJSON() });
Object.assign(viewer.features, request.postDataJSON());
return route.fulfill({ json: { updated: 2, features: viewer.features } });
}
if (path === '/api/admin/users/summary') return route.fulfill({ json: { users: [viewer, other] } });
if (path === '/api/admin/users/id/2' || path === '/api/admin/users/Georgia') return route.fulfill({ json: { user: viewer, stats: viewer.stats } });
if (path === '/api/admin/profiles') return route.fulfill({ json: { profiles: [] } });
return route.fulfill({ json: {} });
});
const page = await context.newPage();
const errors = []; page.on('pageerror', (error) => errors.push(error.message));
for (const width of [1440, 390]) {
await page.setViewportSize({ width, height: 1000 });
await page.goto(`${base}/users/2`);
await page.getByRole('heading', { name: 'Request statistics', exact: true }).waitFor();
assert.equal(await page.getByRole('heading', { name: 'Access controls', exact: true }).count(), 0);
const box = await page.locator('.user-detail-centered').boundingBox();
assert(Math.abs(box.x + box.width / 2 - width / 2) < 4, 'Profile is centred');
await page.getByRole('button', { name: 'Manage this user', exact: true }).click();
const dialog = page.getByRole('dialog');
await dialog.getByRole('checkbox', { name: /My Stats/ }).waitFor();
assert(await dialog.evaluate((element) => element.scrollWidth <= element.clientWidth), `No modal overflow at ${width}`);
assert.equal(await dialog.getByRole('checkbox').count(), 8);
assert(await dialog.getByText('Restrict access or delete accounts', { exact: true }).count());
await dialog.getByRole('checkbox', { name: /^Issues/ }).uncheck();
await dialog.getByRole('button', { name: 'Save feature access', exact: true }).click();
await dialog.getByRole('status').filter({ hasText: 'Feature access saved.' }).waitFor();
assert.deepEqual(writes.at(-1).payload, { issues: false });
await dialog.getByRole('checkbox', { name: /^Ignore profile limits/ }).check();
await dialog.getByRole('button', { name: 'Save feature access', exact: true }).click();
await dialog.getByRole('status').filter({ hasText: 'Feature access saved.' }).waitFor();
assert.deepEqual(writes.at(-1).payload, { ignore_profile_limits: true });
await page.keyboard.press('Escape');
await dialog.waitFor({ state: 'hidden' });
assert(await page.getByRole('button', { name: 'Manage this user', exact: true }).evaluate((element) => element === document.activeElement));
viewer.features.issues = true;
viewer.features.ignore_profile_limits = false;
}
await page.goto(`${base}/users`);
await page.getByRole('button', { name: 'Manage users', exact: true }).click();
const dialog = page.getByRole('dialog');
const issues = dialog.getByRole('checkbox', { name: /^Issues/ });
await issues.waitFor();
assert(await issues.evaluate((element) => element.indeterminate), 'Bulk mixed permissions shown');
await issues.check();
await dialog.getByRole('button', { name: 'Apply changed features to all users', exact: true }).click();
await dialog.getByRole('status').filter({ hasText: 'Feature access saved for 2' }).waitFor();
assert.deepEqual(writes.at(-1), { path: '/api/admin/users/features/bulk', payload: { issues: true } });
signedIn = { username: 'Viewer', role: 'user', features: Object.fromEntries(Object.keys(all).map((key) => [key, false])) };
for (const path of ['/insights', '/', '/new-requests', '/portal/issues', '/profile/invites']) {
await page.goto(base + path);
await page.getByRole('heading', { name: 'Feature unavailable' }).waitFor();
assert.equal(await page.locator('.header-actions a, .workspace-mobile-nav a').count(), 0);
}
assert.deepEqual(errors, []);
console.log('Passed: responsive centred profiles, management overlay, focus restoration, individual and mixed bulk permissions, saved payload scope, and all five denied routes/navigation. API traffic used fixtures only.');
} finally { await browser.close(); }
})().catch((error) => { console.error(error); process.exitCode = 1; });