// Real UI traversal with synthetic protocols; no production hosts or email. import assert from 'node:assert/strict'; import fs from 'node:fs'; import { chromium } from 'playwright'; const base = new URL(process.argv[2]); if (base.protocol !== 'http:' || !['localhost', '127.0.0.1'].includes(base.hostname)) { throw new Error('Use-case browser runner requires an isolated loopback test server'); } const scenario = JSON.parse(fs.readFileSync(process.argv[3], 'utf8')); assert.equal(scenario.synthetic, true); const browser = await chromium.launch({headless: true}); try { const context = await browser.newContext(); // Fail closed on unexpected integrations. Only the isolated app can be contacted. await context.route('**/*', route => { if (new URL(route.request().url()).origin === base.origin) return route.continue(); return route.abort(); }); await context.addInitScript(() => { window.clipboardMode = 'rich'; window.clipboardReceipts = []; Object.defineProperty(navigator, 'clipboard', {configurable: true, value: { write: async items => { if (window.clipboardMode !== 'rich') throw new Error('Rich copy blocked'); const item = items[0]; window.clipboardReceipts.push({ html: await (await item.getType('text/html')).text(), text: await (await item.getType('text/plain')).text(), }); }, writeText: async text => { if (window.clipboardMode === 'denied') throw new Error('Copy blocked'); window.clipboardReceipts.push({text}); }, }}); }); const page = await context.newPage(); page.setDefaultTimeout(10000); const jsErrors = []; page.on('pageerror', error => jsErrors.push(error.message)); const detail = `${base.origin}/app/spaces/${scenario.space_slug}/`; const original = `${detail}?page=${scenario.previous_slug}`; async function login(role) { await page.goto(`${base.origin}/auth/dev-login/`); await page.locator('input[name=subject]').fill(scenario[`${role}_subject`]); await page.locator('input[name=tenant]').fill(scenario.tenant); await page.getByRole('button', {name: 'Establish session'}).click(); await page.waitForURL('**/app/'); } await login('writer'); assert.match(await page.locator('main').innerText(), new RegExp(scenario.space_title)); await page.waitForFunction(() => document.querySelector('.space-list .space-cover')?.naturalWidth === 1); await page.locator(`a[href="/app/spaces/${scenario.space_slug}/"]`).click(); await page.getByRole('link', {name: scenario.previous_title, exact: true}).click(); await page.waitForFunction(() => document.querySelector('#page-content img')?.naturalWidth === 1); await page.getByRole('link', {name: 'Duplicate page', exact: true}).click(); assert.equal(await page.getByLabel('New page slug').inputValue(), ''); await page.locator('input[name=title]').fill(scenario.next_title); await page.getByRole('button', {name: 'Create duplicate'}).click(); await page.waitForURL(`**?page=${scenario.generated_slug}`); assert.match(await page.locator('#page-content').innerText(), /Completed point/); await page.waitForFunction(() => document.querySelector('#page-content img')?.naturalWidth === 1); await page.getByRole('link', {name: 'Rename page', exact: true}).click(); assert.equal(await page.getByLabel('Title', {exact: true}).inputValue(), scenario.next_title); assert.equal(await page.getByLabel('File name (slug)').inputValue(), scenario.generated_slug); assert.equal(await page.getByLabel('Body (markdown)').inputValue(), scenario.previous_body); await page.getByLabel('File name (slug)').fill(scenario.next_slug); await page.getByRole('button', {name: 'Save page'}).click(); await page.waitForURL(`**?page=${scenario.next_slug}`); await page.getByRole('link', {name: 'Edit page', exact: true}).click(); assert.equal(await page.getByLabel('Body (markdown)').inputValue(), scenario.previous_body); await page.getByLabel('Body (markdown)').fill(scenario.next_body); await page.getByRole('button', {name: 'Save page'}).click(); await page.waitForURL(`**?page=${scenario.next_slug}`); await page.reload(); assert.match(await page.locator('#page-content').innerText(), /Follow-up point/); assert.doesNotMatch(await page.locator('#page-content').innerText(), /Completed point/); // Execute the actual static script loaded by the real detail page, not a fixture DOM. for (const mode of ['rich', 'plain', 'denied']) { await page.evaluate(mode => { window.clipboardMode = mode; window.clipboardReceipts = []; }, mode); await page.getByRole('button', {name: 'Copy content to clipboard'}).click(); await page.waitForFunction(() => !document.getElementById('copy-page-content').disabled); const result = await page.evaluate(() => ({ receipts: window.clipboardReceipts, status: document.getElementById('copy-content-status').textContent, manual: document.getElementById('copy-content-manual').value, hidden: document.getElementById('copy-content-manual').hidden, selected: document.getElementById('copy-content-manual').selectionEnd, })); const text = mode === 'denied' ? result.manual : result.receipts[0].text; assert.match(text, /Next weekly call/); assert.match(text, /- Follow-up point/); assert.match(text, / - Nested detail/); assert.match(text, /- Another agenda item/); assert.match(text, /New notes with \*\*emphasis\*\*/); assert.equal(text, scenario.next_title + "\n\n*" + scenario.abstractor + "*\n\n" + scenario.next_body.replace(/\n$/, "") + "\n\nxxx"); assert.doesNotMatch(text, /Edit page|Duplicate page|Source:|content-plane|Sign out/); if (mode === 'denied') { assert.equal(result.receipts.length, 0); assert.equal(result.hidden, false); assert.equal(result.selected, text.length); assert.match(result.status, /Ctrl\+C or Cmd\+C/); assert.doesNotMatch(result.status, /Content copied/); } else { assert.match(result.status, /Content copied/); if (mode === 'rich') { const html = result.receipts[0].html; assert.match(html, /