Files
workinf_Blender_Wasm/tools/web/check-deployed-web-blender.mjs
mes123456 f68c6c9678
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
Add full source parity validation workflow
2026-09-07 16:45:07 +08:00

62 lines
4.3 KiB
JavaScript

import assert from "node:assert/strict";
import crypto from "node:crypto";
import fs from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";
const origin = process.env.WEB_ORIGIN ?? "https://49.232.250.35:58014";
const { chromium } = createRequire(import.meta.url)(path.resolve("web/node_modules/playwright"));
const wasmPath = path.resolve("web/app/public/vendor/blender/web_engine.wasm");
const expectedWasmSha256 = crypto.createHash("sha256").update(fs.readFileSync(wasmPath)).digest("hex");
const requiredIsolation = {
"cross-origin-opener-policy": "same-origin",
"cross-origin-embedder-policy": "require-corp",
"cross-origin-resource-policy": "same-origin",
};
const response = await fetch(`${origin}/`);
assert.equal(response.status, 200);
for (const [name, expected] of Object.entries(requiredIsolation)) assert.equal(response.headers.get(name), expected);
assert.equal(response.headers.get("content-type"), "text/html; charset=utf-8");
assert.match(response.headers.get("content-security-policy") ?? "", /wasm-unsafe-eval/);
const manifestResponse = await fetch(`${origin}/wasm-module-manifest.json`, { cache: "no-store" });
assert.equal(manifestResponse.status, 200);
const moduleManifest = await manifestResponse.json();
const debug = moduleManifest.modules.find((item) => item.id === "debug-incremental");
assert.equal(debug.resources.single.sha256, expectedWasmSha256);
const range = await fetch(`${origin}/vendor/blender/web_engine.wasm`, { headers: { Range: "bytes=0-15" } });
assert.equal(range.status, 206);
assert.equal(range.headers.get("content-type"), "application/wasm");
assert.equal((await range.arrayBuffer()).byteLength, 16);
const full = new Uint8Array(await (await fetch(`${origin}/vendor/blender/web_engine.wasm`, { cache: "no-store" })).arrayBuffer());
assert.equal(crypto.createHash("sha256").update(full).digest("hex"), expectedWasmSha256);
const favicon = await fetch(`${origin}/favicon.svg`);
assert.equal(favicon.status, 200);
assert.equal(favicon.headers.get("content-type"), "image/svg+xml");
const browser = await chromium.launch({ headless: true, executablePath: process.env.CHROME_PATH ?? "/usr/bin/google-chrome-stable" });
const context = await browser.newContext({ viewport: { width: 1440, height: 900 }, ignoreHTTPSErrors: false });
const page = await context.newPage();
const consoleErrors = [];
const requestFailures = [];
const badResponses = [];
page.on("console", (message) => { if (message.type() === "error") consoleErrors.push(message.text()); });
page.on("requestfailed", (request) => requestFailures.push(`${request.url()} ${request.failure()?.errorText ?? "failed"}`));
page.on("response", (item) => { if (item.status() >= 400) badResponses.push(`${item.status()} ${item.url()}`); });
await page.goto(`${origin}/`, { waitUntil: "domcontentloaded", timeout: 60_000 });
await page.waitForFunction(() => document.body.innerText.includes("WASM ABI: ready"), undefined, { timeout: 120_000 });
await page.getByTestId("blend-file-input").setInputFiles(path.resolve("tests/files/web/basic_scene.blend"));
await page.waitForFunction(() => Number(document.body.innerText.match(/Objects (\d+)/)?.[1] ?? 0) > 0, undefined, { timeout: 120_000 });
const beforeObjects = Number(await page.locator("body").evaluate((node) => node.innerText.match(/Objects (\d+)/)?.[1] ?? 0));
await page.getByRole("button", { name: "添加立方体", exact: true }).click();
await page.waitForFunction((before) => Number(document.body.innerText.match(/Objects (\d+)/)?.[1] ?? 0) === before + 1, beforeObjects, { timeout: 60_000 });
const state = await page.evaluate(() => ({ secureContext: window.isSecureContext, crossOriginIsolated: window.crossOriginIsolated, body: document.body.innerText, wasm: performance.getEntriesByType("resource").filter((item) => item.name.includes(".wasm")).map((item) => item.name) }));
assert.equal(state.secureContext, true);
assert.equal(state.crossOriginIsolated, true);
assert.equal(Number(state.body.match(/Objects (\d+)/)?.[1]), beforeObjects + 1);
assert.equal(consoleErrors.length, 0);
assert.equal(requestFailures.length, 0);
assert.equal(badResponses.length, 0);
await context.close();
await browser.close();
process.stdout.write(`deployed-web-blender-ok origin=${origin} wasm=${expectedWasmSha256} range=206 mainMutation=${beforeObjects}->${beforeObjects + 1} chromium=ready\n`);