mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-24 04:33:17 +00:00
04d12bc16e
Extract the Windows-independent Docs repair from candidate 136d039de4a1f8f7debfb1f82d4fffd8bf610083. Add trusted scope after sanitization without expanding document-controlled attributes. Preserve table-local scrolling and verify the current eight-header plans table in desktop Chromium and phone WebKit; native Windows work remains separate. Change-source: pulse-maintainer
125 lines
4.6 KiB
JavaScript
125 lines
4.6 KiB
JavaScript
// Production Docs/router/styles and shipped plan Markdown, no backend.
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { chromium, webkit } = require('playwright');
|
|
(async () => {
|
|
const observe = process.argv.includes('observe');
|
|
const root = '/workspace/frontend-modern';
|
|
process.chdir(root);
|
|
const artifacts = path.join(root, 'node_modules', 'docs-header-browser');
|
|
fs.mkdirSync(artifacts, { recursive: true });
|
|
const { createServer } = await import(path.join(root, 'node_modules/vite/dist/node/index.js'));
|
|
const server = await createServer({
|
|
root,
|
|
configFile: path.join(root, 'vite.config.ts'),
|
|
cacheDir: path.join(root, 'node_modules', '.vite-docs-table-headers'),
|
|
server: { host: '127.0.0.1', port: 5243, strictPort: true },
|
|
optimizeDeps: { noDiscovery: true, include: [] },
|
|
});
|
|
let browser;
|
|
const results = [];
|
|
try {
|
|
await server.listen();
|
|
for (const [engine, width, tone] of [
|
|
['chromium', 1280, 'light'],
|
|
['webkit', 390, 'dark'],
|
|
]) {
|
|
browser = await { chromium, webkit }[engine].launch(
|
|
engine === 'chromium'
|
|
? { headless: true, channel: 'chromium', args: ['--no-sandbox'] }
|
|
: { headless: true },
|
|
);
|
|
const page = await browser.newPage({
|
|
viewport: { width, height: 900 },
|
|
...(engine === 'webkit' ? { isMobile: true, hasTouch: true } : {}),
|
|
});
|
|
const errors = [];
|
|
page.on('response', (response) => {
|
|
if (response.status() >= 400)
|
|
console.log('FAILED_RESPONSE', response.status(), response.url());
|
|
});
|
|
page.on('pageerror', (e) => errors.push(e.message));
|
|
page.on('console', (m) => {
|
|
if (m.type() === 'error') {
|
|
console.log('CONSOLE_ERROR', m.text(), m.location());
|
|
errors.push(m.text());
|
|
}
|
|
});
|
|
await page.goto(
|
|
'http://127.0.0.1:5243/browser-tests/docs-fragment-navigation.html?scenario=plans',
|
|
{ waitUntil: 'domcontentloaded', timeout: 60_000 },
|
|
);
|
|
await page.locator('article table').first().waitFor();
|
|
if (tone === 'dark')
|
|
await page.evaluate(() => document.documentElement.classList.add('dark'));
|
|
const table = page.locator('article table').filter({ hasText: 'Relay (legacy)' }).first();
|
|
const th = await table.locator('thead th').allTextContents();
|
|
const headers = await table.getByRole('columnheader').allTextContents();
|
|
const snapshot = await table.ariaSnapshot();
|
|
const scopes = await table
|
|
.locator('thead th')
|
|
.evaluateAll((nodes) => nodes.map((n) => n.getAttribute('scope')));
|
|
const scroll = await table.evaluate((t) => ({
|
|
wrapper: t.parentElement.dataset.docTableScroll !== undefined,
|
|
outer: document.documentElement.scrollWidth,
|
|
viewport: window.innerWidth,
|
|
width: t.parentElement.clientWidth,
|
|
content: t.parentElement.scrollWidth,
|
|
}));
|
|
if (!observe) {
|
|
assert.equal(th.length, 8);
|
|
assert.deepEqual(headers, th);
|
|
assert.deepEqual(scopes, Array(th.length).fill('col'));
|
|
assert.ok(snapshot.includes('columnheader "Relay (legacy)"'));
|
|
assert.ok(scroll.wrapper);
|
|
assert.ok(scroll.outer <= scroll.viewport + 1);
|
|
if (width === 390) {
|
|
assert.ok(scroll.content > scroll.width);
|
|
const moved = await table.evaluate((t) => {
|
|
t.parentElement.scrollLeft = 180;
|
|
return t.parentElement.scrollLeft;
|
|
});
|
|
assert.ok(moved > 0);
|
|
}
|
|
assert.deepEqual(errors, []);
|
|
}
|
|
await table.locator('thead').scrollIntoViewIfNeeded();
|
|
await page.screenshot({ path: path.join(artifacts, `${engine}-headers.png`) });
|
|
await page.screenshot({
|
|
path: path.join(artifacts, `${engine}-${observe ? 'before' : 'after'}.png`),
|
|
fullPage: true,
|
|
});
|
|
results.push({
|
|
engine,
|
|
version: browser.version(),
|
|
width,
|
|
tone,
|
|
th,
|
|
headers,
|
|
scopes,
|
|
scroll,
|
|
snapshot,
|
|
errors,
|
|
});
|
|
await browser.close();
|
|
browser = undefined;
|
|
}
|
|
fs.writeFileSync(
|
|
path.join(artifacts, observe ? 'before.json' : 'after.json'),
|
|
JSON.stringify(
|
|
{ playwright: require('playwright/package.json').version, observe, results },
|
|
null,
|
|
2,
|
|
),
|
|
);
|
|
console.log(JSON.stringify({ result: observe ? 'observed' : 'passed', results, artifacts }));
|
|
} finally {
|
|
if (browser) await browser.close();
|
|
await server.close();
|
|
}
|
|
})().catch((e) => {
|
|
console.error(e);
|
|
process.exitCode = 1;
|
|
});
|