Skip to content

fix(test): make section-sheet tests independent of the wall clock - #34

Open
kubiknyc wants to merge 1 commit into
mainfrom
worktree-fix-jest-timeout-flake
Open

fix(test): make section-sheet tests independent of the wall clock#34
kubiknyc wants to merge 1 commit into
mainfrom
worktree-fix-jest-timeout-flake

Conversation

@kubiknyc

@kubiknyc kubiknyc commented Aug 3, 2026

Copy link
Copy Markdown
Owner

The eight *SectionSheet suites each run a single test that performs the
suite's first render -- paying the one-time cost of lazily requiring the
RN/Expo component stack -- and then waits a real 400ms debounce, both
inside one jest budget. Warm, that costs ~2.6s against the 5s default;
on a cold transform cache it exceeds even 30s. So the suites failed
deterministically after --clearCache, in a fresh worktree, or whenever
Windows cleaned %TEMP%\jest. It read as a flake only because cache state
varied between runs.

Replace waitFor with the fake-timer pattern already used by
CrewWorkSheet.test.tsx and useSectionDraft.test.tsx: advance by the
exported SECTION_DRAFT_DEBOUNCE_MS, flush the promise chain issueWrite
kicks off, then assert. try/finally restores real timers.

Also set testTimeout to 30000. That does not fix the sheets on its own,
but it fixes RepositoryProvider.rekey.test.tsx cold and gives the
remaining real-timer tests headroom over the 5s default the repo never
chose.

Verified cold (--clearCache) with coverage at 21 workers: 64/64 suites,
790/790 tests. npm run verify exits 0.

Caveat: fake timers also fake jest's own timeout timer, so the 30s limit
is not enforced inside these eight tests.

Summary by CodeRabbit

  • Tests

    • Improved coverage and reliability for report section draft updates.
    • Tests now consistently validate delayed saves and repository updates without relying on wall-clock polling.
    • Added safeguards to ensure timer-based test behavior is properly restored after each test.
  • Chores

    • Increased the automated test timeout to support longer-running test scenarios.

The eight *SectionSheet suites each run a single test that performs the
suite's first render -- paying the one-time cost of lazily requiring the
RN/Expo component stack -- and then waits a real 400ms debounce, both
inside one jest budget. Warm, that costs ~2.6s against the 5s default;
on a cold transform cache it exceeds even 30s. So the suites failed
deterministically after --clearCache, in a fresh worktree, or whenever
Windows cleaned %TEMP%\jest. It read as a flake only because cache state
varied between runs.

Replace waitFor with the fake-timer pattern already used by
CrewWorkSheet.test.tsx and useSectionDraft.test.tsx: advance by the
exported SECTION_DRAFT_DEBOUNCE_MS, flush the promise chain issueWrite
kicks off, then assert. try/finally restores real timers.

Also set testTimeout to 30000. That does not fix the sheets on its own,
but it fixes RepositoryProvider.rekey.test.tsx cold and gives the
remaining real-timer tests headroom over the 5s default the repo never
chose.

Verified cold (--clearCache) with coverage at 21 workers: 64/64 suites,
790/790 tests. npm run verify exits 0.

Caveat: fake timers also fake jest's own timeout timer, so the 30s limit
is not enforced inside these eight tests.
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates eight section-sheet tests to use Jest fake timers for draft debounce handling. The tests flush asynchronous writes and restore real timers. Jest now allows tests to run for up to 30 seconds.

Changes

Section draft test timing

