Skip to content

fix(tests): await in-flight requests in loading-state tests - #505

Merged
ralyodio merged 1 commit into
masterfrom
fix/flaky-dangling-timer-tests
Jul 25, 2026
Merged

fix(tests): await in-flight requests in loading-state tests#505
ralyodio merged 1 commit into
masterfrom
fix/flaky-dangling-timer-tests

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Fixes the test job failure on master (run 30119962468).

What broke

ReferenceError: window is not defined
  ❯ resolveUpdatePriority  react-dom-client.development.js:1308
  ❯ dispatchSetState       react-dom-client.development.js:9126
  ❯ handleSubmit           src/components/reviews/ReviewForm.tsx:58

Two loading-state tests mock a request that resolves on a 100ms timer, assert the loading text synchronously, then return without ever awaiting it:

vi.mocked(reviewsApi.create).mockImplementation(
  () => new Promise((resolve) => setTimeout(() => resolve({...}), 100))
);
fireEvent.click(submitButton);
expect(screen.getByText("Submitting...")).toBeInTheDocument();
});  // <- test ends here; the timer is still pending

The timer outlives the test. Vitest tears down jsdom, then the component's finally { setIsSubmitting(false) } fires and reaches React with no window.

Why it looked random

It only fails when teardown happens to land inside that 100ms window, so it passes locally and on PR branches and then fails on a master push — and it reports against whichever file was unlucky, not the one at fault.

Affected: ReviewForm.test.tsx and NotificationBell.test.tsx (same pattern).

Fix

Await the loading state clearing, which keeps the request inside the test. This also strengthens both tests — they previously asserted only that the loading state appeared, never that it cleared.

Not caused by the bulk-payments PR

The pattern dates to e5703f3 (Jan 2026); #504 didn't touch either file. Adding a test file shifted worker timing just enough to expose the latent race.

Full suite: 1765 pass. Pre-commit gate (lint + type-check + tests + build) passed.

🤖 Generated with Claude Code

Two loading-state tests mocked a request that resolves on a 100ms timer,
asserted the loading text synchronously, then returned without awaiting
it. The timer outlives the test: vitest tears down jsdom, the component's
late setState reaches React with no `window`, and the run dies with

  ReferenceError: window is not defined
    at resolveUpdatePriority (react-dom-client.development.js)
    at handleSubmit (src/components/reviews/ReviewForm.tsx:58)

Because it depends on whether teardown lands inside that 100ms window,
it surfaces as an unrelated random CI failure — the suite passes locally
and on PR branches, then fails on a master push (run 30119962468).

Awaiting the loading state's disappearance keeps the request inside the
test and also strengthens both tests, which previously only checked that
the loading state appeared, never that it cleared.

Predates the bulk-payments work (the pattern dates to e5703f3, Jan 2026);
that PR only shifted worker timing enough to expose it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio merged commit ba1034c into master Jul 25, 2026
5 checks passed
@ralyodio
ralyodio deleted the fix/flaky-dangling-timer-tests branch July 25, 2026 01:19
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