Files
rhinelab-ui/scripts/check-web-integration.mjs
T

78 lines
5.1 KiB
JavaScript

import { createRequire } from 'node:module';
import { mkdir, writeFile, readFile } from 'node:fs/promises';
import assert from 'node:assert/strict';
const require = createRequire(import.meta.url);
const { chromium } = require(process.env.PLAYWRIGHT_MODULE || 'playwright');
const browser = await chromium.launch({ channel: 'msedge', headless: true });
const context = await browser.newContext({ viewport: { width: 1600, height: 900 } });
const page = await context.newPage(), errors = [], results = {};
page.on('pageerror', error => errors.push(String(error)));
page.on('console', message => { if (message.type() === 'error' && /THREE|shader|WebGL/.test(message.text())) errors.push(message.text()); });
const origin = process.env.REVIEW_URL || 'http://127.0.0.1:5188';
await mkdir('verification/web-integration', { recursive: true });
const stats = () => page.evaluate(() => window.rhine.stats());
const close = async () => { await page.locator('[data-action="close-modal"]').click(); await page.waitForTimeout(350); };
try {
await page.goto(origin);
await page.waitForFunction(() => window.rhine?.stats().ready);
assert.equal((await stats()).startup, 'waiting');
assert.equal(await page.locator('.entry-start').isVisible(), true);
await page.locator('.entry-start').click();
await page.waitForFunction(() => window.rhine.stats().startup === 'started');
await page.evaluate(() => window.rhine.archive());
await page.waitForTimeout(1000);
assert.equal((await stats()).wallpaper, null);
assert.equal(await page.locator('.three-toggle').count(), 0);
assert.equal(await page.evaluate(() => typeof window.wallpaperPropertyListener), 'undefined');
await page.locator('[data-action="settings"]').click();
await page.locator('[data-color-theme="dark"]').click();
await page.locator('[data-pref="superPerformance"]').check();
await page.waitForTimeout(2000);
results.fast = await stats();
assert.equal(results.fast.superPerformance, true);
assert.equal(results.fast.motion.reduced, false);
const savedQuality = await page.evaluate(() => JSON.parse(localStorage.getItem('rhine-settings')).rendering);
await close();
await page.screenshot({ path: 'verification/web-integration/dark-fast.png' });
await page.reload(); await page.waitForFunction(() => window.rhine?.stats().ready);
await page.locator('.entry-start').click(); await page.waitForFunction(() => window.rhine.stats().startup === 'started');
await page.evaluate(() => window.rhine.archive()); await page.waitForTimeout(800);
assert.equal((await stats()).superPerformance, true);
assert.equal(await page.evaluate(() => document.documentElement.dataset.darkSurface), 'true');
await page.locator('[data-action="settings"]').click();
await page.locator('[data-pref="superPerformance"]').uncheck();
await close(); await page.waitForTimeout(1000);
assert.equal((await stats()).superPerformance, false);
assert.deepEqual(await page.evaluate(() => JSON.parse(localStorage.getItem('rhine-settings')).rendering), savedQuality);
const before = (await stats()).selected;
await page.keyboard.press('ArrowRight'); await page.waitForTimeout(700);
assert.notEqual((await stats()).selected, before);
const moving = await page.evaluate(async () => {
for (let i = 0; i < 30; i++) { if (document.querySelector('#clock').getAnimations({ subtree: true }).some(a => a.playState === 'running')) return true; await new Promise(r => setTimeout(r, 60)); } return false;
});
assert.equal(moving, true);
await page.evaluate(() => window.rhine.detail()); await page.waitForTimeout(2800);
assert.equal((await stats()).mode, 'detail');
await page.screenshot({ path: 'verification/web-integration/dark-detail.png' });
await page.locator('[data-action="model-viewer"]').click(); await page.waitForTimeout(1600);
assert.ok(await page.locator('canvas').count() >= 2);
await page.keyboard.press('Escape'); await page.waitForTimeout(400);
results.viewports = [];
for (const [width, height] of [[2560,1080],[390,844],[844,390]]) {
await page.setViewportSize({ width, height }); await page.waitForTimeout(600);
assert.equal((await stats()).ready, true);
const overflow = await page.evaluate(() => document.documentElement.scrollWidth > innerWidth + 1);
assert.equal(overflow, false);
results.viewports.push({ width, height, overflow });
}
await page.screenshot({ path: 'verification/web-integration/mobile-landscape.png' });
const html = await readFile('dist/index.html', 'utf8');
assert.match(html, /rel="manifest"/); assert.doesNotMatch(html, /wallpaperPropertyListener/);
const worker = await readFile('dist/sw.js', 'utf8'); assert.ok(worker.length > 1000);
assert.deepEqual(errors, []);
results.startupGesture = results.persistedPerformance = results.restoredQuality = results.numericMotion = results.viewer = results.pwaBuild = true;
results.errors = errors;
await writeFile('verification/web-integration/results.json', JSON.stringify(results, null, 2));
console.log('Web entry, host isolation, theme, performance persistence/restoration, keyboard, clock animation, detail/viewer, responsive and PWA build passed.');
} finally { await browser.close(); }