penpot/frontend/playwright/ui/pages/WasmWorkspacePage.js
Alejandro Alonso 88f2366c6f
🎉 Enable render switch and wasm info by default and simplify feature helpers to use pre-computed features set (#9942)
The setup-wasm-features function is the single source of truth for
    resolving the renderer choice (URL param > profile preference > team
    flags), storing the result in state[:features]. Several helpers were
    re-deriving the same priority chain independently, duplicating logic:

    - wasm-enabled?, wasm-url-override, wasm-url-override-ref
    - enabled-by-flags?, enabled-without-migration?

    This change removes all duplicated helpers and simplifies the
    remaining functions to rely exclusively on the pre-computed
    :features set:

    - active-feature? — now just checks (contains? (:features state)
      feature) without special-casing render-wasm/v1
    - use-feature — uses the reactive features-ref for all features
    - initialize/recompute-features effects — use the local features
      binding directly

    Since :features is rebuilt by setup-wasm-features on every
    initialization and recompute, this preserves correctness while
    eliminating ~50 lines of duplicated code.
2026-06-01 12:52:34 +02:00

113 lines
3.0 KiB
JavaScript

import { expect } from "@playwright/test";
import { WorkspacePage } from "./WorkspacePage";
export const WASM_PROFILE = "logged-in-user/get-profile-wasm-renderer.json";
export const WASM_FLAGS = [
"enable-feature-render-wasm",
"enable-render-wasm-dpr",
"enable-feature-text-editor-v2",
// Default flags enable render-wasm-info; keep screenshots stable in e2e.
"disable-render-wasm-info",
];
export class WasmWorkspacePage extends WorkspacePage {
static async init(page) {
await super.init(page);
await WasmWorkspacePage.mockConfigFlags(page, WASM_FLAGS);
await WasmWorkspacePage.mockRPC(page, "get-profile", WASM_PROFILE);
await page.addInitScript(() => {
document.addEventListener("penpot:wasm:loaded", () => {
window.wasmModuleLoaded = true;
});
document.addEventListener("penpot:wasm:render", () => {
window.wasmRenderCount = (window.wasmRenderCount || 0) + 1;
});
document.addEventListener("penpot:wasm:set-objects", () => {
window.wasmSetObjectsFinished = true;
});
});
}
static async mockConfigFlags(page, flags) {
await super.mockConfigFlags(page, [...WASM_FLAGS, ...flags]);
}
async mockConfigFlags(flags) {
return WasmWorkspacePage.mockConfigFlags(this.page, flags);
}
constructor(page, options) {
super(page, options);
this.canvas = page.getByTestId("canvas-wasm-shapes");
}
async waitForIdle(options) {
return this.page.evaluate(
(options) => new Promise((resolve) => globalThis.requestIdleCallback(resolve, options)),
options
);
}
async waitForFirstRender() {
await this.pageName.waitFor();
await this.canvas.waitFor();
await this.page.waitForFunction(() => {
console.log("RAF:", window.wasmSetObjectsFinished);
return window.wasmSetObjectsFinished;
});
}
async waitForFirstRenderWithoutUI() {
await this.waitForFirstRender();
await this.hideUI();
}
async getRenderCount() {
return this.page.evaluate(() => window.wasmRenderCount || 0);
}
async waitForNextRender(previousCount = null) {
const baseCount =
previousCount === null ? await this.getRenderCount() : previousCount;
await this.page.waitForFunction(
(count) => (window.wasmRenderCount || 0) > count,
baseCount,
);
}
async hideUI() {
await this.page.keyboard.press("\\");
await expect(this.pageName).not.toBeVisible();
}
static async mockGoogleFont(page, fontSlug, assetFilename, options = {}) {
const url = new RegExp(`/internal/gfonts/font/${fontSlug}`);
return await page.route(url, (route) =>
route.fulfill({
status: 200,
path: `playwright/data/${assetFilename}`,
contentType: "application/font-ttf",
...options,
}),
);
}
async mockGoogleFont(fontSlug, assetFilename, options) {
return WasmWorkspacePage.mockGoogleFont(
this.page,
fontSlug,
assetFilename,
options,
);
}
async setupEmptyFile() {
await super.setupEmptyFile();
await this.mockRPC("get-profile", WASM_PROFILE);
}
}