Files
probably-rendering-one-more…/apps/waterfall-wiki/tests/brand-ui-integration.ts
T
codex-bot 602263084f
creative workspace review checks / verify-deployed-canvas (pull_request) Successful in 55s
creative workspace review checks / verify (pull_request) Successful in 27m17s
feat(home): add illustrated editorial landing sections
2026-11-02 14:56:44 +08:00

76 lines
5.8 KiB
TypeScript

/** CI-only checks against the disposable stack, never against personal documents. */
import assert from 'node:assert/strict';
import { chromium, type Request } from 'playwright-core';
import { visitBrowserDocument } from './brand-navigation.mjs';
export async function verifyBrandUI(base: string) {
for (const prefix of process.env.VERIFY_CANVAS_UI === '1' ? ['', '/studio'] : ['']) {
const icon = await fetch(`${base}${prefix}/favicon.ico`);
assert.equal(icon.status, 200);
const bytes = new Uint8Array(await icon.arrayBuffer());
assert.deepEqual([...bytes.slice(0, 4)], [0, 0, 1, 0]);
assert.equal(bytes[4], 7, 'favicon includes seven resolutions');
for (const file of ['logo-light.svg', 'logo-dark.svg', 'icon-dark.svg']) {
const image = await fetch(`${base}${prefix}/brand/${file}`);
assert.equal(image.status, 200, prefix + '/' + file);
assert.match(await image.text(), /<svg/);
}
}
const browser = await chromium.launch({ executablePath: process.env.CHROMIUM_PATH || '/usr/bin/chromium', headless: true, args: ['--no-sandbox', '--disable-dev-shm-usage'] });
try {
const page = await browser.newPage({ viewport: { width: 1440, height: 960 } });
page.setDefaultTimeout(60000);page.setDefaultNavigationTimeout(60000);
const failures: string[] = [], scripts: {path:string;status?:number;ms:number;error?:string}[] = [];
const scriptStarted = new WeakMap<Request,number>();
page.on('request', request => { if(request.resourceType()==='script') scriptStarted.set(request,Date.now()); });
page.on('response', response => { if(response.request().resourceType()==='script') { scripts.push({path:new URL(response.url()).pathname,status:response.status(),ms:Date.now()-(scriptStarted.get(response.request())??Date.now())}); if(scripts.length>24)scripts.shift(); } });
page.on('pageerror', error => failures.push(error.message));
page.on('requestfailed', request => { failures.push(new URL(request.url()).pathname + ': ' + request.failure()?.errorText); if(request.resourceType()==='script') scripts.push({path:new URL(request.url()).pathname,ms:Date.now()-(scriptStarted.get(request)??Date.now()),error:request.failure()?.errorText}); });
const visit = async (path: string, theme: string) => {
const started = Date.now();
try {
await visitBrowserDocument(page, base + path);
await page.waitForFunction(expected => document.documentElement.dataset.theme === expected, theme);
console.log('Brand UI route ready:', path, theme, Date.now() - started);
} catch (error) {
console.error('Brand UI navigation diagnostics', JSON.stringify({path, url:page.url(), elapsedMs:Date.now()-started, failures:failures.slice(-20), scripts:scripts.slice(-24), controls:await page.locator('[data-theme-ready]').evaluateAll(elements=>elements.map(el=>({ready:el.getAttribute('data-theme-ready'),display:getComputedStyle(el).display}))), body:(await page.locator('body').innerText({timeout:3000}).catch(()=>'unavailable')).slice(0,1200)}));
throw error;
}
};
const background = (selector: string) => page.locator(selector).first().evaluate(el => getComputedStyle(el).backgroundColor);
await visit('/', 'home-light');
assert.equal(await background('body'), 'rgb(255, 246, 239)');
assert.ok((await page.title()).includes('啡跃'));
assert.ok((await page.locator('link[rel="icon"]').all()).length >= 2);
assert.equal(await page.locator('.endoleap-mark-light').first().isVisible(), true);
await page.getByRole('button', { name: '切换明暗主题', exact: true }).first().click();
await page.waitForFunction(() => document.documentElement.dataset.theme === 'home-dark');
assert.equal(await background('body'), 'rgb(28, 24, 22)');
assert.equal(await page.locator('.endoleap-mark-dark').first().isVisible(), true);
await visit('/account', 'home-dark');
if (process.env.VERIFY_CANVAS_UI === '1') {
await visit('/graphic', 'canvas-dark');
assert.equal(await background('body'), 'rgb(20, 20, 20)');
assert.equal(await page.locator('[class*="boardWrap"] > div').first().evaluate(el => getComputedStyle(el).backgroundColor), 'rgb(255, 255, 255)', 'artwork stays white in dark chrome');
await page.getByRole('button', { name: '切换明暗主题', exact: true }).first().click();
await page.waitForFunction(() => document.documentElement.dataset.theme === 'canvas-light');
await visit('/infinite_canvas', 'canvas-light');
assert.equal(await background('[class*="viewport"]'), 'rgb(250, 250, 250)');
} else {
await page.getByRole('button', { name: '切换明暗主题', exact: true }).first().click();
}
await visit('/', 'home-light');
await page.setViewportSize({ width: 390, height: 844 });
assert.equal(await page.locator('.endoleap-mark-light').first().isVisible(), true);
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1), 'mobile home has no horizontal overflow');
for (const width of [390, 320]) {
await page.setViewportSize({ width, height: 844 });
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1), 'Editorial home fits narrow screens');
const entry = await page.getByRole('navigation', {name: '主导航'}).getByRole('link', {name: /进入工作台/}).boundingBox();
assert.ok(entry && entry.x >= 0 && entry.x + entry.width <= width, 'Workspace entry is visible, not clipped');
assert.equal(await page.getByRole('link', {name: /去知识空间逛逛/}).getAttribute('href'), '/documents');
assert.equal(await page.getByRole('link', {name: '开始创作', exact: true}).getAttribute('href'), '/account?next=/workspace');
}
console.log('Endoleap logos, both favicon paths, persisted home/canvas themes and artwork color isolation passed.');
} finally { await browser.close(); }
}