Files
workinf_Blender_Wasm/web/tests/e2e/device-loss.spec.ts
2026-08-14 18:08:29 -04:00

38 lines
1.8 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("recovers the main-thread Chromium viewport after a real WebGL context loss", async ({ page }) => {
await page.goto("/");
await page.setInputFiles("[data-testid=blend-file-input]", basicBlend);
await expect(page.getByTestId("scene-stats")).toContainText("Objects 3");
const canvas = page.locator("canvas.viewport-canvas");
await expect(canvas).toHaveAttribute("data-device-status", "ready");
const result = await canvas.evaluate(async (element) => {
const gl = element.getContext("webgl2") ?? element.getContext("webgl");
const extension = gl?.getExtension("WEBGL_lose_context");
if (!gl || !extension) return { supported: false, pixels: 0 };
const waitFor = (status: string): Promise<void> => new Promise((resolve, reject) => {
const started = performance.now();
const poll = (): void => {
if (element.dataset.deviceStatus === status) { resolve(); return; }
if (performance.now() - started > 10_000) { reject(new Error(`Timed out waiting for device status ${status}`)); return; }
requestAnimationFrame(poll);
};
poll();
});
extension.loseContext();
await waitFor("lost");
extension.restoreContext();
await waitFor("ready");
const pixels = new Uint8Array(16 * 16 * 4);
gl.readPixels(0, 0, 16, 16, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
return { supported: true, pixels: pixels.reduce((total, value) => total + (value > 0 ? 1 : 0), 0) };
});
expect(result.supported).toBe(true);
expect(result.pixels).toBeGreaterThan(0);
await page.getByRole("button", { name: "添加立方体" }).click();
await expect(page.getByTestId("engine-status")).toContainText("SceneIR r2 (4 objects)");
});