Files
Magent/scripts/review_duplicate_accounts_ui.cjs
T
Assclaw 38169b881e
Magent CI/CD / verify (push) Successful in 1m54s
Magent CI/CD / deploy-prod (push) Skipped
Magent CI/CD / deploy-beta (push) Skipped
Support original-language movie requests and fix repair dialog layout
2026-09-11 18:05:18 +12:00

67 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 rows = [36, 1880].map(id => ({ user: { id, username: 'DeaTH_TaXi', role: 'user', auth_provider: 'jellyfin', jellyseerr_user_id: 13 },
jellyfin: { id: 'a'.repeat(32), name: 'DeaTH_TaXi' }, candidate_jellyfin_id: 'a'.repeat(32), seerr: [{ id: 13, name: 'DeaTH_TaXi' }],
jellystat: { state: 'matched', id: 'a'.repeat(32) }, issues: ['Multiple Magent rows share this username after case and whitespace normalization.'], state: 'conflict' }));
let blocked = false, confirmed = false, checks = 0; 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: { username: 'Admin', role: 'admin' } });
if (path === '/api/admin/identities') { checks++; return route.fulfill({ json: { rows: confirmed ? [] : rows, counts: { magent: 2, conflict: 2 }, services: { jellyfin: 'available', seerr: 'available', jellystat: 'available' }, jellyfin_users: [{ id: 'a'.repeat(32), name: 'DeaTH_TaXi' }], upstream: [] } }); }
if (path.endsWith('/duplicates/check')) {
const keep = request.postDataJSON().keep_id || 36;
return route.fulfill({ json: { accounts: rows.map(row => ({ ...row.user, email: 'viewer@example.test', profile_id: null, last_login_at: null })), keep_id: keep, recommended_id: 36, revision: String(keep), can_confirm: !blocked, issues: blocked ? ['Another account owns this identity.'] : [],
proposed: { id: keep, username: 'DeaTH_TaXi', email: 'viewer@example.test', jellyfin_user_id: 'a'.repeat(32), seerr_user_id: 13, features: { stats: true, requests: true, new_requests: true, issues: false, invites: false }, auto_search_enabled: false } } });
}
if (path.endsWith('/duplicates/confirm')) { writes.push(request.postDataJSON()); confirmed = true; return route.fulfill({ json: { consolidated: 1, kept_user_id: 1880 } }); }
return route.fulfill({ json: {} });
});
const page = await context.newPage(), 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?view=identities&user=DeaTH_TaXi');
await page.getByRole('button', { name: 'Check all user IDs', exact: true }).click();
const trigger = page.getByRole('button', { name: 'Repair duplicate accounts', exact: true }).first();
await trigger.click(); const dialog = page.getByRole('dialog');
await dialog.getByLabel('Magent account to keep').waitFor();
assert.equal(await dialog.getByLabel('Magent account to keep').inputValue(), '36');
assert(await dialog.getByRole('button', { name: 'Confirm duplicate repair' }).isDisabled());
assert(await dialog.evaluate(el => el.scrollWidth <= el.clientWidth), 'No horizontal overflow');
const bounds = await dialog.boundingBox();
assert(Math.abs(bounds.x + bounds.width / 2 - width / 2) < 2, 'Dialog centered horizontally');
assert(bounds.y >= 19 && bounds.y + bounds.height <= 981, 'Dialog stays inside viewport');
await dialog.getByRole('checkbox').scrollIntoViewIfNeeded();
await dialog.getByRole('checkbox').check();
assert(await dialog.getByRole('button', { name: 'Confirm duplicate repair' }).isEnabled());
await page.keyboard.press('Escape'); await dialog.waitFor({ state: 'hidden' });
assert(await trigger.evaluate(el => el === document.activeElement));
}
blocked = true;
await page.getByRole('button', { name: 'Repair duplicate accounts', exact: true }).first().click();
let dialog = page.getByRole('dialog');
await dialog.getByText('Another account owns this identity.', { exact: true }).waitFor();
assert(await dialog.getByRole('checkbox').isDisabled());
await dialog.getByRole('button', { name: 'Close', exact: true }).click();
blocked = false;
await page.getByRole('button', { name: 'Repair duplicate accounts', exact: true }).first().click(); dialog = page.getByRole('dialog');
await dialog.getByLabel('Magent account to keep').selectOption('1880');
await dialog.getByText('Magent 1880 · Keep', { exact: true }).waitFor();
await dialog.getByRole('checkbox').check();
const previousChecks = checks;
await dialog.getByRole('button', { name: 'Confirm duplicate repair' }).click();
await dialog.waitFor({ state: 'hidden' });
await page.getByRole('button', { name: 'Run check again', exact: true }).waitFor();
assert.deepEqual(writes, [{ user_id: 36, keep_id: 1880, revision: '1880' }]);
assert(checks > previousChecks, 'Identity report refreshed');
assert.deepEqual(errors, []);
console.log('Passed: desktop/mobile duplicate review, recommended account, changed selection, explicit confirmation, conflict blocking, focus restoration and report refresh. All APIs intercepted.');
} finally { await browser.close(); }
})().catch(error => { console.error(error); process.exitCode = 1; });