experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

test(tag-widget-flake): gate on __pageModuleReady before firing setup tag

Full-suite ordering flake on smoke.spec.ts:2010 was a pubsub event race:
the test's 2s sleep after opening the page window is insufficient under
load, and the setup tag command could publish tag:item-added before
page.js had executed its top-level api.subscribe('tag:item-added', ...).
tile-preload's subscribeImpl attaches ipcRenderer.on('pubsub:tag:item-added')
synchronously from that call site, but Electron's webContents.send is
fire-and-forget, so any event arriving before the listener is live is
silently dropped and the widget never updates.

Move the pageWindow handle resolution + a waitForFunction gate on
window.__pageModuleReady (sentinel flipped at the very bottom of page.js)
BEFORE the first executeTag() call. This guarantees page.js has finished
module evaluation (including installing its tag subscribers) before any
tag command runs.

Verified: 236 pass / 2 fail / 2 skip (baseline) across two consecutive
full-suite runs. The remaining two failures (download.spec.ts:151 popup
cleanup and smoke.spec.ts:1438 quit/restart commands) are pre-existing
flakes unrelated to this change.

+19 -4
+19 -4
tests/desktop/smoke.spec.ts
··· 2068 2068 }; 2069 2069 2070 2070 try { 2071 + // Grab the page window handle first so we can gate on page.js readiness 2072 + // BEFORE firing the setup tag. Under full-suite load the 2s sleep above 2073 + // is not enough — the tag command can otherwise publish `tag:item-added` 2074 + // before page.js has run its top-level `api.subscribe('tag:item-added', 2075 + // ...)`. tile-preload's `subscribeImpl` attaches the underlying 2076 + // `ipcRenderer.on('pubsub:tag:item-added')` listener synchronously from 2077 + // page.js module evaluation, so gating on `__pageModuleReady` (the 2078 + // sentinel flipped at the very bottom of page.js) guarantees the 2079 + // listener is live. Electron's `webContents.send` is fire-and-forget — 2080 + // a pubsub event that arrives before the listener is attached is 2081 + // silently dropped, which is the root cause of the full-suite flake. 2082 + const pageWindow = await sharedApp.getWindow(dynamicKey, 10000); 2083 + expect(pageWindow).toBeTruthy(); 2084 + await pageWindow.waitForFunction( 2085 + () => (window as unknown as { __pageModuleReady?: boolean }).__pageModuleReady === true, 2086 + null, 2087 + { timeout: 10000 } 2088 + ); 2089 + 2071 2090 // First tag establishes the item in the datastore and triggers the page's 2072 2091 // resolveItemId fallback, setting currentItemId for subsequent events 2073 2092 const setupResult = await executeTag(setupTag); 2074 2093 expect((setupResult as any).success).toBe(true); 2075 - 2076 - // Get the specific page window we just opened (matches URL key) 2077 - const pageWindow = await sharedApp.getWindow(dynamicKey, 10000); 2078 - expect(pageWindow).toBeTruthy(); 2079 2094 2080 2095 // Wait for page.js to initialize and for the setup tag to appear 2081 2096 // (proves the reactive update path works and currentItemId is set)