Radix UI and @floating-ui call requestAnimationFrame for layout/positioning
on every render — Popovers, DropdownMenus, Checkboxes, etc. In jsdom those
callbacks are deferred outside the current act() boundary, leaving pending
state updates that keep the act() settlement loop running until Vitest's
5000ms hard timeout kills the test. Under load (full suite) there is no
slack to absorb the deferral.
Overriding requestAnimationFrame/cancelAnimationFrame with synchronous
no-ops in the global test setup ensures every Radix UI callback completes
inside the current act() cycle. This fixes the whole class of
Radix-UI-induced flaky timeouts without touching individual test files.
https://claude.ai/code/session_012ACmUs2vAwEF9jZu7Guos2
The previous fix mocked SportIcon to render <img> elements. In jsdom, those
images fail to load and schedule async error callbacks that can stall React's
act() settlement loop when the full suite runs under load, causing the test to
hit the 5000ms timeout intermittently.
Replace the async mock factory with a trivial synchronous stub that returns
null — no images, no async events. resolveSportIconUrl URL resolution is
already covered by its own unit tests, so no coverage is lost.
https://claude.ai/code/session_012ACmUs2vAwEF9jZu7Guos2
Replace async userEvent.click with fireEvent.click for the sport filter
dropdown test when hasTeam=true. The extra Checkbox components rendered in
that path stall userEvent's act() settlement loop inside Radix UI, causing
the test to hang. fireEvent bypasses the async machinery while still
exercising the open/close behavior.
https://claude.ai/code/session_012ACmUs2vAwEF9jZu7Guos2
- Add unique constraint on participantSeasonResults(participantId, sportsSeasonId)
and rewrite upsert to use onConflictDoUpdate, eliminating race conditions and
sequential N*2 queries on sync
- Fetch pending mappings for all sport types; extend Unmatched card to show for
individual sports and route resolve-mapping to participantSeasonResults for
season_standings sports
- Replace hardcoded SEASON_STANDINGS_SIMULATOR_TYPES Set with
sportsSeason.scoringPattern === "season_standings" to avoid drift
- Remove countCompletedRaces() from F1 adapter — gamesPlayed/winPct were computed
but discarded by the orchestrator for season_standings sports
- Replace duplicate parseRacingStatsMap() with the shared statsMap() from espn.ts
https://claude.ai/code/session_012ACmUs2vAwEF9jZu7Guos2
Implements F1StandingsAdapter (Jolpica/Ergast API) and IndyCarStandingsAdapter
(ESPN IRL API), wires them into the syncStandings orchestrator with a
season_standings branch that upserts into participantSeasonResults instead of
regularSeasonStandings, and adds a "Championship Standings" card with a Sync
Standings button to the admin sports season page for individual sports.
https://claude.ai/code/session_012ACmUs2vAwEF9jZu7Guos2