111 lines
4.6 KiB
TypeScript
111 lines
4.6 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import path from "node:path";
|
|
|
|
const basicBlend = path.resolve(import.meta.dirname, "../../../tests/files/web/basic_scene.blend");
|
|
|
|
test("boots and edits with the single-thread engine without cross-origin isolation", async ({ page }) => {
|
|
const engineAssetUrls: string[] = [];
|
|
page.on("request", (request) => {
|
|
const url = new URL(request.url());
|
|
if (/web_engine|pthread/i.test(url.pathname)) engineAssetUrls.push(url.pathname);
|
|
});
|
|
|
|
const documentResponse = await page.goto("/");
|
|
expect(documentResponse).not.toBeNull();
|
|
const headers = await documentResponse!.allHeaders();
|
|
expect(headers["cross-origin-opener-policy"]).toBeUndefined();
|
|
expect(headers["cross-origin-embedder-policy"]).toBeUndefined();
|
|
expect(headers["cross-origin-resource-policy"]).toBeUndefined();
|
|
|
|
const platform = await page.evaluate(async () => {
|
|
const {
|
|
detectBrowserCapabilities,
|
|
gateWasmThreadingCapability,
|
|
selectWebEngineVariant,
|
|
} = await import("/src/platform/capabilities.ts");
|
|
const capabilities = detectBrowserCapabilities();
|
|
const pthreadGate = gateWasmThreadingCapability(capabilities);
|
|
const manifest = await fetch("/engine-manifest.json", { cache: "no-store" }).then((response) => response.json()) as {
|
|
schemaVersion: number;
|
|
memory?: { shared: boolean };
|
|
variants?: Array<{
|
|
id: "single" | "pthread";
|
|
memory: { shared: boolean };
|
|
resources: { js: { url: string }; wasm: { url: string } };
|
|
}>;
|
|
};
|
|
const singleMemory = manifest.schemaVersion === 2
|
|
? manifest.variants?.find((variant) => variant.id === "single")?.memory
|
|
: manifest.memory;
|
|
const selection = selectWebEngineVariant(
|
|
manifest as Parameters<typeof selectWebEngineVariant>[0],
|
|
"AUTO",
|
|
capabilities,
|
|
);
|
|
if (!selection.selectedVariant) throw new Error("AUTO did not select a single-thread variant");
|
|
const selected = selection.selectedVariant;
|
|
const wasmBinary = await fetch(selected.resources.wasm.url, { cache: "no-store" })
|
|
.then((response) => {
|
|
if (!response.ok) throw new Error(`single WASM request failed: ${response.status}`);
|
|
return response.arrayBuffer();
|
|
});
|
|
const imported = await import(/* @vite-ignore */ selected.resources.js.url) as {
|
|
default: (options: { wasmBinary: ArrayBuffer }) => Promise<{
|
|
HEAPU8: Uint8Array;
|
|
_web_engine_create(): number;
|
|
_web_engine_destroy(handle: number): void;
|
|
_web_engine_get_live_handles(): number;
|
|
}>;
|
|
};
|
|
const module = await imported.default({ wasmBinary });
|
|
const variantHandle = module._web_engine_create();
|
|
const variantSharedMemory = typeof SharedArrayBuffer !== "undefined" &&
|
|
module.HEAPU8.buffer instanceof SharedArrayBuffer;
|
|
module._web_engine_destroy(variantHandle);
|
|
return {
|
|
crossOriginIsolated: capabilities.crossOriginIsolated,
|
|
sharedArrayBuffer: capabilities.sharedArrayBuffer,
|
|
worker: capabilities.worker,
|
|
pthreadGate,
|
|
autoSelectedVariant: selected.id,
|
|
variantHandle,
|
|
variantSharedMemory,
|
|
variantLiveAfterDestroy: module._web_engine_get_live_handles(),
|
|
manifestSchemaVersion: manifest.schemaVersion,
|
|
manifestSharedMemory: singleMemory?.shared,
|
|
};
|
|
});
|
|
|
|
expect(platform).toMatchObject({
|
|
crossOriginIsolated: false,
|
|
sharedArrayBuffer: false,
|
|
worker: true,
|
|
autoSelectedVariant: "single",
|
|
variantSharedMemory: false,
|
|
variantLiveAfterDestroy: 0,
|
|
manifestSchemaVersion: 2,
|
|
manifestSharedMemory: false,
|
|
pthreadGate: {
|
|
taskId: "M6-02",
|
|
capability: "WASM_PTHREAD_ENGINE",
|
|
status: "BLOCKED",
|
|
},
|
|
});
|
|
expect(platform.variantHandle).toBeGreaterThan(0);
|
|
expect(platform.pthreadGate.issues.map((issue) => issue.path)).toEqual([
|
|
"crossOriginIsolated",
|
|
"sharedArrayBuffer",
|
|
]);
|
|
|
|
await expect(page.getByTestId("engine-status")).toContainText("Engine: ready", { timeout: 30_000 });
|
|
await expect(page.locator(".status-bar")).toContainText("WASM ABI: ready");
|
|
expect(engineAssetUrls.some((url) => url.endsWith("/vendor/blender/web_engine.wasm"))).toBe(true);
|
|
expect(engineAssetUrls.some((url) => url.endsWith("/vendor/blender/single/web_engine.wasm"))).toBe(true);
|
|
expect(engineAssetUrls.some((url) => /pthread/i.test(url))).toBe(false);
|
|
|
|
await page.setInputFiles("[data-testid=blend-file-input]", basicBlend);
|
|
await expect(page.getByTestId("scene-stats")).toContainText("Objects 3 · Vertices 8 · Faces 6");
|
|
await page.getByRole("button", { name: "添加立方体" }).click();
|
|
await expect(page.getByTestId("scene-stats")).toContainText("Objects 4 · Vertices 16 · Faces 18");
|
|
});
|