You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.8 KiB
92 lines
2.8 KiB
|
5 months ago
|
/**
|
||
|
|
* Probes each demo route with Playwright. Captures console errors and
|
||
|
|
* takes a screenshot. For Dialog/Collapsible/Popover/Toast also clicks
|
||
|
|
* the trigger and captures the open state. Smoke test for the migrated
|
||
|
|
* soma components.
|
||
|
|
*
|
||
|
|
* Usage:
|
||
|
|
* 1. Start the dev server (`npm run dev`).
|
||
|
|
* 2. Adjust `BASE` to the actual port if not 5174.
|
||
|
|
* 3. `npx tsx scripts/demo-probe.ts`.
|
||
|
|
*/
|
||
|
|
import { chromium } from 'playwright';
|
||
|
|
import { mkdir } from 'node:fs/promises';
|
||
|
|
|
||
|
|
const BASE = 'http://localhost:5174';
|
||
|
|
const OUT = 'g:/tmp/demos';
|
||
|
|
|
||
|
|
const routes = [
|
||
|
|
'/',
|
||
|
|
'/toggle',
|
||
|
|
'/switch',
|
||
|
|
'/collapsible',
|
||
|
|
'/avatar',
|
||
|
|
'/dialog',
|
||
|
|
'/drawer',
|
||
|
|
'/popover',
|
||
|
|
'/toast'
|
||
|
|
];
|
||
|
|
|
||
|
|
async function main() {
|
||
|
|
await mkdir(OUT, { recursive: true });
|
||
|
|
const browser = await chromium.launch();
|
||
|
|
const ctx = await browser.newContext({ viewport: { width: 900, height: 1100 } });
|
||
|
|
const page = await ctx.newPage();
|
||
|
|
|
||
|
|
let totalErrors = 0;
|
||
|
|
|
||
|
|
for (const route of routes) {
|
||
|
|
const errors: string[] = [];
|
||
|
|
page.removeAllListeners('console');
|
||
|
|
page.removeAllListeners('pageerror');
|
||
|
|
page.on('console', (msg) => {
|
||
|
|
if (msg.type() === 'error') errors.push(msg.text());
|
||
|
|
});
|
||
|
|
page.on('pageerror', (err) => errors.push(`pageerror: ${err.message}`));
|
||
|
|
|
||
|
|
const url = BASE + route;
|
||
|
|
await page.goto(url, { waitUntil: 'networkidle' });
|
||
|
|
await page.waitForTimeout(300);
|
||
|
|
|
||
|
|
const slug = route === '/' ? 'index' : route.slice(1);
|
||
|
|
await page.screenshot({ path: `${OUT}/${slug}.png` });
|
||
|
|
|
||
|
|
// Interactive checks for components with open/close behavior.
|
||
|
|
if (route === '/dialog') {
|
||
|
|
await page.locator('[data-dialog-trigger]').first().click();
|
||
|
|
await page.waitForTimeout(400);
|
||
|
|
await page.screenshot({ path: `${OUT}/${slug}-open.png` });
|
||
|
|
} else if (route === '/collapsible') {
|
||
|
|
await page.locator('[data-collapsible-trigger]').first().click();
|
||
|
|
await page.waitForTimeout(200);
|
||
|
|
await page.screenshot({ path: `${OUT}/${slug}-open.png` });
|
||
|
|
} else if (route === '/popover') {
|
||
|
|
await page.locator('[data-popover-trigger]').first().click();
|
||
|
|
await page.waitForTimeout(400);
|
||
|
|
await page.screenshot({ path: `${OUT}/${slug}-open.png` });
|
||
|
|
} else if (route === '/toast') {
|
||
|
|
await page.locator('button:has-text("Fulfill")').first().click();
|
||
|
|
await page.waitForTimeout(400);
|
||
|
|
await page.screenshot({ path: `${OUT}/${slug}-open.png` });
|
||
|
|
}
|
||
|
|
|
||
|
|
const status = errors.length === 0 ? '✓' : `✗ ${errors.length} error(s)`;
|
||
|
|
console.log(`${status} ${route}`);
|
||
|
|
if (errors.length > 0) {
|
||
|
|
for (const e of errors) console.log(` ${e.slice(0, 200)}`);
|
||
|
|
// Avatar's network failure is a known sandbox limitation, not a real bug.
|
||
|
|
if (!(route === '/avatar' && errors.every((e) => e.includes('ERR_NAME_NOT_RESOLVED')))) {
|
||
|
|
totalErrors += errors.length;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
await browser.close();
|
||
|
|
process.exit(totalErrors > 0 ? 1 : 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
main().catch((err) => {
|
||
|
|
console.error(err);
|
||
|
|
process.exit(2);
|
||
|
|
});
|