|
20 | 20 | 2. When muted during listening, chunks contain all zeros (silent audio) |
21 | 21 | 3. When unmuted, chunks contain real audio |
22 | 22 | 4. Mute resets to false when recording stops |
23 | | - 5. Uses useVoiceRecordingMuted hook for mute/unmute control |
| 23 | + 5. Stopping while muted does NOT re-acquire microphone (cleanup order test) |
| 24 | + 6. Uses useVoiceRecordingMuted hook for mute/unmute control |
24 | 25 | --> |
25 | 26 | <script type="module"> |
26 | 27 | import { setupMockMediaDevices } from '/assets/esm/speechToSpeech/mockMediaDevices.js'; |
|
52 | 53 | return bytes.every(byte => byte === 0); |
53 | 54 | } |
54 | 55 |
|
| 56 | + // Wrap getUserMedia to track call count for cleanup order test |
| 57 | + let getUserMediaCallCount = 0; |
| 58 | + const originalGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); |
| 59 | + navigator.mediaDevices.getUserMedia = (...args) => { |
| 60 | + getUserMediaCallCount++; |
| 61 | + return originalGetUserMedia(...args); |
| 62 | + }; |
| 63 | + |
55 | 64 | const audioChunks = []; |
56 | 65 | let currentVoiceState = 'idle'; |
57 | 66 | let currentMicrophoneMuted = false; |
|
204 | 213 | ); |
205 | 214 |
|
206 | 215 | expect(muteControlRef.muted).toBe(false); // microphoneMuted resets on stop |
| 216 | + |
| 217 | + // ===== TEST 8: Stopping while muted should NOT re-acquire microphone ===== |
| 218 | + // This test verifies the effect cleanup order in VoiceRecorderBridge: |
| 219 | + // Recording effect cleanup must run BEFORE mute effect cleanup. |
| 220 | + // Otherwise, unmute cleanup would call acquireAndConnectMediaStream(). |
| 221 | + |
| 222 | + // Start fresh recording |
| 223 | + await host.click(micButton); |
| 224 | + await pageConditions.became( |
| 225 | + 'Voice state is listening for cleanup test', |
| 226 | + () => getVoiceState() === 'listening', |
| 227 | + 2000 |
| 228 | + ); |
| 229 | + |
| 230 | + // Record the getUserMedia call count before mute |
| 231 | + const callCountBeforeMute = getUserMediaCallCount; |
| 232 | + |
| 233 | + // Mute (this will stop the MediaStream) |
| 234 | + muteControlRef.setMuted(true); |
| 235 | + await pageConditions.became( |
| 236 | + 'Muted for cleanup test', |
| 237 | + () => getMicrophoneMuted() === true, |
| 238 | + 1000 |
| 239 | + ); |
| 240 | + |
| 241 | + // Record call count after mute (should be same, mute stops mic but doesn't acquire) |
| 242 | + const callCountAfterMute = getUserMediaCallCount; |
| 243 | + expect(callCountAfterMute).toBe(callCountBeforeMute); |
| 244 | + |
| 245 | + // Stop recording while still muted |
| 246 | + await host.click(micButton); |
| 247 | + await pageConditions.became( |
| 248 | + 'Voice state is idle after stopping while muted', |
| 249 | + () => getVoiceState() === 'idle', |
| 250 | + 2000 |
| 251 | + ); |
| 252 | + |
| 253 | + // Wait a bit to ensure any erroneous async mic acquisition would have happened |
| 254 | + await new Promise(r => setTimeout(r, 300)); |
| 255 | + |
| 256 | + // Verify getUserMedia was NOT called again |
| 257 | + // If cleanup order was wrong, unmute would have called acquireAndConnectMediaStream() |
| 258 | + const callCountAfterStop = getUserMediaCallCount; |
| 259 | + expect(callCountAfterStop).toBe(callCountAfterMute); |
207 | 260 | }); |
208 | 261 | </script> |
209 | 262 | </body> |
|
0 commit comments