Video: the check compares both renderers at the cut and every exit frame's recordings (R2.3)

This commit is contained in:
ZacharyZhang-NY committed 2026-10-09 08:23:16 -04:00
1 parent 35165139a8
commit 326fe24cba
2 files changed
+47 -13

No files matched your search

+1 -1
View File
@@ -173,7 +173,7 @@ tests/scripts/ooxml.py <用例> <文件> 不经 LibreOffice 读 DOCX、XLSX、P
tests/scripts/webview.sh 真窗口 CEF 页面:输入法组字与提交、键入、焦点、主题变量、缩放、不可离开所在文件夹
cd site && pnpm deploy 官网构建并经 wrangler 发到 Cloudflare Workers(只有静态资源),地址 https://ely-office.zhangyanghaha0407.workers.dev
cd site && pnpm test && pnpm e2e 官网单测(几何、道路连通)与 Playwright 端到端(悬停、聚焦、按压、命中归属)
cd site/video/scenes && npm run verify 发布视频:离场六块屏幕在切场后各播自己的录屏帧(真页面渲染)
cd site/video/scenes && npm run verify 发布视频:群像与离场两个渲染器在切场处屏幕角点一致,离场全程各屏播自己的录屏帧(真页面渲染)
cargo check --workspace
cargo test --workspace
rm -rf target/debug/incremental 每次构建或测试后都删(用户定:增量缓存会占满磁盘)
+46 -12
View File
@@ -1,33 +1,67 @@
// Checks the leaving screens play their recordings at the cut.
// Checks the cut into the exit: same screens, their own recordings.
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { chromium } from "playwright";
import { createServer } from "vite";
import recs from "../montage/recs.json" with { type: "json" };
import { moment } from "./timeline.ts";
import { recording } from "./turn.ts";
const here = dirname(fileURLToPath(import.meta.url));
const server = await createServer({ root: resolve(here, "../.."), configFile: false, logLevel: "error", server: { port: 0 } });
await server.listen();
const base = server.resolvedUrls.local[0];
const browser = await chromium.launch();
try {
/** A film-sized page whose recordings are any one frame. */
async function open(path) {
const page = await browser.newPage({ viewport: { width: 1920, height: 1080 } });
page.on("pageerror", (e) => {
throw e;
});
// Any frame will do; only which frame is asked matters.
await page.route("**/rec/**", (route) => route.fulfill({ path: resolve(here, "../../public/film/poster.jpg") }));
await page.goto(`${server.resolvedUrls.local[0]}video/scenes/index.html`, { waitUntil: "networkidle" });
// The first frame after the montage is the cut.
await page.goto(`${base}${path}`, { waitUntil: "networkidle" });
return page;
}
/** Each drawn recording: its source and three screen corners. */
const drawn = (page) =>
page.$$eval("#world image", (els) =>
els.map((el) => {
const m = el.getScreenCTM();
const at = (x, y) => [m.a * x + m.c * y + m.e, m.b * x + m.d * y + m.f];
return { href: el.getAttribute("href"), corners: [at(0, 0), at(1280, 0), at(0, 720)] };
}),
);
try {
const cut = recs.first + 129;
for (const f of [cut, cut + 1, cut + 2]) {
await page.evaluate((f) => window.ely.render("files", f), f);
const hrefs = await page.$$eval("#world image", (els) => els.map((el) => el.getAttribute("href")));
const want = String(f - recs.first + 1).padStart(5, "0");
if (hrefs.length !== 6 || !hrefs.every((h) => h.endsWith(`/${want}.jpg`)) || new Set(hrefs).size !== 6) {
throw new Error(`frame ${f}: ${hrefs.length} recordings ${JSON.stringify(hrefs)}`);
const montage = await open("video/montage/index.html");
await montage.waitForFunction(() => window.montage);
const { pins } = await montage.evaluate((f) => window.montage.render(f), cut - 1);
const exit = await open("video/scenes/index.html");
// Every exit frame until the last screen has gone.
for (let f = cut; ; f++) {
await exit.evaluate((f) => window.ely.render("files", f), f);
const shown = await drawn(exit);
const want = moment(f / 30).pieces.map(({ box, land }) => recording(box, land, f)).filter(Boolean);
const got = shown.map((s) => s.href);
if (JSON.stringify([...got].sort()) !== JSON.stringify([...want].sort())) {
throw new Error(`frame ${f}: drew ${JSON.stringify(got)}, not ${JSON.stringify(want)}`);
}
if (f === cut) {
if (got.length !== 6) throw new Error(`the cut shows ${got.length} screens`);
// The montage pins top-left, top-right, bottom-right, bottom-left.
for (const { href, corners } of shown) {
const app = recs.apps.find((a) => href.startsWith(`rec/${a.rec}/`)).app;
const pin = pins[app];
const near = [pin[0], pin[1], pin[3]].every((p, i) => Math.hypot(p[0] - corners[i][0], p[1] - corners[i][1]) < 1);
if (!near) throw new Error(`${app} moves at the cut: ${JSON.stringify(pin)} to ${JSON.stringify(corners)}`);
}
}
if (!want.length) break;
}
console.log("verify: six screens play their own frames across the cut");
console.log("verify: screens hold still across the cut and play their own frames");
} finally {
await browser.close();
await server.close();