Skip to content

Flaky test: SPEAKER-001 chromium timeout from MockEmpiricaProvider re-render loop #1210

Description

@JamesPHoughton

Problem

SPEAKER-001: setSpeaker NotAllowedError is caught without crashing intermittently times out on Chromium (passes consistently on Firefox and WebKit). The test hits the 90s timeout during teardown (browserContext.close), with the console spammed by:

[MockEmpiricaProvider] handleChange called - forcing re-render

This is an infinite re-render loop in the MockEmpiricaProvider, not a test logic issue.

How to reproduce

# Run just this test on chromium — may need several attempts to trigger
npx playwright test --config playwright/playwright.config.mjs "video-call/mocked/Speaker" --grep "SPEAKER-001" --project chromium

The failure is non-deterministic. It passed in a full 249-test run but failed in an isolated 3-test run on the same commit.

Root cause hypothesis

The MockEmpiricaProvider's handleChange callback triggers a re-render whenever a game.get() reads a key that isn't in the mock's attrs. In SPEAKER-001, the game mock only defines dailyUrl:

game: { attrs: { dailyUrl: 'https://test.daily.co/room' } },

When VideoCall reads game.get("recordingEnabled") (added in PR #1209) or any other key not in attrs, the mock may enter a re-render cycle. This was previously observed and documented — useMemo with Object.is() comparison on inline [] defaults creates new refs each render.

The fix applied earlier (stable defaults outside the component) may not cover all paths, or a new game.get() call for a missing key may be re-triggering the issue.

Suggested debugging approach

  1. Check if adding recordingEnabled to test fixtures prevents the flake:

    game: { attrs: { dailyUrl: 'https://test.daily.co/room', recordingEnabled: false } },

    If this fixes it, the root cause is game.get() for missing keys triggering reactivity.

  2. Instrument MockEmpiricaProvider to log which key access triggers handleChange — add a stack trace or key name to the log message.

  3. Investigate why Chromium-only — may be a timing difference in React's batching or event loop scheduling that makes the re-render loop more likely to cascade on Chromium.

  4. Consider making game.get() for missing keys return undefined without triggering reactivity — this would make the mock more robust against new keys being read from game state.

Context

  • Observed during PR fix(recording): start recording client-side to avoid Daily API rate limits #1209 (client-side recording start)
  • Related to the MockEmpiricaProvider reactivity fix from 2026-02-16 (see playwright/mocks/MockEmpiricaProvider.jsx)
  • Test file: playwright/component-tests/video-call/mocked/Speaker.ct.jsx:94
  • Trace available at: test-results/video-call-mocked-Speaker.-2992c--is-caught-without-crashing-chromium/trace.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions