A camera web app can be driven in automation by returning canvas and oscillator streams from getUserMedia
Fact
Replacing navigator.mediaDevices.getUserMedia in the page with a function that resolves to canvas.captureStream(fps) gives the app a live video track it cannot tell apart from a camera. Whatever the test draws on that canvas (a code, a document, a moving scene) arrives through the app's real <video>, frame grabbing and processing path. For the microphone, an OscillatorNode connected to AudioContext.createMediaStreamDestination() gives a live audio track with a steady level. No browser flags, device, or permission prompt are involved.
Why it matters
Automation browsers, embedded panes and CI machines usually have no camera, and flags like Chrome's --use-fake-device-for-media-stream cannot be passed to a browser the test does not launch. The camera path then goes untested, and it is where the lifecycle bugs live: stale paused frames, overlays mapped through object-fit: cover, restarts after the tab is hidden. Where the flag can be passed, its fake microphone can still hang the page's capture queue: [[get-user-media-requests-run-one-at-a-time]].
How to apply
- Install the override before the app calls
getUserMedia, and keep redrawing the canvas (a timer, notrequestAnimationFrame, so a hidden surface still produces frames). A canvas that stops changing stops producing new frames. - Change the drawing mid-test to exercise "scan again" and repeated-result logic. Solid colours make the far end checkable by sampling one pixel.
- An
AudioContextcreated without a user gesture may start suspended and emit silence: resume it, or launch with--autoplay-policy=no-user-gesture-required. - The fake track has no
facingMode, andgetCapabilities()reports no torch or zoom. Test those branches separately.