From 02400a84b9d581fa9a0143c0ea7ab236872a2f60 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Fri, 7 Aug 2026 14:43:59 +0300 Subject: [PATCH] fix(fig): finalize worker cleanup semantics - Retain worker graphs only for lazy first-page imports\n- Make termination idempotent\n- Wait on deterministic population telemetry in E2E coverage --- packages/core/src/kiwi/fig/parse/worker.ts | 9 +++++---- packages/core/src/kiwi/fig/population/client.ts | 3 +++ tests/e2e/pages/fig-population-worker.spec.ts | 15 ++++++++++----- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/core/src/kiwi/fig/parse/worker.ts b/packages/core/src/kiwi/fig/parse/worker.ts index 42dac3324..9826b3018 100644 --- a/packages/core/src/kiwi/fig/parse/worker.ts +++ b/packages/core/src/kiwi/fig/parse/worker.ts @@ -60,10 +60,11 @@ self.onmessage = (event: MessageEvent) => { const { nodeChanges, blobs, images, figKiwiVersion, figSchemaDeflated } = parseFigBuffer( parseRequest.buffer ) - graph = importNodeChanges(nodeChanges, blobs, new Map(images), parseRequest.options) - graph.figKiwiVersion = figKiwiVersion - graph.figSchemaDeflated = figSchemaDeflated - const serialized = serializeSceneGraph(graph) + const parsedGraph = importNodeChanges(nodeChanges, blobs, new Map(images), parseRequest.options) + parsedGraph.figKiwiVersion = figKiwiVersion + parsedGraph.figSchemaDeflated = figSchemaDeflated + graph = parseRequest.options?.populate === 'first-page' ? parsedGraph : undefined + const serialized = serializeSceneGraph(parsedGraph) const transfer = parseRequest.options?.populate === 'first-page' ? [] diff --git a/packages/core/src/kiwi/fig/population/client.ts b/packages/core/src/kiwi/fig/population/client.ts index 302522354..f806502b9 100644 --- a/packages/core/src/kiwi/fig/population/client.ts +++ b/packages/core/src/kiwi/fig/population/client.ts @@ -78,6 +78,7 @@ function createPopulationWorkerClient(graph: SceneGraph, worker: Worker): FigPop >() let revision = 0 let stale = false + let disposed = false let applyingDelta = false const invalidate = () => { if (applyingDelta || stale) return @@ -161,6 +162,8 @@ function createPopulationWorkerClient(graph: SceneGraph, worker: Worker): FigPop }) }, terminate() { + if (disposed) return + disposed = true emitTelemetry({ event: 'terminated' }) fail(false) } diff --git a/tests/e2e/pages/fig-population-worker.spec.ts b/tests/e2e/pages/fig-population-worker.spec.ts index f980bfef4..a585a1005 100644 --- a/tests/e2e/pages/fig-population-worker.spec.ts +++ b/tests/e2e/pages/fig-population-worker.spec.ts @@ -23,15 +23,20 @@ test('populates a real lazy FIG page in the retained parse worker', async () => }) if (!targetPageId) throw new Error('Target page not found') - const loading = editor.page.getByTestId('canvas-loading') - const switchPromise = editor.page.evaluate((pageId) => { + await editor.page.evaluate((pageId) => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') return store.switchPage(pageId) }, targetPageId) - await expect(loading).toBeVisible() - await switchPromise - await expect(loading).not.toBeVisible() + await expect + .poll(() => + editor.page.evaluate(() => + (Reflect.get(window, 'figPopulationWorkerEvents') as Array<{ event: string }>).some( + ({ event }) => event === 'populate' + ) + ) + ) + .toBe(true) const currentPage = await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.()