Skip to content

test: preload the lazy highlighter in mount() (intermittent 'streaming markdown chunks' hookFailed) - #1510

Merged
currentbits merged 1 commit into
mainfrom
fix/preload-highlighter-in-tests
Oct 6, 2026
Merged

currentbits merged 1 commit into
mainfrom
fix/preload-highlighter-in-tests

Conversation

@currentbits

Copy link
Copy Markdown
Owner

Symptom: "streaming markdown chunks › final DOM after a chunked stream equals a one-shot mount" has failed intermittently on macOS CI with failureType: 'hookFailed', on two unrelated PRs (#1505 and #1507). The hook that fails is the global afterEach(unmountAll) in test/support/dom.ts. It throws when React logged any console.error while a component was mounted.

Likely cause: test 15 is the first test in that file to mount fenced code with a known language (ts, md). useHighlightedBlock calls setState after the lazy highlight.js chunk (#1500) loads. If that import resolves between act scopes, React warns "not wrapped in act" and the gate fails the hook.

Fix: mount() now preloads the highlighter, the same way it already preloads lazy views (preloadLazyNamed). Every later then callback is then a microtask inside act. A tiny preloadHighlighter() export is added in src/syntaxHighlight.ts.

Honest note: I could not reproduce the failure locally. Delays of 5 to 1500 ms injected into the engine load didn't trigger it, and the failed attempt's log was overwritten by the passing re-run. This removes the one known path for an out-of-act update in that test, but it isn't proven to be the cause. The merge script now keeps full failure logs, so a recurrence will show the actual console.error.

test:renderer passes 2806 of 2806.

🤖 Generated with Claude Code

… inside act

useHighlightedBlock/useHighlightedLines setState after the lazy highlight.js
chunk loads (#1500). When that promise resolved between act scopes, React
logged 'not wrapped in act' and the console.error gate failed a later hook:
the intermittent 'streaming markdown chunks' hookFailed on CI (#1505, #1507).
Preloading it once in mount() (like preloadLazyNamed) makes every later
then-callback a microtask inside act.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-06T15:25:24.566183Z 846b9e3 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@currentbits

Copy link
Copy Markdown
Owner Author

Cause confirmed. It reproduced locally in a full renderer-suite run on main merged with #1509, without this fix:

not ok 15 - final DOM after a chunked stream equals a one-shot mount
  failureType: 'hookFailed'
  error: React logged 2 console error(s):
    An update to %s inside a test was not wrapped in act(...) … CodeBlock

CodeBlock is the useHighlightedBlock consumer: the lazy highlighter's setState landed outside act. That's exactly the path this PR preloads.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant