From 89d4d8345f1ad7afea8c163c02b3cc33d793126a Mon Sep 17 00:00:00 2001 From: Miguel Angel Simon Sierra Date: Sat, 3 Oct 2026 23:57:50 -0700 Subject: [PATCH 1/5] test(studio): the edit bench render serves GSAP from the repo, never the CDN --- .../studio/tests/e2e/edit-accuracy/case.mjs | 2 +- .../studio/tests/e2e/edit-accuracy/render.mjs | 3 ++ .../tests/e2e/edit-accuracy/render.test.mjs | 41 +++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 packages/studio/tests/e2e/edit-accuracy/render.test.mjs diff --git a/packages/studio/tests/e2e/edit-accuracy/case.mjs b/packages/studio/tests/e2e/edit-accuracy/case.mjs index 4aa2c859f11..90d2e3216d2 100644 --- a/packages/studio/tests/e2e/edit-accuracy/case.mjs +++ b/packages/studio/tests/e2e/edit-accuracy/case.mjs @@ -770,7 +770,7 @@ async function nudgeGesture(ctx, pre) { const blockedCdnUrls = new Set(); /** Serves the fixtures' CDN requests from the repo; any other CDN URL is blocked and named once. */ -async function serveFixtureAssetsLocally(page) { +export async function serveFixtureAssetsLocally(page) { const cdp = await page.createCDPSession(); cdp.on("Fetch.requestPaused", ({ requestId, request }) => { const file = localAsset(request.url); diff --git a/packages/studio/tests/e2e/edit-accuracy/render.mjs b/packages/studio/tests/e2e/edit-accuracy/render.mjs index 8d859d5e8ff..1987ea8ca53 100644 --- a/packages/studio/tests/e2e/edit-accuracy/render.mjs +++ b/packages/studio/tests/e2e/edit-accuracy/render.mjs @@ -9,6 +9,7 @@ import { createFileServer, initializeSession, } from "../../../../producer/src/index.js"; +import { serveFixtureAssetsLocally } from "./case.mjs"; import { BACKGROUND, COMPOSITION, PLAYHEAD, TARGET } from "./grid.mjs"; const FPS = { num: 30, den: 1 }; @@ -83,6 +84,8 @@ export async function renderBox(dir, decoder, time = PLAYHEAD) { // A composition with no GSAP never registers a timeline; the default 45 s wait for one changes no pixel. { playerReadyTimeout: 10_000 }, ); + // The producer's own browser would fetch GSAP from the CDN; a stalled fetch renders the 0 s frame. + await serveFixtureAssetsLocally(session.page); await initializeSession(session); const { buffer } = await captureFrameToBuffer(session, 0, time); // Diagnostic only: a DOM rect ignores clip-path, so it cannot score a crop. diff --git a/packages/studio/tests/e2e/edit-accuracy/render.test.mjs b/packages/studio/tests/e2e/edit-accuracy/render.test.mjs new file mode 100644 index 00000000000..041d1720a27 --- /dev/null +++ b/packages/studio/tests/e2e/edit-accuracy/render.test.mjs @@ -0,0 +1,41 @@ +import { mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { createRequire } from "node:module"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { describe, expect, it, vi } from "vitest"; +import { FIXTURE_CDN } from "./grid.mjs"; + +const require = createRequire(import.meta.url); +const gsapUrl = `${FIXTURE_CDN}npm/gsap@${require("gsap/package.json").version}/dist/gsap.min.js`; +const sent = []; +const handlers = {}; +const page = { + createCDPSession: async () => ({ + on: (event, handler) => (handlers[event] = handler), + send: async (method, params) => void sent.push({ method, params }), + }), + evaluate: async () => null, +}; + +vi.mock("../../../../producer/src/index.js", () => ({ + createFileServer: async () => ({ url: "http://127.0.0.1:1", close() {} }), + createCaptureSession: async () => ({ page }), + // Navigation: Chrome pauses the fixture's GSAP request here when it is intercepted. + initializeSession: async () => + handlers["Fetch.requestPaused"]?.({ requestId: "1", request: { url: gsapUrl } }), + captureFrameToBuffer: async () => ({ buffer: Buffer.alloc(0) }), + closeCaptureSession: async () => undefined, +})); + +describe("renderBox", () => { + it("serves the fixture's GSAP from the repo, never the CDN", async () => { + const { renderBox } = await import("./render.mjs"); + const dir = mkdtempSync(join(tmpdir(), "edit-bench-render-")); + const decoder = { evaluate: async () => ({ left: 0, right: 1, top: 0, bottom: 1, area: 1 }) }; + await renderBox(dir, decoder); + rmSync(dir, { recursive: true }); + expect(sent.map((s) => s.method)).toEqual(["Fetch.enable", "Fetch.fulfillRequest"]); + const gsap = readFileSync(require.resolve("gsap/dist/gsap.min.js")).toString("base64"); + expect(sent[1].params.body).toBe(gsap); + }); +}); From d86b2ad1e95ab501fb0022c822dce9257f5adb2a Mon Sep 17 00:00:00 2001 From: Miguel Angel Simon Sierra Date: Sun, 4 Oct 2026 00:33:14 -0700 Subject: [PATCH 2/5] test(studio): the edit bench render opens no second page that fetches GSAP --- packages/studio/tests/e2e/edit-accuracy/render.mjs | 3 ++- packages/studio/tests/e2e/edit-accuracy/render.test.mjs | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/studio/tests/e2e/edit-accuracy/render.mjs b/packages/studio/tests/e2e/edit-accuracy/render.mjs index 1987ea8ca53..1865cf77e10 100644 --- a/packages/studio/tests/e2e/edit-accuracy/render.mjs +++ b/packages/studio/tests/e2e/edit-accuracy/render.mjs @@ -82,7 +82,8 @@ export async function renderBox(dir, decoder, time = PLAYHEAD) { }, null, // A composition with no GSAP never registers a timeline; the default 45 s wait for one changes no pixel. - { playerReadyTimeout: 10_000 }, + // Static-frame dedup opens a second page that would fetch GSAP from the CDN; one frame needs none. + { playerReadyTimeout: 10_000, staticFrameDedup: false }, ); // The producer's own browser would fetch GSAP from the CDN; a stalled fetch renders the 0 s frame. await serveFixtureAssetsLocally(session.page); diff --git a/packages/studio/tests/e2e/edit-accuracy/render.test.mjs b/packages/studio/tests/e2e/edit-accuracy/render.test.mjs index 041d1720a27..fd4088a968f 100644 --- a/packages/studio/tests/e2e/edit-accuracy/render.test.mjs +++ b/packages/studio/tests/e2e/edit-accuracy/render.test.mjs @@ -9,6 +9,7 @@ const require = createRequire(import.meta.url); const gsapUrl = `${FIXTURE_CDN}npm/gsap@${require("gsap/package.json").version}/dist/gsap.min.js`; const sent = []; const handlers = {}; +const sessionArgs = []; const page = { createCDPSession: async () => ({ on: (event, handler) => (handlers[event] = handler), @@ -19,7 +20,7 @@ const page = { vi.mock("../../../../producer/src/index.js", () => ({ createFileServer: async () => ({ url: "http://127.0.0.1:1", close() {} }), - createCaptureSession: async () => ({ page }), + createCaptureSession: async (...args) => (sessionArgs.push(args), { page }), // Navigation: Chrome pauses the fixture's GSAP request here when it is intercepted. initializeSession: async () => handlers["Fetch.requestPaused"]?.({ requestId: "1", request: { url: gsapUrl } }), @@ -28,7 +29,7 @@ vi.mock("../../../../producer/src/index.js", () => ({ })); describe("renderBox", () => { - it("serves the fixture's GSAP from the repo, never the CDN", async () => { + it("serves the fixture's GSAP from the repo and opens no second page that would fetch it", async () => { const { renderBox } = await import("./render.mjs"); const dir = mkdtempSync(join(tmpdir(), "edit-bench-render-")); const decoder = { evaluate: async () => ({ left: 0, right: 1, top: 0, bottom: 1, area: 1 }) }; @@ -37,5 +38,6 @@ describe("renderBox", () => { expect(sent.map((s) => s.method)).toEqual(["Fetch.enable", "Fetch.fulfillRequest"]); const gsap = readFileSync(require.resolve("gsap/dist/gsap.min.js")).toString("base64"); expect(sent[1].params.body).toBe(gsap); + expect(sessionArgs[0][4]).toMatchObject({ staticFrameDedup: false }); }); }); From 6876a8519e4154524924acc201d5be4d03fe5b16 Mon Sep 17 00:00:00 2001 From: Miguel Angel Simon Sierra Date: Sun, 4 Oct 2026 01:37:14 -0700 Subject: [PATCH 3/5] test(studio): the render test checks the CDN pattern matches the fixture's GSAP URL --- packages/studio/tests/e2e/edit-accuracy/render.test.mjs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/studio/tests/e2e/edit-accuracy/render.test.mjs b/packages/studio/tests/e2e/edit-accuracy/render.test.mjs index fd4088a968f..7b0c8a79b08 100644 --- a/packages/studio/tests/e2e/edit-accuracy/render.test.mjs +++ b/packages/studio/tests/e2e/edit-accuracy/render.test.mjs @@ -33,9 +33,14 @@ describe("renderBox", () => { const { renderBox } = await import("./render.mjs"); const dir = mkdtempSync(join(tmpdir(), "edit-bench-render-")); const decoder = { evaluate: async () => ({ left: 0, right: 1, top: 0, bottom: 1, area: 1 }) }; - await renderBox(dir, decoder); - rmSync(dir, { recursive: true }); + try { + await renderBox(dir, decoder); + } finally { + rmSync(dir, { recursive: true }); + } expect(sent.map((s) => s.method)).toEqual(["Fetch.enable", "Fetch.fulfillRequest"]); + const [{ urlPattern }] = sent[0].params.patterns; + expect(gsapUrl.startsWith(urlPattern.replace(/\*$/, ""))).toBe(true); const gsap = readFileSync(require.resolve("gsap/dist/gsap.min.js")).toString("base64"); expect(sent[1].params.body).toBe(gsap); expect(sessionArgs[0][4]).toMatchObject({ staticFrameDedup: false }); From 8081ccf7db58ab44f8aa5adecf26f66f71e0833d Mon Sep 17 00:00:00 2001 From: Miguel Angel Simon Sierra Date: Sun, 4 Oct 2026 01:45:25 -0700 Subject: [PATCH 4/5] test(studio): match the CDN pattern the way Chrome does --- .../studio/tests/e2e/edit-accuracy/render.test.mjs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/studio/tests/e2e/edit-accuracy/render.test.mjs b/packages/studio/tests/e2e/edit-accuracy/render.test.mjs index 7b0c8a79b08..a42854f34a4 100644 --- a/packages/studio/tests/e2e/edit-accuracy/render.test.mjs +++ b/packages/studio/tests/e2e/edit-accuracy/render.test.mjs @@ -7,6 +7,14 @@ import { FIXTURE_CDN } from "./grid.mjs"; const require = createRequire(import.meta.url); const gsapUrl = `${FIXTURE_CDN}npm/gsap@${require("gsap/package.json").version}/dist/gsap.min.js`; +// Chrome's Fetch urlPattern: the whole URL, `*` any run of characters, `?` one character. +const chromeUrlPattern = (pattern) => + new RegExp( + `^${pattern + .replace(/[.+^${}()|[\]\\]/g, "\\$&") + .replace(/\*/g, ".*") + .replace(/\?/g, ".")}$`, + ); const sent = []; const handlers = {}; const sessionArgs = []; @@ -40,7 +48,7 @@ describe("renderBox", () => { } expect(sent.map((s) => s.method)).toEqual(["Fetch.enable", "Fetch.fulfillRequest"]); const [{ urlPattern }] = sent[0].params.patterns; - expect(gsapUrl.startsWith(urlPattern.replace(/\*$/, ""))).toBe(true); + expect(gsapUrl).toMatch(chromeUrlPattern(urlPattern)); const gsap = readFileSync(require.resolve("gsap/dist/gsap.min.js")).toString("base64"); expect(sent[1].params.body).toBe(gsap); expect(sessionArgs[0][4]).toMatchObject({ staticFrameDedup: false }); From cfb1a296f9ef272462fc1fb40fc432540fbbc215 Mon Sep 17 00:00:00 2001 From: Miguel Angel Simon Sierra Date: Sun, 4 Oct 2026 01:53:24 -0700 Subject: [PATCH 5/5] test(studio): the render test checks the whole interception pattern --- packages/studio/tests/e2e/edit-accuracy/render.test.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/studio/tests/e2e/edit-accuracy/render.test.mjs b/packages/studio/tests/e2e/edit-accuracy/render.test.mjs index a42854f34a4..15ac4e4bc60 100644 --- a/packages/studio/tests/e2e/edit-accuracy/render.test.mjs +++ b/packages/studio/tests/e2e/edit-accuracy/render.test.mjs @@ -47,8 +47,9 @@ describe("renderBox", () => { rmSync(dir, { recursive: true }); } expect(sent.map((s) => s.method)).toEqual(["Fetch.enable", "Fetch.fulfillRequest"]); - const [{ urlPattern }] = sent[0].params.patterns; - expect(gsapUrl).toMatch(chromeUrlPattern(urlPattern)); + const { patterns } = sent[0].params; + expect(patterns).toEqual([{ urlPattern: patterns[0].urlPattern }]); + expect(gsapUrl).toMatch(chromeUrlPattern(patterns[0].urlPattern)); const gsap = readFileSync(require.resolve("gsap/dist/gsap.min.js")).toString("base64"); expect(sent[1].params.body).toBe(gsap); expect(sessionArgs[0][4]).toMatchObject({ staticFrameDedup: false });