Files
FreeCADWasmDev/web/tools/test-module-preload.mjs
wangdequan 9a7c4f0335 Save FreeCAD Web workspace sources and user validation evidence
IFC native binding remains incomplete; preserve accurate test results.
2026-09-15 22:01:58 +08:00

91 lines
4.2 KiB
JavaScript

import assert from "node:assert/strict";
import fs from "node:fs";
import vm from "node:vm";
import test from "node:test";
import ts from "typescript";
const implementations = {
public: fs.readFileSync(new URL("../public/module-preload.js", import.meta.url), "utf8"),
typescript: ts.transpileModule(fs.readFileSync(new URL("../src/module-preload.ts", import.meta.url), "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 },
}).outputText,
};
async function preload(source, search, manifest, failedUrl) {
const window = { location: { search, href: `http://localhost/${search}` } };
const requests = [];
let active = 0;
let peak = 0;
const fetch = async (url, options) => {
requests.push({ url, cache: options.cache });
if (url === "/manifest.json") return { ok: true, json: async () => manifest };
active += 1;
peak = Math.max(peak, active);
await new Promise((resolve) => setImmediate(resolve));
active -= 1;
return { ok: url !== failedUrl, status: url === failedUrl ? 404 : 200, arrayBuffer: async () => new ArrayBuffer(8) };
};
vm.runInNewContext(source, { window, fetch, URL, URLSearchParams, exports: {} });
const deadline = Date.now() + 2000;
while (window.__freecadModulePreloadState.phase === "loading" && Date.now() < deadline) {
await new Promise((resolve) => setImmediate(resolve));
}
const state = JSON.parse(JSON.stringify(window.__freecadModulePreloadState));
assert.notEqual(state.phase, "loading", "preload did not finish");
return { state, requests, peak };
}
const manifest = { schema: "web-module-manifest/v1", modules: {
Part: { revision: "part-one", workers: {
"part.worker.ts": { wasmUrl: "/Part.wasm", dataUrl: "/Part.data", runtimeUrl: "/Part.js" },
"part-inspect.worker.ts": { wasmUrl: "/Part.wasm", dataUrl: "/Part.data" },
} },
TechDraw: { revision: "techdraw-one", wasmUrl: "/TechDraw.wasm", runtimeUrl: "/TechDraw.js" },
Fem: { revision: "fem-one", wasmUrl: "/Fem.wasm" },
} };
for (const [name, source] of Object.entries(implementations)) {
test(`${name}: unrequested modules stay unloaded; shared artifact URLs are fetched once`, async () => {
const { state, requests, peak } = await preload(source, "?moduleManifest=/manifest.json&preload=Part,Part", manifest);
assert.equal(state.phase, "ready");
assert.equal(state.requestedAssets, 2);
assert.equal(state.loadedAssets, 2);
assert.equal(state.loadedBytes, 16);
assert.deepEqual(requests, [
{ url: "/manifest.json", cache: "no-cache" },
{ url: "http://localhost/Part.wasm", cache: "force-cache" },
{ url: "http://localhost/Part.data", cache: "force-cache" },
]);
assert.equal(peak, 2);
});
test(`${name}: top-level artifact URLs and requested asset kinds are honored`, async () => {
const { state, requests } = await preload(source, "?moduleManifest=/manifest.json&preloadModules=TechDraw&preloadKinds=wasm,runtime", manifest);
assert.equal(state.phase, "ready");
assert.equal(state.loadedAssets, 2);
assert.deepEqual(requests.slice(1).map((row) => row.url), ["http://localhost/TechDraw.wasm", "http://localhost/TechDraw.js"]);
});
test(`${name}: concurrency is bounded and invalid values cannot silently skip downloads`, async () => {
for (const [value, expectedPeak] of [["invalid", 2], ["99", 2], ["1", 1], ["-1", 1]]) {
const { state, peak } = await preload(source, `?moduleManifest=/manifest.json&preload=Part&preloadConcurrency=${value}`, manifest);
assert.equal(state.phase, "ready");
assert.equal(state.loadedAssets, 2);
assert.equal(peak, expectedPeak);
}
});
test(`${name}: missing modules and download failures remain errors`, async () => {
const { state } = await preload(source, "?moduleManifest=/manifest.json&preload=Part,Missing", manifest, "http://localhost/Part.wasm");
assert.equal(state.phase, "error");
assert.equal(state.loadedAssets, 1);
assert.equal(state.failedAssets.length, 2);
});
test(`${name}: no preload selection makes no requests`, async () => {
const { state, requests } = await preload(source, "?moduleManifest=/manifest.json", manifest);
assert.equal(state.phase, "disabled");
assert.deepEqual(requests, []);
});
}