62 lines
4.3 KiB
JavaScript
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`);
|