- app.css 删除 8 个无引用 legacy 别名,新增 --id-1..5 身份灰阶实色阶 - 画布去紫罗兰二级 palette(tokens.css 删除,改用全站 token) - 画布/镜头台/智能体/omni/视频组件硬编码色全部归位 token - agentPalette 彩色身份色改为显影灰阶 --id 阶;修复 3 处相纸白底白字不可读 - WorkflowLibrary 试运行抽屉焦点还原(异步禁用触发键丢焦)修复 - e2e: fpages/import 色值断言对齐现行 token;新增 hel685 走查脚本 (1440/1024/390 截图 + 控制台错误 + 减动效 + 键盘焦点 + 对比度探针); pagination 空库自举;fpages 增加逐页控制台错误检查 Co-authored-by: multica-agent <github@multica.ai>
97 lines
3.6 KiB
JavaScript
97 lines
3.6 KiB
JavaScript
/* Pagination + perf check (§五): intercept the jobs API and serve 220
|
||
* synthetic takes so the >80 path engages without touching the backend. */
|
||
import { chromium } from 'playwright';
|
||
|
||
let failures = 0;
|
||
const ok = (name, cond, extra = '') => {
|
||
console.log(`${cond ? 'PASS' : 'FAIL'} ${name}${extra ? ' — ' + extra : ''}`);
|
||
if (!cond) failures++;
|
||
};
|
||
|
||
const run = async () => {
|
||
const browser = await chromium.launch();
|
||
const page = await (
|
||
await browser.newContext({ viewport: { width: 1440, height: 900 } })
|
||
).newPage();
|
||
|
||
const base = 'http://127.0.0.1:5173';
|
||
let realJobs = [];
|
||
// HEL-685 harness fix: fan-out needs ≥1 real take to clone; on a fresh DB
|
||
// the list is empty — kick one quick fake-ComfyUI image job, wait for it,
|
||
// and only then start intercepting.
|
||
{
|
||
const probe = await fetch('http://127.0.0.1:8247/api/playground/jobs').then((r) => r.json());
|
||
if (!Array.isArray(probe) || probe.length === 0) {
|
||
await fetch('http://127.0.0.1:8247/api/playground/generate', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
workflow_id: 1,
|
||
input_values: { 1: { text: 'pagination 基准' }, 2: 42 },
|
||
source: 'studio-image',
|
||
}),
|
||
});
|
||
for (let i = 0; i < 60; i++) {
|
||
await page.waitForTimeout(500);
|
||
const jobs = await fetch('http://127.0.0.1:8247/api/playground/jobs').then((r) => r.json());
|
||
if (Array.isArray(jobs) && jobs.some((j) => j.status === 'done')) break;
|
||
}
|
||
}
|
||
}
|
||
await page.route('**/api/playground/jobs**', async (route) => {
|
||
const r = await route.fetch();
|
||
realJobs = await r.json();
|
||
// Fan the real list out to 220 takes with distinct ids/timestamps.
|
||
const fan = [];
|
||
for (let i = 0; i < 220; i++) {
|
||
const src = realJobs[i % realJobs.length] ?? realJobs[0];
|
||
fan.push({
|
||
...src,
|
||
id: 9000 + i,
|
||
status: 'done',
|
||
output_paths: src.output_paths,
|
||
created_at: new Date(Date.now() - i * 47 * 60 * 1000).toISOString(),
|
||
});
|
||
}
|
||
await route.fulfill({ json: fan });
|
||
});
|
||
|
||
const t0 = Date.now();
|
||
await page.goto(`${base}/image`);
|
||
await page.waitForSelector('#desk-prompt', { timeout: 15000 });
|
||
await page.waitForSelector('.take');
|
||
await page.waitForTimeout(800);
|
||
const rendered = await page.locator('.take').count();
|
||
ok('220 条记录时首屏只渲染最近 80 条', rendered === 80, `rendered ${rendered}`);
|
||
const btn = page.locator('.earlier');
|
||
const label = await btn.textContent();
|
||
ok('出现「显示更早」按钮并带余量', /140/.test(label || ''), (label || '').trim());
|
||
await btn.click();
|
||
await page.waitForTimeout(600);
|
||
ok('点击后追加 80 条(共 160)', (await page.locator('.take').count()) === 160);
|
||
await page.locator('.earlier').click();
|
||
await page.waitForTimeout(600);
|
||
ok('再点展开全部 220 条', (await page.locator('.take').count()) === 220);
|
||
const loadMs = Date.now() - t0;
|
||
ok('整段交互在 3 秒内完成', loadMs < 3000, `${loadMs}ms`);
|
||
|
||
// scripted-painting budget while 220 cards live (SSE 只更新相关行:
|
||
// invalidate jobs → 220 卡重排仍是 keyed 更新)
|
||
const metrics = await page.evaluate(async () => {
|
||
const t = performance.now();
|
||
for (let i = 0; i < 50; i++) await fetch('/api/playground/jobs');
|
||
return { poll50: Math.round(performance.now() - t) };
|
||
});
|
||
ok('50 次 jobs 轮询(220 卡在屏)总耗时 < 8 秒', metrics.poll50 < 8000, `${metrics.poll50}ms`);
|
||
|
||
await page.screenshot({ path: 'shots/13-pagination-220.png' });
|
||
await browser.close();
|
||
console.log(failures === 0 ? '\nPAGINATION CHECKS PASSED' : `\n${failures} FAILED`);
|
||
process.exit(failures ? 1 : 0);
|
||
};
|
||
|
||
run().catch((e) => {
|
||
console.error('SCRIPT ERROR:', e);
|
||
process.exit(2);
|
||
});
|