// Fixture-only action feedback and accessible dialog checks; no live API writes. const assert = require('node:assert/strict') const { chromium } = require(process.env.REVIEW_PLAYWRIGHT || 'playwright') const base = process.env.REVIEW_BASE || 'http://127.0.0.1:3101' ;(async () => { const browser = await chromium.launch({ headless: true }) try { const context = await browser.newContext() await context.addCookies([{ name: 'magent_logged_in', value: '1', url: base }]) let downloading = true, finished = false const events = [ { id: '1', service: 'Magent', state: 'complete', message: 'Your action has been received.' }, { id: '2', service: 'Radarr', state: 'active', message: 'Checking whether the replacement has been downloaded…' }, ] let releaseAction await context.route('**/api/**', async (route) => { const path = new URL(route.request().url()).pathname const reply = (json) => route.fulfill({ json }) if (path === '/api/auth/me') return reply({ username: 'Member', role: 'user' }) if (path.endsWith('/snapshot')) return reply({ request_id: '12', title: 'Activity review', request_type: 'movie', state: 'DOWNLOADING', timeline: [], actions: [], presentation: { status: { label: 'Download in progress', meaning: 'Your movie is downloading.' }, download: { visible: downloading, summary: 'Downloading (1 active).' }, nextStep: { title: 'Let the download finish', description: 'No action needed.', actionIds: [] }, pipeline: [], } }) if (path.endsWith('/actions/recheck')) { await new Promise((resolve) => { releaseAction = resolve }); return reply({ message: 'Request checked.' }) } if (path.includes('/operations/')) return reply({ id: 'fixture', label: 'Recheck request status', status: finished ? 'complete' : 'running', events: finished ? [...events, { id: '3', service: 'Magent', state: 'complete', message: 'This check has finished. Your movie is still downloading.' }] : events }) if (path.includes('/events/stream')) return route.fulfill({ contentType: 'text/event-stream', body: ': fixture\n\n' }) return reply({ navigation: { showRequests: true }, services: [] }) }) const page = await context.newPage() const errors = [] page.on('pageerror', (error) => errors.push(error.message)) for (const width of [1440, 710, 390]) { await page.setViewportSize({ width, height: 960 }) for (downloading of [true, false]) { finished = false await page.goto(base + '/requests/12') await page.getByRole('button', { name: 'Recheck request', exact: true }).click({ timeout: 5000 }).catch(async (error) => { console.error(errors, (await page.locator('body').innerText()).slice(0, 1600)); throw error }) const card = page.locator('.latest-activity') await card.locator('.latest-activity-message').filter({ hasText: events[1].message }).waitFor() assert.equal(await card.getByText(events[0].message, { exact: true }).isVisible(), false) if (width === 1440 && downloading) { const activityBox = await card.boundingBox() const downloadBox = await page.locator('.request-overview-block').filter({ hasText: 'Current download state' }).boundingBox() assert.ok(activityBox.x > downloadBox.x && Math.abs(activityBox.y - downloadBox.y) < 2, 'Activity must use the spare right-hand quadrant') } const before = await page.locator('.request-next-step').boundingBox() await card.getByRole('button').click() const dialog = page.getByRole('dialog', { name: 'Recheck request status' }) await dialog.waitFor() await dialog.getByText(events[0].message, { exact: true }).waitFor() assert.equal(await page.evaluate(() => document.body.style.overflow), 'hidden') const after = await page.locator('.request-next-step').boundingBox() assert.equal(before.y, after.y, 'Opening the dialog must not expand the page') await page.keyboard.press('Escape') await dialog.waitFor({ state: 'hidden' }) assert.equal(await card.getByRole('button').evaluate((el) => el === document.activeElement), true) finished = true; releaseAction() await card.getByText('Finished', { exact: true }).waitFor() await card.getByRole('button').click() await dialog.getByText('This check has finished. Your movie is still downloading.', { exact: true }).waitFor() if (process.env.REVIEW_DIR) await page.screenshot({ path: `${process.env.REVIEW_DIR}/activity-${width}-${downloading}.png` }) await dialog.getByRole('button', { name: 'Dismiss activity' }).click() await card.waitFor({ state: 'hidden' }) assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth), false) assert.notEqual(await page.evaluate(() => document.body.style.overflow), 'hidden') } } assert.deepEqual(errors, []) console.log('PASS: right-hand activity card, latest event only, live updates, modal history, Escape/focus return, dismissal, desktop/tablet/mobile; all API calls mocked.') } finally { await browser.close() } })().catch((error) => { console.error(error); process.exitCode = 1 })