Skip to content

fix(e2e): replace wall-clock waits with product-emitted signals - #271

Merged
h4yfans merged 1 commit into
mainfrom
fix/e2e-shard-1-structural-primitives
Apr 18, 2026
Merged

fix(e2e): replace wall-clock waits with product-emitted signals#271
h4yfans merged 1 commit into
mainfrom
fix/e2e-shard-1-structural-primitives

Conversation

@h4yfans

@h4yfans h4yfans commented Apr 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

Structural fix for the recurring shard 1/3 failures. Stops patching individual flakes with bigger timeouts.

  • Product signals (tiny surface): calendar-week-view.tsx emits data-anchor-date + data-visible-day-start; test-hooks.ts exposes hasNoteOnDevice(noteId) for direct main-process replication probing.
  • Test primitives (tests/e2e/utils/wait-helpers.ts): waitForStable, waitForNoteReplicated, waitForAnchorDate, getAnchorDate, getVisibleDayStart.
  • Test rewrites: calendar-week-scroll.e2e.ts → semantic user-observable assertions (visible week moved forward, Today returns to origin within 1-day rounding slack). body-crdt-coverage-variants.e2e.ts V6 → one syncBothAndWait + parallel waitForNoteReplicated on both devices via the new hook. Removed the orphaned readReplicatedNoteStatus.

Test plan

  • 5 consecutive green local runs on the three CI-failing tests (TZ=UTC CI=1 --workers=1 --retries=0)
  • Full body-crdt-coverage-variants + calendar + calendar-comprehensive + calendar-week-scroll suites: 29 passed, 1 skipped, 0 failed
  • pnpm typecheck:web and pnpm typecheck:node clean
  • CI shard 1/3 passes 3 consecutive runs
  • CI shard 2/3 + 3/3 stay green

Follow-up (not in this PR)

  1. Migrate ~300 waitForTimeout call sites across 21 files to waitForStable (one file per PR)
  2. Runtime-balanced sharding instead of alphabetical
  3. Warm-cache fixtures

🤖 Generated with Claude Code

Structural fix for shard 1/3 flakiness. Stops patching individual tests.

Root cause: tests asserted on async effects (CSS smooth-scroll completion,
cross-device CRDT convergence) that the product emits no readiness signal
for, and compensated with fixed waitForTimeout values tuned for fast local
dev boxes. Under CI xvfb load those values were exceeded and tests read
mid-flight state. Previous stabilizations only widened the wall-clock
windows.

Three layered changes:

1. Product signals (minimal, targeted):
   - src/renderer/components/calendar/calendar-week-view.tsx: expose
     anchorDate + visibleDayStart as data attributes so tests can observe
     state directly instead of reverse-engineering via scrollLeft.
   - src/main/test-hooks.ts: add hasNoteOnDevice(noteId) hook returning
     recordPresent/crdtPresent/crdtBody for the local device. Lets tests
     probe replication with a single main-process roundtrip instead of
     polling UI body text through the renderer.

2. Reusable test primitives (new wait-helpers.ts):
   - waitForStable<T>: polls a value and returns when it has not changed
     for stableFor ms, or throws on timeout. Signal-based, CI-safe.
   - waitForNoteReplicated: wraps the new test hook and normalizes the
     expected body. Replaces the loop-then-hard-equal pattern.
   - getAnchorDate / waitForAnchorDate / getVisibleDayStart helpers.

3. Test rewrites:
   - calendar-week-scroll.e2e.ts: assertions shifted from pixel-tolerance
     scrollLeft comparisons to user-observable semantics (visible week
     moved forward, Today returns to origin within 1-day rounding slack).
     Deleted the waitForTimeout-based waitForScrollSettle helper.
   - body-crdt-coverage-variants.e2e.ts V6: replaced the syncBothAndWait
     inside expect.poll loop with one sync round-trip plus per-device
     waitForNoteReplicated in parallel. Removed the orphaned
     readReplicatedNoteStatus helper.

Verification: 5 consecutive green local runs under TZ=UTC CI=1 --workers=1
--retries=0 on the three CI-failing tests (~23s per 4-test batch). Full
body-crdt-coverage-variants + calendar + calendar-comprehensive +
calendar-week-scroll suites: 29 passed, 1 skipped, 0 failed (3.7 min).
typecheck:web and typecheck:node clean.

Follow-up (not in this change): migrate ~300 waitForTimeout call sites
across 21 files to waitForStable; shard rebalance; warm-cache fixtures.
@h4yfans
h4yfans merged commit e6efbab into main Apr 18, 2026
7 of 8 checks passed
h4yfans added a commit that referenced this pull request May 6, 2026
@h4yfans
h4yfans deleted the fix/e2e-shard-1-structural-primitives branch May 6, 2026 16:36
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