Layer / File(s) Summary
Deterministic debounce test timing
package.json, src/components/report/*SectionSheet.test.tsx
The tests replace wall-clock waitFor polling with SECTION_DRAFT_DEBOUNCE_MS, fake-timer advancement, explicit promise flushing, and guaranteed timer restoration. Jest receives a 30-second test timeout.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • kubiknyc/worklog#8: Introduced the NotesSectionSheet/CrewSectionSheet autosave and useSectionDraft patterns exercised by these tests.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: removing wall-clock dependence from SectionSheet tests.
Description check ✅ Passed The description explains the problem, solution, verification results, timeout change, and fake-timer caveat, but omits several template headings.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-fix-jest-timeout-flake

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/components/report/DelaysSectionSheet.test.tsx (1)

22-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the manual two-tick microtask flush with jest.advanceTimersByTimeAsync.

All eight converted tests use the same pattern: jest.advanceTimersByTime(SECTION_DRAFT_DEBOUNCE_MS) followed by exactly two await Promise.resolve() calls, with a comment stating this exists because "issueWrite chains through a Promise." This hard-codes an assumption about the promise-chain depth inside useSectionDraft.ts. If that depth changes in the future (for example, an added .then() for optimistic updates or error handling), all eight tests can start failing for reasons unrelated to the behavior under test, and each failure requires re-deriving the correct tick count. Jest 29 (the version in use here) exposes jest.advanceTimersByTimeAsync(msToRun), which flushes scheduled promise callbacks between timer executions automatically, removing the need to guess the tick count. This does not affect correctness today (the PR states 790/790 tests pass), and the current pattern matches the documented repo precedent in CrewWorkSheet.test.tsx and useSectionDraft.test.tsx, so this is optional rather than urgent.

  • src/components/report/DelaysSectionSheet.test.tsx#L22-L38: Replace jest.advanceTimersByTime(SECTION_DRAFT_DEBOUNCE_MS) plus the two await Promise.resolve() calls with await jest.advanceTimersByTimeAsync(SECTION_DRAFT_DEBOUNCE_MS).
  • src/components/report/DeliveriesSectionSheet.test.tsx#L21-L43: Apply the same replacement.
  • src/components/report/EquipmentSectionSheet.test.tsx#L21-L39: Apply the same replacement.
  • src/components/report/InspectionsSectionSheet.test.tsx#L21-L43: Apply the same replacement.
  • src/components/report/RfisSectionSheet.test.tsx#L21-L38: Apply the same replacement.
  • src/components/report/SafetySectionSheet.test.tsx#L25-L42: Apply the same replacement.
  • src/components/report/VisitorsSectionSheet.test.tsx#L21-L38: Apply the same replacement.
  • src/components/report/WeatherSectionSheet.test.tsx#L21-L43: Apply the same replacement.
♻️ Proposed pattern change (applies to each site above)
-    fireEvent.press(getByLabelText('Add delay'));
-    jest.advanceTimersByTime(SECTION_DRAFT_DEBOUNCE_MS);
-    // Flush the microtask chain the debounced callback kicks off (issueWrite
-    // chains through a Promise) — fake timers don't do this for us.
-    await Promise.resolve();
-    await Promise.resolve();
+    fireEvent.press(getByLabelText('Add delay'));
+    await jest.advanceTimersByTimeAsync(SECTION_DRAFT_DEBOUNCE_MS);
     expect(mockUpdateSection).toHaveBeenCalledWith('r1', 'delays', expect.anything(), false);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/report/DelaysSectionSheet.test.tsx` around lines 22 - 38,
Replace the manual timer advancement and two Promise.resolve() calls in the test
flow around DelaysSectionSheet, applying the same change at
src/components/report/DelaysSectionSheet.test.tsx:22-38,
src/components/report/DeliveriesSectionSheet.test.tsx:21-43,
src/components/report/EquipmentSectionSheet.test.tsx:21-39,
src/components/report/InspectionsSectionSheet.test.tsx:21-43,
src/components/report/RfisSectionSheet.test.tsx:21-38,
src/components/report/SafetySectionSheet.test.tsx:25-42,
src/components/report/VisitorsSectionSheet.test.tsx:21-38, and
src/components/report/WeatherSectionSheet.test.tsx:21-43. Use await
jest.advanceTimersByTimeAsync(SECTION_DRAFT_DEBOUNCE_MS) and remove the obsolete
microtask-flush comment and awaits.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/components/report/DelaysSectionSheet.test.tsx`:
- Around line 22-38: Replace the manual timer advancement and two
Promise.resolve() calls in the test flow around DelaysSectionSheet, applying the
same change at src/components/report/DelaysSectionSheet.test.tsx:22-38,
src/components/report/DeliveriesSectionSheet.test.tsx:21-43,
src/components/report/EquipmentSectionSheet.test.tsx:21-39,
src/components/report/InspectionsSectionSheet.test.tsx:21-43,
src/components/report/RfisSectionSheet.test.tsx:21-38,
src/components/report/SafetySectionSheet.test.tsx:25-42,
src/components/report/VisitorsSectionSheet.test.tsx:21-38, and
src/components/report/WeatherSectionSheet.test.tsx:21-43. Use await
jest.advanceTimersByTimeAsync(SECTION_DRAFT_DEBOUNCE_MS) and remove the obsolete
microtask-flush comment and awaits.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f5406e8d-2836-4c49-a023-a7db6372f001

📥 Commits

Reviewing files that changed from the base of the PR and between d04866b and 7a895b8.

📒 Files selected for processing (9)
  • package.json
  • src/components/report/DelaysSectionSheet.test.tsx
  • src/components/report/DeliveriesSectionSheet.test.tsx
  • src/components/report/EquipmentSectionSheet.test.tsx
  • src/components/report/InspectionsSectionSheet.test.tsx
  • src/components/report/RfisSectionSheet.test.tsx
  • src/components/report/SafetySectionSheet.test.tsx
  • src/components/report/VisitorsSectionSheet.test.tsx
  • src/components/report/WeatherSectionSheet.test.tsx

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