Commit 0a758fb
* Add comprehensive video call testing strategy and implementation
This commit addresses the lack of tests for the videocall interface by
introducing a layered testing approach that balances speed, cost, and
confidence.
## What's Added
### Documentation
- **VIDEOCALL_TESTING_STRATEGY.md**: Complete testing philosophy and
implementation plan covering unit tests (mocked), contract tests,
smoke tests (live Daily.co), and cross-browser E2E
- **VIDEOCALL_TESTING_QUICKSTART.md**: 30-minute quick start guide to
get first tests running
### Unit Tests (Vitest)
- Mock utilities for @daily-co/daily-react components and hooks
- Example tests for VideoCall subscription management and device alignment
- Fast feedback loop without hitting Daily.co API
### E2E Smoke Tests (Playwright)
- New playwright-videocall/ directory for gradual migration from Cypress
- Live Daily.co integration tests with automatic room creation/cleanup
- Helpers for managing test rooms and minimizing API usage
- Cross-browser support (Chromium, Firefox, WebKit)
### CI/CD Integration
- GitHub Actions workflow with smart path filtering
- Runs unit tests on every commit to call-related code
- Runs smoke tests only on main branch or manual trigger
- Supports manual cross-browser test execution
## Testing Philosophy
Uses a 4-layer approach:
1. Unit tests (mocked) - Fast feedback, 90% of runs
2. Contract tests - Verify Daily.co API assumptions
3. Smoke tests (live) - Confidence before deployment
4. Cross-browser E2E - Catch browser-specific bugs
## Cost Management
- Free tier Daily.co usage: ~1% per month (100 min / 10,000 available)
- Short-lived rooms (1 hour expiry)
- Conditional CI execution (path filters)
- Automated room cleanup
## Playwright vs Cypress
Recommends Playwright for new video tests due to:
- Better multi-browser support
- Improved WebRTC/permission mocking
- Faster execution
- Modern API design
Existing Cypress tests remain untouched for gradual migration.
## Next Steps
See VIDEOCALL_TESTING_QUICKSTART.md for:
- Setting up Playwright
- Running first tests
- Customizing for your app
- Adding to CI
https://claude.ai/code/session_01WNWJMiUufNo4NTgPx3pbU8
* Add Playwright component testing infrastructure
- Create playwright/ directory with clean separation:
- mocks/ for reusable Empirica mock classes (MockPlayer, MockGame, MockStage)
- helpers/ for scenario builders and Daily.co room setup
- component-tests/ for test files
- Add initial VideoCall component tests with real Daily.co rooms
- Integrate production server code for room management
- Add npm scripts for running component tests
- Create comprehensive documentation and README
This enables component-level testing with real WebRTC while mocking
Empirica state, avoiding the complexity of full E2E batch setup.
https://claude.ai/code/session_b1DG1
* Remove old testing infrastructure, keep only clean Playwright component tests
- Removed old E2E setup in playwright-videocall/
- Removed old subscription tests
- Removed old documentation and CI workflow
- Kept only clean playwright/ directory with reusable mocks and component tests
https://claude.ai/code/session_01WNWJMiUufNo4NTgPx3pbU8
* Remove old testing infrastructure and finalize clean component test setup
- Removed playwright-videocall/ directory (old E2E approach)
- Removed client/src/call/__tests__/ (old subscription tests)
- Removed docs/VIDEOCALL_TESTING_*.md (old documentation)
- Removed .github/workflows/videocall-tests.yml (old CI workflow)
- Kept only the new clean playwright/ component testing setup
https://claude.ai/code/session_b1DG1
* Refactor Playwright component tests for scalability and organization
Restructure component tests from single monolithic file into organized,
concern-based architecture to support scaling to hundreds of tests.
Changes:
- Split VideoCall.ct.jsx into three focused files by concern:
- VideoCall.basic.ct.jsx (smoke tests)
- VideoCall.states.ct.jsx (tile states: muted, waiting, etc.)
- VideoCall.layout.ct.jsx (multi-player scenarios)
- Create shared/fixtures.js with 5 reusable test configurations
- Move debug test to organized debug/ folder
- Add comprehensive documentation:
- playwright/README.md (architecture, config, troubleshooting)
- component-tests/README.md (organization principles)
- video-call/README.md (test catalog and guidelines)
- mocks/README.md (mock architecture deep dive)
- Add npm scripts for headed and UI modes
- Rename playwright.config.js to .mjs for ESM compatibility
All 7 tests passing. Ready for expansion with clear patterns established.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* test(playwright): migrate Cypress layout tests and add comprehensive assertions
- Migrate 8 Cypress discussionLayout scenarios to Playwright component tests (~30x faster)
- Create VideoCall.customLayouts.ct.jsx with 6 custom layout tests (2x2 grid, PiP, telephone game, breakout rooms, hide self view)
- Rename VideoCall.layout.ct.jsx → VideoCall.responsiveLayout.ct.jsx
- Expand responsive tests from 1 to 17 tests (player counts, screen widths, dynamic resizing)
- Add layout-helpers.js with deep assertions (overlap detection, z-index verification, space filling)
- Add layout-fixtures.js with reusable layout configurations
- Fix bug in DailyVideo mock showing "mirrored" on all tiles instead of just local participant
- Fix z-index test by checking parent element instead of Tile itself
- Add MIGRATION.md tracking Cypress → Playwright migration progress
All 28 component tests passing ✅
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: Add dual-config Playwright component testing for VideoCall
Implements comprehensive component testing infrastructure with separate
configs for mocked and integration tests.
## Mocked Tests (29 passing ✓)
- Fast execution (~12s for all tests)
- Full control over Daily.co state for edge case testing
- No external dependencies (no API keys needed)
- Test coverage:
* Basic rendering and smoke tests (2 tests)
* Tile states (muted, waiting, connected) (3 tests)
* Responsive layouts (17 tests)
* Custom layouts (grid, PiP, breakout rooms) (7 tests)
## Integration Tests (Infrastructure ready)
- Separate config for real Daily.co WebRTC testing
- Requires DAILY_APIKEY for real connections
- Tests browser-specific behavior (Safari audio, device recovery)
- Currently under development
## Configuration
- playwright.config.mjs: Mocked Daily + Empirica (runs mocked/ tests)
- playwright.integration.config.mjs: Real Daily, mocked Empirica (runs integration/ tests)
- Package scripts: npm run test:component, test:component:integration
## File Organization
- component-tests/video-call/mocked/: Fast mocked tests
- component-tests/video-call/integration/: Real Daily integration tests
- component-tests/shared/: Shared fixtures and helpers
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: Resolve MockEmpiricaProvider reactivity bug and add extensive documentation
## The Problem
Components using usePlayer() weren't seeing updated player state after player.set()
was called, even though the mutation happened correctly. The root cause was that
MockPlayer instances were being recreated on every render, destroying all state.
## Root Causes Identified
1. Inline array literals as default props (players = []) created NEW array references
on every render, causing useMemo to re-evaluate and create brand new MockPlayer
instances
2. Including handleChange callback in useMemo dependencies caused unnecessary
re-creation of mock instances
3. Missing renderCount dependency in contextValue memoization meant Context
consumers weren't triggered to update after forceUpdate()
## The Three-Part Fix
### 1. Stable Default Values
- Define EMPTY_PLAYERS_ARRAY and EMPTY_OBJECT outside component
- React's useMemo uses Object.is() for comparison: [] !== [] but
EMPTY_PLAYERS_ARRAY === EMPTY_PLAYERS_ARRAY
### 2. Remove handleChange from useMemo Dependencies
- handleChange is stable (useCallback with empty deps)
- Including it caused mysterious re-creation bugs
- Safe to omit since it's passed to constructors, not read from closure
### 3. Memoize contextValue with renderCount Dependency
- When renderCount increments (via forceUpdate), create NEW contextValue object
- React Context detects reference change and propagates to consumers
- Consumers re-render and call player.get() to see fresh data
## Documentation Added
Added ~600 lines of detailed comments explaining:
- The observable mutation pattern (mutable state + manual re-render triggers)
- How React Context propagation works with the reactivity system
- Why instance stability is critical for state preservation
- Complete end-to-end reactivity flow diagrams
## Debug Test Suite
Added MockHarnessDebug.ct.jsx with 6 isolated tests that verify harness
reactivity without making Daily API calls, saving WebRTC call minutes during
development.
## Verification
- All 6 debug tests pass
- All 6 VideoCall integration tests pass
- Player instance stability confirmed (sameInstance: true across re-renders)
- State mutations propagate correctly to all components
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* playwright tests
* test: Add 93 mocked component tests for VideoCall features
Implements Phase 2 of the video call test plan: mocked component tests
covering all testable behaviors without requiring real Daily.co infrastructure.
New test files (playwright/component-tests/video-call/mocked/):
- Tile.ct.jsx (9 tests): self-view, video/audio muted states, waiting state
- Tray.ct.jsx (7 tests): Fix A/V button, camera/mic toggles, missing participant button
- FixAV.ct.jsx (14 tests): modal workflow, multi-select, mic/camera muted diagnosis+fix,
AudioContext suspended fix, success state, auto-close (FIXAV-001 to FIXAV-014)
- Subscriptions.ct.jsx (6 tests): drift detection, repair payload, cooldown enforcement,
unsubscribable tracks, log content (SUB-001 to SUB-006)
- AudioContext.ct.jsx (6 tests): suspended detection, banner UI, resume, auto-resume,
state logging (AUDIO-001 to AUDIO-006)
- ErrorReporting.ct.jsx (5 tests): camera/mic errors, Sentry capture, breadcrumbs
- DeviceAlignmentLogs.ct.jsx (3 tests): log deduplication, fallback messages
- Speaker.ct.jsx (4 tests): setSpeaker error handling, fallback retry, Sentry breadcrumb
- VideoCall.deviceAlignment.ct.jsx (3 tests): device label matching, skip conditions
- VideoCall.historyAndData.ct.jsx (5 tests): dailyId history, avReports logging
Mock infrastructure updates:
- MockDailyProvider: add MockCallObject EventEmitter with updateParticipants spy,
localAudio/localVideo stubs, setLocalAudio/setLocalVideo for soft-fix testing,
_audioEnabled/_videoEnabled state control, device stubs
- sentry-mock.js: full rewrite with window.mockSentryCaptures capturing all calls
- console-capture.js: new helper for intercepting console output in tests
- daily-hooks.jsx: fix useParticipantProperty to read from context
- playwright.config.mjs: set workers=2 to prevent parallel load failures
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* test: Add FIXAV-006/008 (mic/camera track-ended + re-acquire)
Extends mock infrastructure to support track-ended diagnosis:
- MockCallObject: add _audioReadyState/_videoReadyState (default 'live')
Tests set these to 'ended' to simulate mic/camera track ending mid-call.
- setInputDevicesAsync() now resets readyState='live' on re-acquisition,
allowing re-diagnosis to confirm the fix succeeded.
New tests in FixAV.ct.jsx (16 total, up from 14):
- FIXAV-006: mic track ended → microphoneTrackEnded detected → setInputDevicesAsync
re-acquires mic → readyState resets to 'live' → "Issue resolved"
- FIXAV-008: camera track ended → cameraTrackEnded detected → setInputDevicesAsync
re-acquires camera → readyState resets to 'live' → "Issue resolved"
Both tests use twoPlayerConfigWithDevices which provides
devices.microphones and devices.cameras (required by attemptSoftFixes).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* test: Add PERM-001 to PERM-004 (browser permission monitoring)
navigator.permissions.query() is a getter-only prototype property in Chrome,
so tests must use Object.defineProperty(navigator, 'permissions', ...) to
install a controllable mock (direct assignment silently fails).
New PermissionMonitoring.ct.jsx (4 tests):
- PERM-001: camera permission change → [Permissions] console.warn logged
- PERM-002: mic permission change → [Permissions] console.warn logged
- PERM-003: permission revoked to 'denied' → additional console.error logged
- PERM-004: browserPermissions field captured in Sentry reportedAVError
(hint.extra.beforeDiagnostics.browserPermissions.camera === 'denied')
Mock strategy:
- installPermissionsMock(): uses Object.defineProperty on navigator to
shadow the prototype getter with a configurable own property
- makePerm(): creates PermissionStatus objects with getter/setter on
'onchange' so VideoCall's handler can be assigned and then triggered
- window.triggerPermChange(type, newState): fires synthetic permission
change events from test code
PERM-005 (Daily participant permissions) and PERM-006 (blocked tracks)
remain deferred — different underlying systems.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* test: Add SPEAKER-004/006 (gesture prompt for Safari speaker gestures)
After merging main (f463d5d) which implemented the unified setup completion
prompt, add tests for the newly-available gesture prompt behavior:
- SPEAKER-004: gesture prompt overlay shown when setSpeaker throws NotAllowedError
- SPEAKER-006: gesture prompt dismisses after user clicks "Enable Audio"
- SPEAKER-002: updated to use a generic Error (not NotAllowedError) so it
tests the fallback-speaker path, which is now separate from the gesture
prompt path
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* docs: Add Playwright CT section to Claude.md and fix Speaker test count
- Claude.md: add Component Tests section with run commands, file→feature
mapping, and in-page mock control reference for debugging sessions
- TEST-PROGRESS.md: fix Speaker.ct.jsx count (4→6 after SPEAKER-004/006)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* docs: Add CLAUDE.md with project context and Playwright CT reference
Includes project structure, dev commands, Sentry/GitHub tool notes,
key conventions, and a Component Tests section with:
- Run commands for Playwright CT
- File→feature mapping for video-call tests
- In-page mock control reference for debugging sessions
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* handle tab losing focus
* save position to daily object
* chore: Reduce console log spam from audio/visibility monitoring
Removed noisy repeated logs:
- DEBUG overlay IIFE that logged on every render
- User gesture detection logs (fired on every click/keydown)
- Auto-resume check logs (fired every 5 seconds)
- Visibility focus/blur console logs (still stored to player state)
Kept important debug logs for weird states:
- AudioContext suspended on creation (warning)
- Page blurred while AudioContext suspended (warning, critical for #1187)
- AudioContext resumed successfully (confirmation)
- AudioContext resume failure (error)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Show stall prompt faster when page is unfocused during join
When Firefox suspends WebRTC due to unfocused tab, we now show the
"Video connection paused" prompt after 500ms instead of 5s:
- If page is already unfocused when join starts → prompt in 500ms
- If page blurs during join → prompt in 500ms from blur
- Fallback 5s timer remains for edge cases
Also removed verbose "Attempting join" log to reduce noise.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Delay AudioContext prompt to prevent modal flicker
Firefox often auto-resumes AudioContext shortly after page load when
the page is focused. Previously we would show the "enable audio" modal
immediately on suspension, causing it to flash and disappear.
Now we:
- Wait 800ms before showing prompt (if page is focused)
- Show immediately if page is unfocused (Firefox won't auto-resume)
- Cancel the delay if AudioContext resumes on its own
This prevents the modal from flickering when Firefox auto-resumes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Skip visibility tracking in tests and add AudioContext debug logs
- Skip blur/focus visibility tracking in component tests (detected via
window.mockPlayers) - fixes Playwright click timeouts
- Add AudioContext creation, state change, and auto-resume debug logs
- Update test mocks to provide AudioContext and document.hasFocus stubs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* ci: Add Playwright component tests workflow
Runs the 102 mocked VideoCall component tests on every push and PR.
Only installs chromium browser to keep CI fast.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Update ConditionalRender.jsx
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9194252 commit 0a758fb
76 files changed
Lines changed: 17020 additions & 186 deletions
File tree
- .github/workflows
- client
- src
- call
- components
- intro-exit/setup
- playwright
- component-tests
- debug
- video-call
- fixtures
- integration
- debug-components
- mocked
- helpers
- mocks
- playwright-report-integration
- test-results
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
28 | 70 | | |
29 | 71 | | |
30 | 72 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
19 | 17 | | |
20 | 18 | | |
21 | 19 | | |
| |||
39 | 37 | | |
40 | 38 | | |
41 | 39 | | |
| 40 | + | |
| 41 | + | |
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| 49 | + | |
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
54 | 55 | | |
55 | | - | |
| 56 | + | |
0 commit comments