|
| 1 | +--- |
| 2 | +id: mock-video-injection-web-automation-selenium-chromium |
| 3 | +title: Mock Video Injection on Web Automation (Selenium/Chromium) |
| 4 | +sidebar_label: Mock Video Injection |
| 5 | +description: Inject a custom video file as a fake camera feed in Chromium-based Selenium tests on TestMu AI for WebRTC, KYC, video conferencing, and getUserMedia-based workflows. |
| 6 | +tags: |
| 7 | + - how-to |
| 8 | + - web-automation |
| 9 | + - selenium |
| 10 | + - webrtc |
| 11 | + - video-injection |
| 12 | + - mock-camera |
| 13 | + - getUserMedia |
| 14 | +keywords: |
| 15 | + - mock video injection |
| 16 | + - selenium fake camera |
| 17 | + - chromium fake video capture |
| 18 | + - lambda:userFiles |
| 19 | + - getUserMedia selenium |
| 20 | + - webrtc automation testing |
| 21 | + - mock camera feed |
| 22 | +url: https://www.testmuai.com/support/docs/mock-video-injection-web-automation-selenium-chromium/ |
| 23 | +site_name: TestMu AI |
| 24 | +slug: mock-video-injection-web-automation-selenium-chromium/ |
| 25 | +canonical: https://www.testmuai.com/support/docs/mock-video-injection-web-automation-selenium-chromium/ |
| 26 | +--- |
| 27 | + |
| 28 | +import BrandName, { BRAND_URL } from '@site/src/component/BrandName'; |
| 29 | + |
| 30 | +<script type="application/ld+json" |
| 31 | + dangerouslySetInnerHTML={{ __html: JSON.stringify({ |
| 32 | + "@context": "https://schema.org", |
| 33 | + "@type": "BreadcrumbList", |
| 34 | + "itemListElement": [{ |
| 35 | + "@type": "ListItem", |
| 36 | + "position": 1, |
| 37 | + "name": "TestMu AI", |
| 38 | + "item": BRAND_URL |
| 39 | + },{ |
| 40 | + "@type": "ListItem", |
| 41 | + "position": 2, |
| 42 | + "name": "Support", |
| 43 | + "item": `${BRAND_URL}/support/docs/` |
| 44 | + },{ |
| 45 | + "@type": "ListItem", |
| 46 | + "position": 3, |
| 47 | + "name": "Mock Video Injection on Web Automation (Selenium/Chromium)", |
| 48 | + "item": `${BRAND_URL}/support/docs/mock-video-injection-web-automation-selenium-chromium/` |
| 49 | + }] |
| 50 | + }) |
| 51 | + }} |
| 52 | +></script> |
| 53 | + |
| 54 | +# Mock Video Injection on Web Automation (Selenium/Chromium) |
| 55 | + |
| 56 | +Inject a custom video file as a fake camera feed in Chromium-based Selenium tests on <BrandName />. This is useful for testing WebRTC, video conferencing, KYC or identity verification, and any flow that calls `getUserMedia()`. |
| 57 | + |
| 58 | +## How It Works |
| 59 | + |
| 60 | +1. Upload your `.mjpeg` or `.y4m` video file to <BrandName /> using the web automation user-files API. |
| 61 | +2. Pre-load the file onto the test VM using the `lambda:userFiles` capability. |
| 62 | +3. Pass Chrome flags to use the uploaded file as a fake camera device. |
| 63 | + |
| 64 | +Chrome treats the file as a looping camera feed, so any `getUserMedia({ video: true })` call receives frames from your file instead of a real camera. |
| 65 | + |
| 66 | +## Prerequisites |
| 67 | + |
| 68 | +- A <BrandName /> account with Web Automation access |
| 69 | +- A `.mjpeg` video file such as `sample_640x360.mjpeg` |
| 70 | + - Recommended resolution: `640x360` or `1280x720` |
| 71 | + - Chrome also supports `.y4m` (raw YUV4MPEG2) format |
| 72 | +- <BrandName /> credentials available as `LT_USERNAME` and `LT_ACCESS_KEY` |
| 73 | + |
| 74 | +## Step 1: Upload the Video File |
| 75 | + |
| 76 | +Upload your `.mjpeg` file using the web automation user-files API. |
| 77 | + |
| 78 | +### cURL |
| 79 | + |
| 80 | +```bash |
| 81 | +curl -X POST \ |
| 82 | + "https://api.lambdatest.com/automation/api/v1/user-files" \ |
| 83 | + -u "$LT_USERNAME:$LT_ACCESS_KEY" \ |
| 84 | + -F "files=@/path/to/sample_640x360.mjpeg" |
| 85 | +``` |
| 86 | + |
| 87 | +### Response |
| 88 | + |
| 89 | +```json |
| 90 | +{ |
| 91 | + "status": "success", |
| 92 | + "data": [ |
| 93 | + { |
| 94 | + "error": "", |
| 95 | + "message": "File have been uploaded successfully to our lambda storage", |
| 96 | + "key": "sample_640x360.mjpeg" |
| 97 | + } |
| 98 | + ] |
| 99 | +} |
| 100 | +``` |
| 101 | + |
| 102 | +:::note |
| 103 | +**Limits**: maximum 20 MB per upload and maximum 150 files per organization. |
| 104 | + |
| 105 | +The `/mfs/v1.0/media/upload` endpoint is for mobile and app automation. For web automation, use `/automation/api/v1/user-files`. |
| 106 | +::: |
| 107 | + |
| 108 | +## Step 2: Configure Selenium Capabilities |
| 109 | + |
| 110 | +### Java (Selenium 4, W3C) |
| 111 | + |
| 112 | +```java |
| 113 | +import org.openqa.selenium.chrome.ChromeOptions; |
| 114 | +import org.openqa.selenium.remote.RemoteWebDriver; |
| 115 | +import java.net.URL; |
| 116 | +import java.util.*; |
| 117 | + |
| 118 | +ChromeOptions options = new ChromeOptions(); |
| 119 | + |
| 120 | +options.addArguments( |
| 121 | + "--use-fake-ui-for-media-stream", |
| 122 | + "--use-fake-device-for-media-stream", |
| 123 | + "--use-file-for-fake-video-capture=/home/ltuser/Downloads/sample_640x360.mjpeg" |
| 124 | +); |
| 125 | + |
| 126 | +HashSet<String> userFiles = new HashSet<>(); |
| 127 | +userFiles.add("sample_640x360.mjpeg"); |
| 128 | + |
| 129 | +HashMap<String, Object> ltOptions = new HashMap<>(); |
| 130 | +ltOptions.put("platform", "Linux"); |
| 131 | +ltOptions.put("build", "Mock Video Injection Test"); |
| 132 | +ltOptions.put("name", "Fake Camera Feed Test"); |
| 133 | +ltOptions.put("video", true); |
| 134 | +ltOptions.put("w3c", true); |
| 135 | + |
| 136 | +options.setCapability("LT:Options", ltOptions); |
| 137 | +options.setCapability("lambda:userFiles", userFiles); |
| 138 | + |
| 139 | +RemoteWebDriver driver = new RemoteWebDriver( |
| 140 | + new URL("https://" + LT_USERNAME + ":" + LT_ACCESS_KEY + "@hub.lambdatest.com/wd/hub"), |
| 141 | + options |
| 142 | +); |
| 143 | +``` |
| 144 | + |
| 145 | +### Python |
| 146 | + |
| 147 | +```python |
| 148 | +from selenium import webdriver |
| 149 | + |
| 150 | +options = webdriver.ChromeOptions() |
| 151 | +options.add_argument("--use-fake-ui-for-media-stream") |
| 152 | +options.add_argument("--use-fake-device-for-media-stream") |
| 153 | +options.add_argument("--use-file-for-fake-video-capture=/home/ltuser/Downloads/sample_640x360.mjpeg") |
| 154 | + |
| 155 | +lt_options = { |
| 156 | + "platform": "Linux", |
| 157 | + "build": "Mock Video Injection Test", |
| 158 | + "name": "Fake Camera Feed Test", |
| 159 | + "video": True, |
| 160 | + "w3c": True, |
| 161 | +} |
| 162 | + |
| 163 | +options.set_capability("LT:Options", lt_options) |
| 164 | +options.set_capability("lambda:userFiles", ["sample_640x360.mjpeg"]) |
| 165 | + |
| 166 | +driver = webdriver.Remote( |
| 167 | + command_executor=f"https://{LT_USERNAME}:{LT_ACCESS_KEY}@hub.lambdatest.com/wd/hub", |
| 168 | + options=options, |
| 169 | +) |
| 170 | +``` |
| 171 | + |
| 172 | +### JavaScript (WebDriverIO or raw WebDriver) |
| 173 | + |
| 174 | +```javascript |
| 175 | +const capabilities = { |
| 176 | + browserName: "Chrome", |
| 177 | + browserVersion: "latest", |
| 178 | + platformName: "Linux", |
| 179 | + "LT:Options": { |
| 180 | + platform: "Linux", |
| 181 | + build: "Mock Video Injection Test", |
| 182 | + name: "Fake Camera Feed Test", |
| 183 | + video: true, |
| 184 | + w3c: true, |
| 185 | + }, |
| 186 | + "lambda:userFiles": ["sample_640x360.mjpeg"], |
| 187 | + "goog:chromeOptions": { |
| 188 | + args: [ |
| 189 | + "--use-fake-ui-for-media-stream", |
| 190 | + "--use-fake-device-for-media-stream", |
| 191 | + "--use-file-for-fake-video-capture=/home/ltuser/Downloads/sample_640x360.mjpeg", |
| 192 | + "--no-sandbox", |
| 193 | + "--disable-gpu", |
| 194 | + ], |
| 195 | + }, |
| 196 | +}; |
| 197 | +``` |
| 198 | + |
| 199 | +## Step 3: Verify the Video Feed in Your Test |
| 200 | + |
| 201 | +After the session starts, navigate to a page that requests camera access and confirm the fake stream is being used. |
| 202 | + |
| 203 | +```java |
| 204 | +driver.get("https://www.lambdatest.com/selenium-playground/webrtc-video"); |
| 205 | + |
| 206 | +// Or open your application's camera page |
| 207 | +driver.get("https://your-app.com/video-call"); |
| 208 | + |
| 209 | +Boolean isPlaying = (Boolean) driver.executeScript( |
| 210 | + "const video = document.querySelector('video');" + |
| 211 | + "return video && !video.paused && video.readyState >= 2;" |
| 212 | +); |
| 213 | +``` |
| 214 | + |
| 215 | +## File Paths by OS |
| 216 | + |
| 217 | +The `lambda:userFiles` capability places files in these directories: |
| 218 | + |
| 219 | +| Platform | File Path | |
| 220 | +|---|---| |
| 221 | +| Linux | `/home/ltuser/Downloads/sample_640x360.mjpeg` | |
| 222 | +| Windows | `C:\\Users\\ltuser\\Downloads\\sample_640x360.mjpeg` | |
| 223 | +| macOS | `/Users/ltuser/Downloads/sample_640x360.mjpeg` | |
| 224 | + |
| 225 | +Adjust the `--use-file-for-fake-video-capture` path to match your target platform. |
| 226 | + |
| 227 | +## Chrome Flags Reference |
| 228 | + |
| 229 | +| Flag | Purpose | |
| 230 | +|---|---| |
| 231 | +| `--use-fake-ui-for-media-stream` | Auto-grants `getUserMedia()` permission without a popup | |
| 232 | +| `--use-fake-device-for-media-stream` | Replaces real camera and microphone hardware with fake devices | |
| 233 | +| `--use-file-for-fake-video-capture=<path>` | Uses the specified file as the fake camera feed | |
| 234 | +| `--use-file-for-fake-audio-capture=<path>` | Uses the specified file as fake microphone input (`.wav` format) | |
| 235 | + |
| 236 | +## Platform Compatibility |
| 237 | + |
| 238 | +:::caution macOS limitation |
| 239 | +On **macOS**, `getUserMedia()` correctly returns a `MediaStream` with valid track label, resolution (`640x360`), and frame rate (`30fps`). However, Chrome on macOS does **not** decode MJPEG frames into the `<video>` element rendering pipeline. `readyState` stays at `0` and `videoWidth` / `videoHeight` remain `0`. |
| 240 | + |
| 241 | +Use **Linux** for mock video injection tests that require visual verification or canvas-based frame analysis. macOS is suitable only for API-level checks that validate stream properties without rendering frames. |
| 242 | +::: |
| 243 | + |
| 244 | +| Platform | getUserMedia | Track Label | Resolution | Frame Rate | Video Element Rendering | |
| 245 | +|---|---|---|---|---|---| |
| 246 | +| Linux (Ubuntu 20 / Chrome 145) | PASS | File-based | 640x360 | 30fps | PASS | |
| 247 | +| macOS (Sequoia / Chrome 145) | PASS | File-based | 640x360 | 30fps | FAIL (`readyState=0`) | |
| 248 | +| Windows | Untested | — | — | — | — | |
| 249 | + |
| 250 | +## Troubleshooting |
| 251 | + |
| 252 | +| Issue | Solution | |
| 253 | +|---|---| |
| 254 | +| Black or empty video feed | Verify the file name in `lambda:userFiles` matches exactly, including case | |
| 255 | +| Permission popup still appears | Confirm `--use-fake-ui-for-media-stream` is set | |
| 256 | +| File not found on VM | Check the OS-specific path; if needed, use `driver.executeScript("lambda-files-download=sample_640x360.mjpeg")` as a fallback | |
| 257 | +| Video not looping | Chrome loops `.mjpeg` files automatically; `.y4m` files also loop by default | |
| 258 | +| Wrong resolution | Use a file resolution that matches your app expectations; `640x360` is a safe default | |
| 259 | +| Windows path errors | Use escaped backslashes: `C:\\Users\\ltuser\\Downloads\\sample_640x360.mjpeg` | |
| 260 | +| macOS video does not render | This is a known Chrome limitation; use Linux when visual verification is required | |
| 261 | + |
| 262 | +## Creating an `.mjpeg` Test File |
| 263 | + |
| 264 | +If you do not already have an `.mjpeg` file, generate one with `ffmpeg`: |
| 265 | + |
| 266 | +```bash |
| 267 | +# Convert MP4 to MJPEG (640x360, 30fps, 10 seconds) |
| 268 | +ffmpeg -i input.mp4 -vf scale=640:360 -r 30 -t 10 -f mjpeg sample_640x360.mjpeg |
| 269 | + |
| 270 | +# Generate a synthetic color bars video |
| 271 | +ffmpeg -f lavfi -i "smptebars=duration=10:size=640x360:rate=30" -f mjpeg sample_640x360.mjpeg |
| 272 | +``` |
| 273 | + |
| 274 | +## Quick Validation Checklist |
| 275 | + |
| 276 | +- [ ] `.mjpeg` file uploaded using `/automation/api/v1/user-files` |
| 277 | +- [ ] `lambda:userFiles` includes the exact uploaded file name |
| 278 | +- [ ] `--use-fake-device-for-media-stream` is set |
| 279 | +- [ ] `--use-fake-ui-for-media-stream` is set |
| 280 | +- [ ] `--use-file-for-fake-video-capture` points to the correct OS path |
| 281 | +- [ ] The test navigates to a page that calls `getUserMedia()` |
| 282 | +- [ ] The video element is confirmed as playing (`readyState >= 2`) on Linux |
| 283 | + |
| 284 | +## Validation Notes |
| 285 | + |
| 286 | +This workflow was validated on: |
| 287 | + |
| 288 | +- **Linux (Ubuntu 20) + Chrome 145**: visual rendering and API-level validation both passed |
| 289 | +- **macOS (Sequoia) + Chrome 145**: API-level validation passed, but visual rendering did not |
| 290 | + |
| 291 | +Use Linux when your test needs visible camera frames inside the page or canvas pipeline. |
| 292 | + |
| 293 | +## Target Audience |
| 294 | + |
| 295 | +1. Developers building WebRTC or video features |
| 296 | +2. QA engineers testing camera-based workflows |
| 297 | +3. Customer support teams guiding customers through video injection setup |
0 commit comments