fix(test): fix race condition in next-pages HMR test#26311
Conversation
|
Updated 8:12 PM PT - Jan 20th, 2026
❌ Your commit
🧪 To try this PR locally: bunx bun-pr 26311That installs a local version of the PR into your bun-26311 --bun |
4b90a70 to
6844778
Compare
WalkthroughAdded persistent console buffering and an index-aware waitForConsoleMessage to the dev-server Puppeteer test; navigations and reloads now use explicit load semantics and console-message index markers (initial load, reload, HMR) to avoid race conditions and sequence test steps. (50 words) Changes
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
6844778 to
c598c5c
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
test/integration/next-pages/test/dev-server-puppeteer.ts (1)
66-85: Reload wait can resolve before the reload happens.Both
initial_load_promiseandreload_promiselisten for/counter a/and are attached at the same time (lines 82–83), so the first match resolves both. This makesawait reload_promiseat line 117 effectively a no-op, reintroducing the race condition the early attachment was meant to prevent. Wait for the second match (or otherwise distinguish the reload signal) while still attaching the listener early.🛠️ Suggested fix (wait for Nth match)
- function waitForConsoleMessage(page: Page, regex: RegExp) { + function waitForConsoleMessage(page: Page, regex: RegExp, matchIndex = 1) { const { resolve, promise } = Promise.withResolvers<void>(); + let matches = 0; function onMessage(msg: ConsoleMessage) { const text = msg.text(); if (regex.test(text)) { - page.off("console", onMessage); - resolve(); + if (++matches >= matchIndex) { + page.off("console", onMessage); + resolve(); + } } } page.on("console", onMessage); return promise; } @@ - const initial_load_promise = waitForConsoleMessage(p, /counter a/); - const reload_promise = waitForConsoleMessage(p, /counter a/); + const initial_load_promise = waitForConsoleMessage(p, /counter a/, 1); + const reload_promise = waitForConsoleMessage(p, /counter a/, 2);
4471dae to
bca74c3
Compare
|
CI build failed due to infrastructure issue (Buildkite API returning malformed JSON in SetupBuildkite.cmake). Tests didn't run. Will need a rebuild. |
The HMR test was failing intermittently due to multiple race conditions: 1. Console message listeners could miss messages or match wrong occurrence - Fixed by collecting ALL messages into an array and searching with startIndex 2. Page interactions happened before navigation completed - Fixed by awaiting p.goto() and p.reload() with waitUntil: "load" The new approach: - A persistent listener collects all console messages from page creation - waitForConsoleMessage(page, regex, startIndex) searches the array - If message exists, returns immediately; otherwise waits for new messages - Each call returns the next index, allowing waiting for Nth occurrence Fixes #11255 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
bca74c3 to
9317608
Compare
The test was failing because after reload, the element was queried immediately after the page load event but before React hydration completed. The click wasn't taking effect because the element wasn't fully interactive yet. Fixes: 1. Use networkidle0 instead of load for reload to wait for all network requests to complete 2. Explicitly wait for #counter-fixture to be visible before interacting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@test/integration/next-pages/test/dev-server-puppeteer.ts`:
- Around line 74-93: The waitForConsoleMessage function has a race between
checking consoleMessages and attaching the temporary listener; fix it by first
attaching the onMessage listener to page, then re-scan the consoleMessages
buffer (consoleMessages) for a match and if found remove the listener and
resolve immediately, otherwise keep the listener active and return the promise
from Promise.withResolvers; update references in waitForConsoleMessage and
ensure the onMessage handler removes itself via page.off("console", onMessage)
when resolving so you don't leak listeners.
Fixed race condition where a message could arrive between checking the buffer and attaching the listener. Now we attach the listener FIRST, then check the buffer. A `resolved` flag prevents double resolution and ensures the listener is properly removed. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
test/integration/next-pages/test/dev-server.test.tsTest plan
Fixes #11255
🤖 Generated with Claude Code