96 lines
4.7 KiB
TypeScript
96 lines
4.7 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const root = path.resolve(import.meta.dirname, "../../..");
|
|
const identity = JSON.parse(fs.readFileSync(path.join(root, "tests/golden/M12-02B/identity.json"), "utf8"));
|
|
const desktop = JSON.parse(fs.readFileSync(path.join(root, "tests/golden/M12-02H/desktop-report.json"), "utf8"));
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(root, "tests/golden/M12-02H/manifest.json"), "utf8"));
|
|
const preview = fs.readFileSync(path.join(root, "tests/golden/M12-02B/preview.png"));
|
|
|
|
test("M12-02H main-thread and Offscreen preview displays match the Blender RGBA8 metrics", async ({ page }) => {
|
|
await page.goto("/");
|
|
const result = await page.evaluate(async ({ identityValue, bytes, desktopValue, thresholds }) => {
|
|
const { displayAssetPreview } = await import("/src/assets/AssetPreviewDisplay.ts");
|
|
const { compareRenderImages } = await import("/src/three-adapter/render-image-comparison.ts");
|
|
document.body.replaceChildren();
|
|
document.body.style.margin = "0";
|
|
const canvas = document.createElement("canvas");
|
|
canvas.id = "m12-asset-preview";
|
|
canvas.setAttribute("aria-label", "Asset preview");
|
|
canvas.style.width = "128px";
|
|
canvas.style.height = "128px";
|
|
canvas.style.imageRendering = "pixelated";
|
|
document.body.append(canvas);
|
|
const encoded = new Uint8Array(bytes).buffer;
|
|
const main = await displayAssetPreview(canvas, "MAIN_THREAD_CANVAS_2D", identityValue, encoded.slice(0));
|
|
const workerResult = await new Promise<{ receipt: unknown; pixels: Uint8Array }>((resolve, reject) => {
|
|
const worker = new Worker("/src/workers/asset-preview-display-test.worker.ts", { type: "module" });
|
|
worker.onmessage = (event) => {
|
|
worker.terminate();
|
|
event.data.ok ? resolve(event.data) : reject(new Error(event.data.error));
|
|
};
|
|
worker.onerror = (event) => { worker.terminate(); reject(new Error(event.message)); };
|
|
worker.postMessage({ identity: identityValue, bytes: encoded.slice(0) });
|
|
});
|
|
const reference = new Uint8Array(desktopValue.pixelCount * 4);
|
|
for (let offset = 0; offset < reference.byteLength; offset += 4) reference.set(desktopValue.referencePixel, offset);
|
|
const mainMetrics = compareRenderImages(reference, main.pixels, desktopValue.width, desktopValue.height, thresholds);
|
|
const offscreenPixels = new Uint8Array(workerResult.pixels);
|
|
const offscreenMetrics = compareRenderImages(reference, offscreenPixels, desktopValue.width, desktopValue.height, thresholds);
|
|
const wrong = new Uint8Array(main.pixels);
|
|
wrong[0] ^= 0xff;
|
|
const wrongMetrics = compareRenderImages(reference, wrong, desktopValue.width, desktopValue.height, thresholds);
|
|
return {
|
|
main: { receipt: main.receipt, pixels: Array.from(main.pixels) },
|
|
offscreen: { receipt: workerResult.receipt, pixels: Array.from(offscreenPixels) },
|
|
mainMetrics,
|
|
offscreenMetrics,
|
|
wrongMetrics,
|
|
};
|
|
}, { identityValue: identity, bytes: [...preview], desktopValue: desktop, thresholds: manifest.thresholds });
|
|
|
|
const canvas = page.locator("#m12-asset-preview");
|
|
await expect(canvas).toBeVisible();
|
|
await expect(canvas).toHaveAttribute("width", "8");
|
|
await expect(canvas).toHaveAttribute("height", "8");
|
|
await expect(canvas).toHaveAttribute("data-asset-preview-status", "ready");
|
|
await expect(canvas).toHaveAttribute("data-asset-preview-backend", "MAIN_THREAD_CANVAS_2D");
|
|
await expect(canvas).toHaveCSS("width", "128px");
|
|
await expect(canvas).toHaveCSS("height", "128px");
|
|
expect(result.main.receipt).toMatchObject({
|
|
status: "READY",
|
|
backend: "MAIN_THREAD_CANVAS_2D",
|
|
width: 8,
|
|
height: 8,
|
|
pixelByteLength: 256,
|
|
pixelSha256: desktop.rgbaSha256,
|
|
nonTransparentPixels: 64,
|
|
bitmapClosed: true,
|
|
});
|
|
expect(result.offscreen.receipt).toMatchObject({
|
|
status: "READY",
|
|
backend: "OFFSCREEN_CANVAS_2D",
|
|
width: 8,
|
|
height: 8,
|
|
pixelByteLength: 256,
|
|
pixelSha256: desktop.rgbaSha256,
|
|
nonTransparentPixels: 64,
|
|
bitmapClosed: true,
|
|
});
|
|
expect(result.main.pixels).toEqual(result.offscreen.pixels);
|
|
for (const metrics of [result.mainMetrics, result.offscreenMetrics]) {
|
|
expect(metrics.status).toBe("READY");
|
|
expect(metrics.errorCode).toBeNull();
|
|
expect(metrics.meanAbsoluteError).toBe(0);
|
|
expect(metrics.rootMeanSquaredError).toBe(0);
|
|
expect(metrics.p95ChannelError).toBe(0);
|
|
expect(metrics.maxChannelError).toBe(0);
|
|
expect(metrics.badPixelRatio).toBe(0);
|
|
expect(metrics.foregroundIntersectionOverUnion).toBe(1);
|
|
expect(metrics.alphaCoverageDeltaRatio).toBe(0);
|
|
}
|
|
expect(result.wrongMetrics.status).toBe("BLOCKED");
|
|
expect(result.wrongMetrics.errorCode).toBe("RENDER_REFERENCE_MISMATCH");
|
|
});
|