Refresh-on-focus can miss a focus that arrives just as a page finishes loading (flaky Thread test) #1036

Closed
opened 2026-10-02 05:01:10 +00:00 by claude-bot · 1 comment
Collaborator

Seen

PR #1034 (backend only) went red on CI / Frontend (shard 2/2), run https://git.rhoving.com/rbrooks/Quest-Board/actions/runs/1797 :

src/pages/discussions/Thread.test.jsx
reading it > what was unread when it was opened (#1020) > keeps them marked after the thread is read again, which says nothing is new
TestingLibraryElementError: Unable to find an element with the text: Arrived while reading.
  147 |       window.dispatchEvent(new Event("focus"));
  148 |       await screen.findByText("Arrived while reading.");

1 failed, 1563 passed; the shard took 888 s (a busy runner). The find waits 5 s, so this was not slowness: the focus never caused a second read.

Cause (read from the code; not reproduced locally)

useFocusRefresh (pages/discussions/useTalk.js) keeps the latest refresh in a ref and updates that ref in a passive effect (useEffect). Thread's callback is if (thread && !deleted) load(). Passive effects run some time after the commit that draws the page, so there is a moment when the posts are on screen and the ref still holds the callback from the render before, in which thread was null. A focus in that moment does nothing. The test dispatches focus as soon as the posts appear, which on a loaded runner lands inside it.

For a person it means a focus or tab-visible event in the instant a thread, a thread list or a Talk count finishes loading is dropped; the next one works.

Fix

Update the ref in a layout effect, which runs inside the commit, so the callback is current by the time the page can be seen. One line in useFocusRefresh, for all three callers (Thread, useThreads, useTalkCount).

## Seen PR #1034 (backend only) went red on **CI / Frontend (shard 2/2)**, run https://git.rhoving.com/rbrooks/Quest-Board/actions/runs/1797 : ``` src/pages/discussions/Thread.test.jsx reading it > what was unread when it was opened (#1020) > keeps them marked after the thread is read again, which says nothing is new TestingLibraryElementError: Unable to find an element with the text: Arrived while reading. 147 | window.dispatchEvent(new Event("focus")); 148 | await screen.findByText("Arrived while reading."); ``` 1 failed, 1563 passed; the shard took 888 s (a busy runner). The find waits 5 s, so this was not slowness: the focus never caused a second read. ## Cause (read from the code; not reproduced locally) `useFocusRefresh` (`pages/discussions/useTalk.js`) keeps the latest `refresh` in a ref and updates that ref in a passive effect (`useEffect`). Thread's callback is `if (thread && !deleted) load()`. Passive effects run some time after the commit that draws the page, so there is a moment when the posts are on screen and the ref still holds the callback from the render before, in which `thread` was null. A focus in that moment does nothing. The test dispatches focus as soon as the posts appear, which on a loaded runner lands inside it. For a person it means a focus or tab-visible event in the instant a thread, a thread list or a Talk count finishes loading is dropped; the next one works. ## Fix Update the ref in a layout effect, which runs inside the commit, so the callback is current by the time the page can be seen. One line in `useFocusRefresh`, for all three callers (`Thread`, `useThreads`, `useTalkCount`).
Author
Collaborator

Done in PR #1040, merged to main on 2026-10-02 with CI green.

useFocusRefresh now sets its callback ref in a layout effect, inside the commit, so a focus or tab-visible event arriving just as a thread, a thread list or a Talk count finishes loading is no longer dropped. New useTalk.test.jsx covers it.

The PR's first CI run went red on a different flaky test (Preview.test.jsx, #1039); it passed once main carried that fix (PR #1041). Branches opened before this merge need main merged in to pick it up; #1034 has been updated.

Done in PR #1040, merged to main on 2026-10-02 with CI green. `useFocusRefresh` now sets its callback ref in a layout effect, inside the commit, so a focus or tab-visible event arriving just as a thread, a thread list or a Talk count finishes loading is no longer dropped. New `useTalk.test.jsx` covers it. The PR's first CI run went red on a different flaky test (`Preview.test.jsx`, #1039); it passed once main carried that fix (PR #1041). Branches opened before this merge need main merged in to pick it up; #1034 has been updated.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#1036
No description provided.