waybetter-for-x/apps/desktop/scripts/area-plugins-shots.mjs
2026-10-01 06:01:13 +07:00

49 lines
2.9 KiB
JavaScript

// Screenshots of an area plugin's in-page side: the built X runtime (src-tauri/x-runtime.js) in a
// static x.com fixture, with the given flags on, optionally after running one palette command (an
// area's settings dialog). Run `node scripts/build-inject.mjs` first. Not a live X test.
//
// node scripts/area-plugins-shots.mjs <outDir> 'name|path|flags|command|lang'...
// node scripts/area-plugins-shots.mjs ../../verification/area-plugins/phase1 \
// 'navigation-settings|/home|navigation.focusMode,navigation.keyboardPlus|bt-navigation-plus.plugin.js:settings'
//
// `flags` are turned on over the defaults (comma separated); `command` is `<area owner>:<id>`.
// Console errors and "[wayBetter for X] … failed" lines are printed and make the script exit 1.
import { readFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { join } from 'node:path';
import { chromium } from 'playwright';
import { fixtureHtml } from './theme-matrix/fixtures.mjs';
const root = fileURLToPath(new URL('../', import.meta.url));
const runtime = await readFile(join(root, 'src-tauri/x-runtime.js'), 'utf8');
const [, , out, ...shots] = process.argv;
if (!out || !shots.length) { console.error("usage: node scripts/area-plugins-shots.mjs <outDir> 'name|path|flags|command'..."); process.exit(1); }
const cellOf = path => (path.startsWith('/notifications') ? 'notifications' : /^\/(i\/chat|messages)/.test(path) ? 'chat' : path === '/home' ? 'home' : 'profile');
const browser = await chromium.launch();
let failed = 0;
for (const spec of shots) {
const [name, path = '/home', flags = '', command = ''] = spec.split('|');
const page = await browser.newPage({ viewport: { width: 1280, height: 860 }, deviceScaleFactor: 2, colorScheme: 'dark' });
const errors = [];
page.on('pageerror', error => errors.push(error.message));
page.on('console', message => { if (message.type() === 'error') errors.push(message.text()); });
await page.route('https://x.com/**', route => route.fulfill({ contentType: 'text/html', body: fixtureHtml(cellOf(path), 'dark') }));
await page.addInitScript(runtime);
await page.goto(`https://x.com${path}`);
await page.evaluate(list => {
window.BetterTwttr.features.apply(Object.fromEntries(list.map(flag => [flag, true])));
}, flags.split(',').filter(Boolean));
await page.waitForTimeout(400);
if (command) {
const ran = await page.evaluate(id => window.BetterTwttr.api.commands.run(id), command);
if (!ran) errors.push(`no command ${command} (registered: ${await page.evaluate(() => window.BetterTwttr.api.commands.list().map(item => item.id).join(', '))})`);
await page.waitForTimeout(500);
}
await page.screenshot({ path: `${out}/${name}.png` });
console.log(name, errors.length ? `ERRORS: ${errors.join(' | ')}` : 'ok');
failed += errors.length ? 1 : 0;
await page.close();
}
await browser.close();
process.exit(failed ? 1 : 0);