38 lines
1.8 KiB
TypeScript
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)");
|
|
});
|