74 lines
4.0 KiB
TypeScript
74 lines
4.0 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 the offline engine, renders SceneIR and performs a Main edit", async ({ page, browserName }) => {
|
|
const externalRequests: string[] = [];
|
|
let origin = "";
|
|
page.on("request", (request) => {
|
|
if (origin && new URL(request.url()).origin !== origin) externalRequests.push(request.url());
|
|
});
|
|
await page.setViewportSize({ width: 1280, height: 800 });
|
|
await page.goto("/");
|
|
origin = new URL(page.url()).origin;
|
|
await expect(page.locator("[data-testid=engine-status]")).toContainText("Engine: ready", { timeout: 30_000 });
|
|
await expect(page.locator(".status-bar")).toContainText(/Storage: (IndexedDB \+ OPFS|IndexedDB|unavailable)/, { timeout: 20_000 });
|
|
await page.setInputFiles("[data-testid=blend-file-input]", basicBlend);
|
|
await expect(page.locator("[data-testid=scene-stats]")).toContainText("Objects 3 · Vertices 8 · Faces 6");
|
|
await page.getByRole("button", { name: "添加立方体" }).click();
|
|
await expect(page.locator("[data-testid=scene-stats]")).toContainText("Objects 4 · Vertices 16 · Faces 18");
|
|
const pixels = await page.locator("canvas.viewport-canvas").evaluate((canvas) => {
|
|
const gl = canvas.getContext("webgl2") ?? canvas.getContext("webgl");
|
|
if (!gl) return 0;
|
|
const sample = new Uint8Array(16 * 16 * 4);
|
|
gl.readPixels(0, 0, 16, 16, gl.RGBA, gl.UNSIGNED_BYTE, sample);
|
|
return sample.reduce((sum, value) => sum + (value > 0 ? 1 : 0), 0);
|
|
});
|
|
expect(pixels, `${browserName} returned a blank viewport`).toBeGreaterThan(0);
|
|
expect(externalRequests).toEqual([]);
|
|
});
|
|
|
|
test("keeps content-addressed asset recovery available in Chromium", async ({ page }) => {
|
|
await page.goto("/");
|
|
const result = await page.evaluate(async () => {
|
|
const { StorageClient } = await import("/src/storage/StorageClient.ts");
|
|
const firstClient = new StorageClient();
|
|
await firstClient.ensureProject("chromium-assets");
|
|
const bytes = Uint8Array.from([1, 2, 3, 4]).buffer;
|
|
const first = await firstClient.putAsset("chromium-assets", bytes, "application/octet-stream", "//cache/check.bin");
|
|
firstClient.terminate();
|
|
const secondClient = new StorageClient();
|
|
const restored = await secondClient.readAsset("chromium-assets", first.sha256);
|
|
secondClient.terminate();
|
|
return { sha256: first.sha256, restored: Array.from(new Uint8Array(restored.data)), sourcePath: first.sourcePath };
|
|
});
|
|
expect(result.sha256).toMatch(/^[a-f0-9]{64}$/);
|
|
expect(result.restored).toEqual([1, 2, 3, 4]);
|
|
expect(result.sourcePath).toBe("cache/check.bin");
|
|
});
|
|
|
|
test("keeps the committed project after quota failure and Worker restart in Chromium", async ({ page, browserName }) => {
|
|
await page.goto("/");
|
|
const result = await page.evaluate(async () => {
|
|
const { StorageClient } = await import("/src/storage/StorageClient.ts");
|
|
const projectId = `chromium-quota-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
const first = new StorageClient();
|
|
const committed = await first.saveProject(projectId, 1, Uint8Array.from([1, 2, 3, 4]).buffer);
|
|
let error = "";
|
|
try { await first.saveProject(projectId, 2, Uint8Array.from([9, 9, 9, 9]).buffer, "quota"); }
|
|
catch (caught) { error = caught instanceof Error ? caught.message : String(caught); }
|
|
const retained = await first.readProject(projectId);
|
|
first.terminate();
|
|
const restarted = new StorageClient();
|
|
const reopened = await restarted.readProject(projectId);
|
|
restarted.terminate();
|
|
return { backend: committed.backend, error, revision: retained.revision, reopenedRevision: reopened.revision, bytes: Array.from(new Uint8Array(reopened.buffer)) };
|
|
});
|
|
expect(result.backend, `${browserName} storage backend`).toMatch(/^(opfs|indexeddb)$/);
|
|
expect(result.error).toContain("QuotaExceededError");
|
|
expect(result.revision).toBe(1);
|
|
expect(result.reopenedRevision).toBe(1);
|
|
expect(result.bytes).toEqual([1, 2, 3, 4]);
|
|
});
|