diff --git a/.github/workflows/fix-flakes-prompt.md b/.github/workflows/fix-flakes-prompt.md index ba43719927477..29acc7016bf0d 100644 --- a/.github/workflows/fix-flakes-prompt.md +++ b/.github/workflows/fix-flakes-prompt.md @@ -20,7 +20,8 @@ bots/PRs it disrupts — **not** by "has a tidy error message". Pick a candidate whose failing `bot_name` OS matches yours so you can reproduce it. Keep the ranked list — you fall back down it in step 2. Say why you picked the top one. Once you have the target, use the "Generate a linked emoji run history" recipe in -`.claude/skills/playwright-test-results/SKILL.md`. Keep the Markdown output for the PR body. +`.claude/skills/playwright-test-results/SKILL.md`. Include the complete output in the PR body: +never trim it or remove green runs, and check the square count matches the per-run row count. ## 2. Check nobody's on it — and that it isn't already fixed @@ -33,9 +34,8 @@ down your step-1 ranking, re-checking each; only stop once the whole shortlist i before a fix landed, so a test fixed mid-window looks maximally bimodal (old fails + new passes), which is exactly what floats it up step 1. Check whether a fix has landed since it last flaked: find the commit its most recent failing run ran on, and look at what's changed - in that test's file since. A commit that plausibly targets the test or its feature — a - browser roll, or a fix to the test or the code it exercises — means the remaining DB fails - are from before the fix, so move on. + in that test's file since. Only move on if enough subsequent runs show the failures stopped; + a browser roll alone is not evidence of a fix. ## 3. Reproduce on this OS @@ -59,15 +59,17 @@ are project-locked, so use the one matching the failing bot: Other suites (electron `etest`, etc.): see `package.json` scripts. Add `--repeat-each=N` to force a flake's flip. -**You can only reproduce what this OS reaches.** A failure you can't reach here is itself -evidence it's environment-specific — a skip candidate (step 6), not a blind-fix. -Keep any OS handling keyed on the *current* OS, never hardcoded. +**You can only reproduce what this OS and architecture reaches.** Match both from `bot_name`; +non-reproduction under lighter local load or on another architecture is not itself a skip candidate. +Keep any OS/architecture handling keyed on the *current* environment, never hardcoded. Broader OS coverage comes from different agent runs on other OSes, not from you. ## 4. Fix — root cause or scoped skip - **Tractable → fix the source.** Usually a test-side race: a missing `await`, waiting on the wrong signal, an under-specified locator, leaked state. Fix the test (or the product bug). +- **Timeout → check the budget before skipping.** Compare passing durations and neighboring tests; + if working tests share an expensive operation near the timeout, prefer a scoped `it.slow()`. - **Engine/OS-specific, unreachable here, or genuinely hard → scope a skip**, narrowed to the exact failing condition — never a whole file or browser: @@ -81,9 +83,9 @@ Broader OS coverage comes from different agent runs on other OSes, not from you. flake-fighter rarely is). Never `skip` just to turn a red green. **Verify locally — your PR gets no CI (step 6), so this is the only proof:** flake → re-run with -`--repeat-each` and confirm it's stable; skip → confirm it's skipped on the target config and -**still runs elsewhere**. Then run `npm run flint`. Record exactly what you ran — it goes in the -PR body. +`--repeat-each` and confirm it's stable; slow → confirm it still runs and passes; skip → confirm +it's skipped on the target config and **still runs elsewhere**. Then run `npm run flint`. Record +exactly what you ran — it goes in the PR body. ## 5. Pick a reviewer @@ -121,4 +123,4 @@ Report what you committed, the reviewer, and why. - **One target, one commit.** Don't batch. - **Scoped skips only** — narrow to the failing condition, never a whole file or browser matrix. -- **No unverified PRs** — if you couldn't run it locally, prefer a documented fixme. +- **No unverified PRs** — if you cannot validate a scoped mitigation, make no commit. diff --git a/.github/workflows/fix-flakes.yml b/.github/workflows/fix-flakes.yml index 346f7359378b4..c2fcb65e2d8fc 100644 --- a/.github/workflows/fix-flakes.yml +++ b/.github/workflows/fix-flakes.yml @@ -73,11 +73,12 @@ jobs: via the playwright-test-results skill. \`bot_name\` encodes the OS. Write your answer to output/runner.txt, and nothing else there: exactly one of these - six runner labels, or the single word \`none\` if no OS is worth a run. + seven runner labels, or the single word \`none\` if no platform is worth a run. ubuntu-22.04 ubuntu-22.04-arm ubuntu-24.04 - macos-14-xlarge macos-15-xlarge windows-latest - Map a candidate's \`bot_name\` to the closest of those (e.g. \`*-macos-15-*\` -> - macos-15-xlarge). Explain your reasoning briefly in your final message. + macos-14-xlarge macos-15-large macos-15-xlarge windows-latest + Map \`*-macos-15-large\` to \`macos-15-large\` and \`*-macos-15-xlarge\` to + \`macos-15-xlarge\`; never substitute one architecture for another. Explain your + reasoning briefly in your final message. ${HINT:+Focus hint from the operator: $HINT} EOF @@ -102,7 +103,7 @@ jobs: exit 0 fi case "$runner" in - ubuntu-22.04|ubuntu-22.04-arm|ubuntu-24.04|macos-14-xlarge|macos-15-xlarge|windows-latest) ;; + ubuntu-22.04|ubuntu-22.04-arm|ubuntu-24.04|macos-14-xlarge|macos-15-large|macos-15-xlarge|windows-latest) ;; *) echo "::error::Triage chose a non-allowlisted runner: '$runner'." >&2; exit 1 ;; esac echo "Triage chose runner: $runner" diff --git a/README.md b/README.md index b54a1bc7c4d10..f4f7c49c67cfb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 🎭 Playwright -[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) [![Chromium version](https://img.shields.io/badge/chromium-151.0.7922.19-blue.svg?logo=google-chrome)](https://www.chromium.org/Home) [![Firefox version](https://img.shields.io/badge/firefox-152.0.4-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/) [![WebKit version](https://img.shields.io/badge/webkit-26.5-blue.svg?logo=safari)](https://webkit.org/) [![Join Discord](https://img.shields.io/badge/join-discord-informational)](https://aka.ms/playwright/discord) +[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) [![Chromium version](https://img.shields.io/badge/chromium-151.0.7922.34-blue.svg?logo=google-chrome)](https://www.chromium.org/Home) [![Firefox version](https://img.shields.io/badge/firefox-152.0.4-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/) [![WebKit version](https://img.shields.io/badge/webkit-26.5-blue.svg?logo=safari)](https://webkit.org/) [![Join Discord](https://img.shields.io/badge/join-discord-informational)](https://aka.ms/playwright/discord) ## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright) @@ -296,7 +296,7 @@ The [Playwright VS Code extension](https://marketplace.visualstudio.com/items?it | | Linux | macOS | Windows | | :--- | :---: | :---: | :---: | -| Chromium1 151.0.7922.19 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Chromium1 151.0.7922.34 | :white_check_mark: | :white_check_mark: | :white_check_mark: | | WebKit 26.5 | :white_check_mark: | :white_check_mark: | :white_check_mark: | | Firefox 152.0.4 | :white_check_mark: | :white_check_mark: | :white_check_mark: | diff --git a/packages/isomorphic/deviceDescriptorsSource.json b/packages/isomorphic/deviceDescriptorsSource.json index 4a4842b428555..6204363f4f1f5 100644 --- a/packages/isomorphic/deviceDescriptorsSource.json +++ b/packages/isomorphic/deviceDescriptorsSource.json @@ -110,7 +110,7 @@ "defaultBrowserType": "webkit" }, "Galaxy S5": { - "userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 360, "height": 640 @@ -121,7 +121,7 @@ "defaultBrowserType": "chromium" }, "Galaxy S5 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 640, "height": 360 @@ -132,7 +132,7 @@ "defaultBrowserType": "chromium" }, "Galaxy S8": { - "userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 360, "height": 740 @@ -143,7 +143,7 @@ "defaultBrowserType": "chromium" }, "Galaxy S8 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 740, "height": 360 @@ -154,7 +154,7 @@ "defaultBrowserType": "chromium" }, "Galaxy S9+": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 320, "height": 658 @@ -165,7 +165,7 @@ "defaultBrowserType": "chromium" }, "Galaxy S9+ landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 658, "height": 320 @@ -176,7 +176,7 @@ "defaultBrowserType": "chromium" }, "Galaxy S24": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-S921U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-S921U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 360, "height": 780 @@ -187,7 +187,7 @@ "defaultBrowserType": "chromium" }, "Galaxy S24 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-S921U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-S921U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 780, "height": 360 @@ -198,7 +198,7 @@ "defaultBrowserType": "chromium" }, "Galaxy A55": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-A556B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-A556B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 480, "height": 1040 @@ -209,7 +209,7 @@ "defaultBrowserType": "chromium" }, "Galaxy A55 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-A556B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-A556B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 1040, "height": 480 @@ -220,7 +220,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Tab S4": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36", "viewport": { "width": 712, "height": 1138 @@ -231,7 +231,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Tab S4 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36", "viewport": { "width": 1138, "height": 712 @@ -242,7 +242,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Tab S9": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-X710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-X710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36", "viewport": { "width": 640, "height": 1024 @@ -253,7 +253,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Tab S9 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-X710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-X710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36", "viewport": { "width": 1024, "height": 640 @@ -264,7 +264,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Fold 6": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 928, "height": 1080 @@ -279,7 +279,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Fold 6 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 1080, "height": 928 @@ -294,7 +294,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Fold 6 Cover": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 484, "height": 1188 @@ -309,7 +309,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Fold 6 Cover landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 1188, "height": 484 @@ -324,7 +324,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Fold 7": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 984, "height": 1092 @@ -339,7 +339,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Fold 7 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 1092, "height": 984 @@ -354,7 +354,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Fold 7 Cover": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 360, "height": 840 @@ -369,7 +369,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Fold 7 Cover landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 840, "height": 360 @@ -384,7 +384,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Flip 6": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 360, "height": 880 @@ -399,7 +399,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Flip 6 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 880, "height": 360 @@ -414,7 +414,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Flip 6 Cover": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 360, "height": 374 @@ -429,7 +429,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Flip 6 Cover landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 374, "height": 360 @@ -444,7 +444,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Flip 7": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 360, "height": 840 @@ -459,7 +459,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Flip 7 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 840, "height": 360 @@ -474,7 +474,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Flip 7 Cover": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 474, "height": 524 @@ -489,7 +489,7 @@ "defaultBrowserType": "chromium" }, "Galaxy Z Flip 7 Cover landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 524, "height": 474 @@ -1748,7 +1748,7 @@ "defaultBrowserType": "webkit" }, "LG Optimus L70": { - "userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 384, "height": 640 @@ -1759,7 +1759,7 @@ "defaultBrowserType": "chromium" }, "LG Optimus L70 landscape": { - "userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 640, "height": 384 @@ -1770,7 +1770,7 @@ "defaultBrowserType": "chromium" }, "Microsoft Lumia 550": { - "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36 Edge/14.14263", + "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36 Edge/14.14263", "viewport": { "width": 360, "height": 640 @@ -1781,7 +1781,7 @@ "defaultBrowserType": "chromium" }, "Microsoft Lumia 550 landscape": { - "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36 Edge/14.14263", + "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36 Edge/14.14263", "viewport": { "width": 640, "height": 360 @@ -1792,7 +1792,7 @@ "defaultBrowserType": "chromium" }, "Microsoft Lumia 950": { - "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36 Edge/14.14263", + "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36 Edge/14.14263", "viewport": { "width": 360, "height": 640 @@ -1803,7 +1803,7 @@ "defaultBrowserType": "chromium" }, "Microsoft Lumia 950 landscape": { - "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36 Edge/14.14263", + "userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36 Edge/14.14263", "viewport": { "width": 640, "height": 360 @@ -1814,7 +1814,7 @@ "defaultBrowserType": "chromium" }, "Nexus 10": { - "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36", "viewport": { "width": 800, "height": 1280 @@ -1825,7 +1825,7 @@ "defaultBrowserType": "chromium" }, "Nexus 10 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36", "viewport": { "width": 1280, "height": 800 @@ -1836,7 +1836,7 @@ "defaultBrowserType": "chromium" }, "Nexus 4": { - "userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 384, "height": 640 @@ -1847,7 +1847,7 @@ "defaultBrowserType": "chromium" }, "Nexus 4 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 640, "height": 384 @@ -1858,7 +1858,7 @@ "defaultBrowserType": "chromium" }, "Nexus 5": { - "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 360, "height": 640 @@ -1869,7 +1869,7 @@ "defaultBrowserType": "chromium" }, "Nexus 5 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 640, "height": 360 @@ -1880,7 +1880,7 @@ "defaultBrowserType": "chromium" }, "Nexus 5X": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 412, "height": 732 @@ -1891,7 +1891,7 @@ "defaultBrowserType": "chromium" }, "Nexus 5X landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 732, "height": 412 @@ -1902,7 +1902,7 @@ "defaultBrowserType": "chromium" }, "Nexus 6": { - "userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 412, "height": 732 @@ -1913,7 +1913,7 @@ "defaultBrowserType": "chromium" }, "Nexus 6 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 732, "height": 412 @@ -1924,7 +1924,7 @@ "defaultBrowserType": "chromium" }, "Nexus 6P": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 412, "height": 732 @@ -1935,7 +1935,7 @@ "defaultBrowserType": "chromium" }, "Nexus 6P landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 732, "height": 412 @@ -1946,7 +1946,7 @@ "defaultBrowserType": "chromium" }, "Nexus 7": { - "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36", "viewport": { "width": 600, "height": 960 @@ -1957,7 +1957,7 @@ "defaultBrowserType": "chromium" }, "Nexus 7 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36", "viewport": { "width": 960, "height": 600 @@ -2012,7 +2012,7 @@ "defaultBrowserType": "webkit" }, "Pixel 2": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 411, "height": 731 @@ -2023,7 +2023,7 @@ "defaultBrowserType": "chromium" }, "Pixel 2 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 731, "height": 411 @@ -2034,7 +2034,7 @@ "defaultBrowserType": "chromium" }, "Pixel 2 XL": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 411, "height": 823 @@ -2045,7 +2045,7 @@ "defaultBrowserType": "chromium" }, "Pixel 2 XL landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 823, "height": 411 @@ -2056,7 +2056,7 @@ "defaultBrowserType": "chromium" }, "Pixel 3": { - "userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 393, "height": 786 @@ -2067,7 +2067,7 @@ "defaultBrowserType": "chromium" }, "Pixel 3 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 786, "height": 393 @@ -2078,7 +2078,7 @@ "defaultBrowserType": "chromium" }, "Pixel 4": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 353, "height": 745 @@ -2089,7 +2089,7 @@ "defaultBrowserType": "chromium" }, "Pixel 4 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 745, "height": 353 @@ -2100,7 +2100,7 @@ "defaultBrowserType": "chromium" }, "Pixel 4a (5G)": { - "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 412, "height": 892 @@ -2115,7 +2115,7 @@ "defaultBrowserType": "chromium" }, "Pixel 4a (5G) landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "height": 892, "width": 412 @@ -2130,7 +2130,7 @@ "defaultBrowserType": "chromium" }, "Pixel 5": { - "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 393, "height": 851 @@ -2145,7 +2145,7 @@ "defaultBrowserType": "chromium" }, "Pixel 5 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 851, "height": 393 @@ -2160,7 +2160,7 @@ "defaultBrowserType": "chromium" }, "Pixel 6": { - "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 412, "height": 915 @@ -2175,7 +2175,7 @@ "defaultBrowserType": "chromium" }, "Pixel 6 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 915, "height": 412 @@ -2190,7 +2190,7 @@ "defaultBrowserType": "chromium" }, "Pixel 6 Pro": { - "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 412, "height": 892 @@ -2205,7 +2205,7 @@ "defaultBrowserType": "chromium" }, "Pixel 6 Pro landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 892, "height": 412 @@ -2220,7 +2220,7 @@ "defaultBrowserType": "chromium" }, "Pixel 6a": { - "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 412, "height": 915 @@ -2235,7 +2235,7 @@ "defaultBrowserType": "chromium" }, "Pixel 6a landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 915, "height": 412 @@ -2250,7 +2250,7 @@ "defaultBrowserType": "chromium" }, "Pixel 7": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 412, "height": 915 @@ -2265,7 +2265,7 @@ "defaultBrowserType": "chromium" }, "Pixel 7 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 915, "height": 412 @@ -2280,7 +2280,7 @@ "defaultBrowserType": "chromium" }, "Pixel 7 Pro": { - "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 412, "height": 892 @@ -2295,7 +2295,7 @@ "defaultBrowserType": "chromium" }, "Pixel 7 Pro landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 892, "height": 412 @@ -2310,7 +2310,7 @@ "defaultBrowserType": "chromium" }, "Pixel 7a": { - "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 412, "height": 915 @@ -2325,7 +2325,7 @@ "defaultBrowserType": "chromium" }, "Pixel 7a landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 915, "height": 412 @@ -2340,7 +2340,7 @@ "defaultBrowserType": "chromium" }, "Pixel 8": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 412, "height": 915 @@ -2355,7 +2355,7 @@ "defaultBrowserType": "chromium" }, "Pixel 8 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 915, "height": 412 @@ -2370,7 +2370,7 @@ "defaultBrowserType": "chromium" }, "Pixel 8 Pro": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 448, "height": 997 @@ -2385,7 +2385,7 @@ "defaultBrowserType": "chromium" }, "Pixel 8 Pro landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 997, "height": 448 @@ -2400,7 +2400,7 @@ "defaultBrowserType": "chromium" }, "Pixel 8a": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 412, "height": 915 @@ -2415,7 +2415,7 @@ "defaultBrowserType": "chromium" }, "Pixel 8a landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 915, "height": 412 @@ -2430,7 +2430,7 @@ "defaultBrowserType": "chromium" }, "Pixel 9": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 360, "height": 808 @@ -2445,7 +2445,7 @@ "defaultBrowserType": "chromium" }, "Pixel 9 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 808, "height": 360 @@ -2460,7 +2460,7 @@ "defaultBrowserType": "chromium" }, "Pixel 9 Pro": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 427, "height": 952 @@ -2475,7 +2475,7 @@ "defaultBrowserType": "chromium" }, "Pixel 9 Pro landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 952, "height": 427 @@ -2490,7 +2490,7 @@ "defaultBrowserType": "chromium" }, "Pixel 9 Pro XL": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 448, "height": 997 @@ -2505,7 +2505,7 @@ "defaultBrowserType": "chromium" }, "Pixel 9 Pro XL landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 997, "height": 448 @@ -2520,7 +2520,7 @@ "defaultBrowserType": "chromium" }, "Pixel 10": { - "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 360, "height": 808 @@ -2535,7 +2535,7 @@ "defaultBrowserType": "chromium" }, "Pixel 10 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 808, "height": 360 @@ -2550,7 +2550,7 @@ "defaultBrowserType": "chromium" }, "Pixel 10 Pro": { - "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 427, "height": 952 @@ -2565,7 +2565,7 @@ "defaultBrowserType": "chromium" }, "Pixel 10 Pro landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 952, "height": 427 @@ -2580,7 +2580,7 @@ "defaultBrowserType": "chromium" }, "Pixel 10 Pro XL": { - "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 448, "height": 997 @@ -2595,7 +2595,7 @@ "defaultBrowserType": "chromium" }, "Pixel 10 Pro XL landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "screen": { "width": 997, "height": 448 @@ -2610,7 +2610,7 @@ "defaultBrowserType": "chromium" }, "Moto G4": { - "userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 360, "height": 640 @@ -2621,7 +2621,7 @@ "defaultBrowserType": "chromium" }, "Moto G4 landscape": { - "userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Mobile Safari/537.36", + "userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Mobile Safari/537.36", "viewport": { "width": 640, "height": 360 @@ -2632,7 +2632,7 @@ "defaultBrowserType": "chromium" }, "Desktop Chrome HiDPI": { - "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36", "screen": { "width": 1792, "height": 1120 @@ -2647,7 +2647,7 @@ "defaultBrowserType": "chromium" }, "Desktop Edge HiDPI": { - "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36 Edg/151.0.7922.19", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36 Edg/151.0.7922.34", "screen": { "width": 1792, "height": 1120 @@ -2692,7 +2692,7 @@ "defaultBrowserType": "webkit" }, "Desktop Chrome": { - "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36", "screen": { "width": 1920, "height": 1080 @@ -2707,7 +2707,7 @@ "defaultBrowserType": "chromium" }, "Desktop Edge": { - "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.19 Safari/537.36 Edg/151.0.7922.19", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36 Edg/151.0.7922.34", "screen": { "width": 1920, "height": 1080 diff --git a/packages/playwright-core/browsers.json b/packages/playwright-core/browsers.json index 56a2e6489fa17..78210dbd34ac9 100644 --- a/packages/playwright-core/browsers.json +++ b/packages/playwright-core/browsers.json @@ -3,16 +3,16 @@ "browsers": [ { "name": "chromium", - "revision": "1233", + "revision": "1234", "installByDefault": true, - "browserVersion": "151.0.7922.19", + "browserVersion": "151.0.7922.34", "title": "Chrome for Testing" }, { "name": "chromium-headless-shell", - "revision": "1233", + "revision": "1234", "installByDefault": true, - "browserVersion": "151.0.7922.19", + "browserVersion": "151.0.7922.34", "title": "Chrome Headless Shell" }, { @@ -45,7 +45,7 @@ }, { "name": "webkit", - "revision": "2331", + "revision": "2332", "installByDefault": true, "revisionOverrides": { "mac14": "2251", diff --git a/packages/playwright-core/src/server/bidi/bidiPage.ts b/packages/playwright-core/src/server/bidi/bidiPage.ts index b5347db1c0682..1d4a08b4701df 100644 --- a/packages/playwright-core/src/server/bidi/bidiPage.ts +++ b/packages/playwright-core/src/server/bidi/bidiPage.ts @@ -256,7 +256,9 @@ export class BidiPage implements PageDelegate { } private _onDownloadWillBegin(event: bidi.BrowsingContext.DownloadWillBeginParams) { - if (!event.navigation) + // TODO: remove the event.navigation fallback when Chrome supports event.download + // See https://github.com/GoogleChromeLabs/chromium-bidi/issues/4155 + if (!event.download && !event.navigation) return; this._page.frameManager.frameAbortedNavigation(event.context, 'Download is starting'); @@ -268,13 +270,15 @@ export class BidiPage implements PageDelegate { if (!originPage) return; - this._browserContext._browser.downloadCreated(originPage, event.navigation, event.url, event.suggestedFilename, event.suggestedFilename); + this._browserContext._browser.downloadCreated(originPage, event.download ?? event.navigation, event.url, event.suggestedFilename, event.suggestedFilename); } private _onDownloadEnded(event: bidi.BrowsingContext.DownloadEndParams) { - if (!event.navigation) + // TODO: remove the event.navigation fallback when Chrome supports event.download + // See https://github.com/GoogleChromeLabs/chromium-bidi/issues/4155 + if (!event.download && !event.navigation) return; - this._browserContext._browser.downloadFinished(event.navigation, event.status === 'canceled' ? 'canceled' : undefined); + this._browserContext._browser.downloadFinished(event.download ?? event.navigation, event.status === 'canceled' ? 'canceled' : undefined); } private _onLogEntryAdded(params: bidi.Log.Entry) { diff --git a/packages/playwright-core/src/server/bidi/third_party/bidiProtocolCore.ts b/packages/playwright-core/src/server/bidi/third_party/bidiProtocolCore.ts index e3b8b93250bf0..69413589d6e4c 100644 --- a/packages/playwright-core/src/server/bidi/third_party/bidiProtocolCore.ts +++ b/packages/playwright-core/src/server/bidi/third_party/bidiProtocolCore.ts @@ -1,5 +1,5 @@ /** - * Copyright 2024 Google LLC. + * Copyright 2026 Google LLC. * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -101,6 +101,7 @@ export const enum ErrorCode { NoSuchNetworkData = 'no such network data', NoSuchNode = 'no such node', NoSuchRequest = 'no such request', + NoSuchScreencast = 'no such screencast', NoSuchScript = 'no such script', NoSuchStoragePartition = 'no such storage partition', NoSuchUserContext = 'no such user context', @@ -473,7 +474,10 @@ export type BrowsingContextCommand = | BrowsingContext.Navigate | BrowsingContext.Print | BrowsingContext.Reload + | BrowsingContext.SetBypassCsp | BrowsingContext.SetViewport + | BrowsingContext.StartScreencast + | BrowsingContext.StopScreencast | BrowsingContext.TraverseHistory; export type BrowsingContextResult = | BrowsingContext.ActivateResult @@ -486,7 +490,10 @@ export type BrowsingContextResult = | BrowsingContext.NavigateResult | BrowsingContext.PrintResult | BrowsingContext.ReloadResult + | BrowsingContext.SetBypassCspResult | BrowsingContext.SetViewportResult + | BrowsingContext.StartScreencastResult + | BrowsingContext.StopScreencastResult | BrowsingContext.TraverseHistoryResult; export type BrowsingContextEvent = | BrowsingContext.ContextCreated @@ -569,12 +576,16 @@ export namespace BrowsingContext { export namespace BrowsingContext { export type Navigation = string; } +export namespace BrowsingContext { + export type Download = string; +} export namespace BrowsingContext { export type BaseNavigationInfo = { context: BrowsingContext.BrowsingContext; navigation: BrowsingContext.Navigation | null; timestamp: JsUint; url: string; + userContext?: Browser.UserContext; }; } export namespace BrowsingContext { @@ -704,6 +715,7 @@ export namespace BrowsingContext { export namespace BrowsingContext { export type CreateResult = { context: BrowsingContext.BrowsingContext; + userContext?: Browser.UserContext; }; } export namespace BrowsingContext { @@ -878,6 +890,25 @@ export namespace BrowsingContext { export namespace BrowsingContext { export type ReloadResult = BrowsingContext.NavigateResult; } +export namespace BrowsingContext { + export type SetBypassCsp = { + method: 'browsingContext.setBypassCSP'; + params: BrowsingContext.SetBypassCspParameters; + }; +} +export namespace BrowsingContext { + export type SetBypassCspParameters = { + bypass: true | null; + contexts?: [ + BrowsingContext.BrowsingContext, + ...BrowsingContext.BrowsingContext[], + ]; + userContexts?: [Browser.UserContext, ...Browser.UserContext[]]; + }; +} +export namespace BrowsingContext { + export type SetBypassCspResult = EmptyResult; +} export namespace BrowsingContext { export type SetViewport = { method: 'browsingContext.setViewport'; @@ -904,6 +935,56 @@ export namespace BrowsingContext { export namespace BrowsingContext { export type SetViewportResult = EmptyResult; } +export namespace BrowsingContext { + export type StartScreencast = { + method: 'browsingContext.startScreencast'; + params: BrowsingContext.StartScreencastParameters; + }; +} +export namespace BrowsingContext { + export type StartScreencastParameters = { + context: BrowsingContext.BrowsingContext; + mimeType?: string; + video?: BrowsingContext.MediaTrackConstraints; + /** + * @defaultValue `false` + */ + audio?: boolean; + }; +} +export namespace BrowsingContext { + export type MediaTrackConstraints = { + width?: JsUint; + height?: JsUint; + frameRate?: JsUint; + }; +} +export namespace BrowsingContext { + export type StartScreencastResult = { + screencast: BrowsingContext.Screencast; + path: string; + }; +} +export namespace BrowsingContext { + export type Screencast = string; +} +export namespace BrowsingContext { + export type StopScreencast = { + method: 'browsingContext.stopScreencast'; + params: BrowsingContext.StopScreencastParameters; + }; +} +export namespace BrowsingContext { + export type StopScreencastParameters = { + screencast: BrowsingContext.Screencast; + }; +} +export namespace BrowsingContext { + export type StopScreencastResult = { + path: string; + error?: string; + }; +} export namespace BrowsingContext { export type TraverseHistory = { method: 'browsingContext.traverseHistory'; @@ -954,6 +1035,7 @@ export namespace BrowsingContext { context: BrowsingContext.BrowsingContext; timestamp: JsUint; url: string; + userContext?: Browser.UserContext; }; } export namespace BrowsingContext { @@ -976,6 +1058,7 @@ export namespace BrowsingContext { } export namespace BrowsingContext { export type DownloadWillBeginParams = { + download: BrowsingContext.Download; suggestedFilename: string; } & BrowsingContext.BaseNavigationInfo; } @@ -993,11 +1076,13 @@ export namespace BrowsingContext { export namespace BrowsingContext { export type DownloadCanceledParams = { status: 'canceled'; + download: BrowsingContext.Download; } & BrowsingContext.BaseNavigationInfo; } export namespace BrowsingContext { export type DownloadCompleteParams = { status: 'complete'; + download: BrowsingContext.Download; filepath: string | null; } & BrowsingContext.BaseNavigationInfo; } @@ -1030,6 +1115,7 @@ export namespace BrowsingContext { context: BrowsingContext.BrowsingContext; accepted: boolean; type: BrowsingContext.UserPromptType; + userContext?: Browser.UserContext; userText?: string; }; } @@ -1045,6 +1131,7 @@ export namespace BrowsingContext { handler: Session.UserPromptHandlerType; message: string; type: BrowsingContext.UserPromptType; + userContext?: Browser.UserContext; defaultValue?: string; }; } @@ -1054,8 +1141,11 @@ export type EmulationCommand = | Emulation.SetLocaleOverride | Emulation.SetNetworkConditions | Emulation.SetScreenOrientationOverride + | Emulation.SetScreenSettingsOverride | Emulation.SetScriptingEnabled + | Emulation.SetScrollbarTypeOverride | Emulation.SetTimezoneOverride + | Emulation.SetTouchOverride | Emulation.SetUserAgentOverride; export type EmulationResult = | Emulation.SetForcedColorsModeThemeOverrideResult @@ -1063,7 +1153,9 @@ export type EmulationResult = | Emulation.SetLocaleOverrideResult | Emulation.SetScreenOrientationOverrideResult | Emulation.SetScriptingEnabledResult + | Emulation.SetScrollbarTypeOverrideResult | Emulation.SetTimezoneOverrideResult + | Emulation.SetTouchOverrideResult | Emulation.SetUserAgentOverrideResult; export namespace Emulation { export type SetForcedColorsModeThemeOverride = { @@ -1307,6 +1399,25 @@ export namespace Emulation { export namespace Emulation { export type SetScriptingEnabledResult = EmptyResult; } +export namespace Emulation { + export type SetScrollbarTypeOverride = { + method: 'emulation.setScrollbarTypeOverride'; + params: Emulation.SetScrollbarTypeOverrideParameters; + }; +} +export namespace Emulation { + export type SetScrollbarTypeOverrideParameters = { + scrollbarType: 'classic' | 'overlay' | null; + contexts?: [ + BrowsingContext.BrowsingContext, + ...BrowsingContext.BrowsingContext[], + ]; + userContexts?: [Browser.UserContext, ...Browser.UserContext[]]; + }; +} +export namespace Emulation { + export type SetScrollbarTypeOverrideResult = EmptyResult; +} export namespace Emulation { export type SetTimezoneOverride = { method: 'emulation.setTimezoneOverride'; @@ -1326,6 +1437,28 @@ export namespace Emulation { export namespace Emulation { export type SetTimezoneOverrideResult = EmptyResult; } +export namespace Emulation { + export type SetTouchOverride = { + method: 'emulation.setTouchOverride'; + params: Emulation.SetTouchOverrideParameters; + }; +} +export namespace Emulation { + export type SetTouchOverrideParameters = { + /** + * Must be greater than or equal to `1`. + */ + maxTouchPoints: JsUint | null; + contexts?: [ + BrowsingContext.BrowsingContext, + ...BrowsingContext.BrowsingContext[], + ]; + userContexts?: [Browser.UserContext, ...Browser.UserContext[]]; + }; +} +export namespace Emulation { + export type SetTouchOverrideResult = EmptyResult; +} export type NetworkCommand = | Network.AddDataCollector | Network.AddIntercept @@ -1381,6 +1514,7 @@ export namespace Network { redirectCount: JsUint; request: Network.RequestData; timestamp: JsUint; + userContext?: Browser.UserContext | null; intercepts?: [Network.Intercept, ...Network.Intercept[]]; }; } @@ -2059,6 +2193,7 @@ export namespace Script { export type WindowRealmInfo = Script.BaseRealmInfo & { type: 'window'; context: BrowsingContext.BrowsingContext; + userContext?: Browser.UserContext; sandbox?: string; }; } @@ -2367,6 +2502,7 @@ export namespace Script { export type Source = { realm: Script.Realm; context?: BrowsingContext.BrowsingContext; + userContext?: Browser.UserContext; }; } export namespace Script { @@ -2833,38 +2969,26 @@ export namespace Input { } export namespace Input { export type PointerCommonProperties = { - /** - * @defaultValue `1` - */ width?: JsUint; - /** - * @defaultValue `1` - */ height?: JsUint; /** - * @defaultValue `0` + * Must be between `0` and `1`, inclusive. */ pressure?: number; /** - * @defaultValue `0` + * Must be between `-1` and `1`, inclusive. */ tangentialPressure?: number; /** * Must be between `0` and `359`, inclusive. - * - * @defaultValue `0` */ twist?: number; /** * Must be between `0` and `1.5707963267948966`, inclusive. - * - * @defaultValue `0` */ altitudeAngle?: number; /** * Must be between `0` and `6.283185307179586`, inclusive. - * - * @defaultValue `0` */ azimuthAngle?: number; }; @@ -2914,6 +3038,7 @@ export namespace Input { export namespace Input { export type FileDialogInfo = { context: BrowsingContext.BrowsingContext; + userContext?: Browser.UserContext; element?: Script.SharedReference; multiple: boolean; }; diff --git a/packages/playwright-core/src/server/fetch.ts b/packages/playwright-core/src/server/fetch.ts index e9c1fbc1ba137..e5778afb760a6 100644 --- a/packages/playwright-core/src/server/fetch.ts +++ b/packages/playwright-core/src/server/fetch.ts @@ -476,8 +476,7 @@ export abstract class APIRequestContext extends SdkObject { return; } - if (headers['host']) - headers['host'] = locationURL.host; + setHeader(headers, 'host', locationURL.host); // Drop credentials scoped to the original origin on cross-origin redirects. if (locationURL.origin !== url.origin) diff --git a/packages/playwright-core/src/server/webkit/wkPage.ts b/packages/playwright-core/src/server/webkit/wkPage.ts index ef084aed771e6..5258751640416 100644 --- a/packages/playwright-core/src/server/webkit/wkPage.ts +++ b/packages/playwright-core/src/server/webkit/wkPage.ts @@ -1242,6 +1242,8 @@ export class WKPage implements PageDelegate { ['notifications', 'notifications'], ['clipboard-read', 'clipboard-read'], ['screen-wake-lock', 'screen-wake-lock'], + ['camera', 'camera'], + ['microphone', 'microphone'], ]); const filtered = permissions.map(permission => { const protocolPermission = webPermissionToProtocol.get(permission); diff --git a/tests/bidi/expectations/moz-firefox-nightly-library.txt b/tests/bidi/expectations/moz-firefox-nightly-library.txt index e13c5d5e1441c..d2848e3d27954 100644 --- a/tests/bidi/expectations/moz-firefox-nightly-library.txt +++ b/tests/bidi/expectations/moz-firefox-nightly-library.txt @@ -101,7 +101,6 @@ library/defaultbrowsercontext-2.spec.ts › should support hasTouch option [fail library/defaultbrowsercontext-2.spec.ts › should support reducedMotion option [fail] library/defaultbrowsercontext-2.spec.ts › should work in persistent context [fail] library/download.spec.ts › download event › should be able to cancel pending downloads [timeout] -library/download.spec.ts › download event › should report download path within page.on('download', …) handler for Blobs [timeout] library/download.spec.ts › download event › should report new window downloads [timeout] library/download.spec.ts › download event › should throw if browser dies [fail] library/emulation-focus.spec.ts › should focus popups by default [fail] diff --git a/tests/library/browsercontext-fetch.spec.ts b/tests/library/browsercontext-fetch.spec.ts index 46831e62ca49e..54f219d2cd0c6 100644 --- a/tests/library/browsercontext-fetch.spec.ts +++ b/tests/library/browsercontext-fetch.spec.ts @@ -1436,7 +1436,7 @@ it('should update host header on redirect', async ({ context, server }) => { }); const reqPromise = server.waitForRequest('/test'); const response = await context.request.get(server.PREFIX + '/redirect', { - headers: { host: new URL(server.PREFIX).host } + headers: { HosT: new URL(server.PREFIX).host } }); expect(redirectCount).toBe(2); await expect(response).toBeOK(); diff --git a/tests/library/defaultbrowsercontext-2.spec.ts b/tests/library/defaultbrowsercontext-2.spec.ts index 823ad6492769a..f0eb64bd80db2 100644 --- a/tests/library/defaultbrowsercontext-2.spec.ts +++ b/tests/library/defaultbrowsercontext-2.spec.ts @@ -20,6 +20,7 @@ import fs from 'fs'; import path from 'path'; it.skip(({ mode }) => mode !== 'default', 'Remote persistent contexts are not supported'); +it.slow(({ browserName, isMac }) => browserName === 'firefox' && isMac && process.arch === 'x64', 'Persistent Firefox launches are slow on Intel macOS runners under load.'); it('should support hasTouch option', async ({ server, launchPersistent }) => { const { page } = await launchPersistent({ hasTouch: true }); diff --git a/tests/library/permissions.spec.ts b/tests/library/permissions.spec.ts index 846d502f03021..e880797b53452 100644 --- a/tests/library/permissions.spec.ts +++ b/tests/library/permissions.spec.ts @@ -322,3 +322,76 @@ it('can request screen-wake-lock', { await page.goto('https://example.com'); await page.evaluate(() => navigator.wakeLock.request('screen')); }); + +it.describe('camera and microphone', () => { + // WebKit exposes deterministic mock capture devices; capture is gated on the + // 'camera'/'microphone' permissions. Chromium needs --use-fake-device-for-media-stream + // and Firefox has no camera/microphone permission mapping, so scope to WebKit. + it.skip(({ browserName }) => browserName !== 'webkit', 'WebKit mock-capture-device based test'); + // Native Windows WebKit is built without a media-capture backend, so getUserMedia is + // unavailable there; WSL runs the Linux build, which does have mock capture. + it.skip(({ isWindows, channel }) => isWindows && channel !== 'webkit-wsl', 'WebKit has no media capture on Windows'); + + async function getUserMedia(page, constraints) { + return await page.evaluate(async constraints => { + try { + const stream = await navigator.mediaDevices.getUserMedia(constraints); + const tracks = stream.getTracks().map(track => ({ kind: track.kind, live: track.readyState === 'live' })); + stream.getTracks().forEach(track => track.stop()); + tracks.sort((a, b) => a.kind.localeCompare(b.kind)); + return { tracks }; + } catch (error) { + return { error: error.name }; + } + }, constraints); + } + + it('should capture when camera and microphone are granted', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/2973' } + }, async ({ page, context, server, isFrozenWebkit }) => { + it.skip(isFrozenWebkit, 'Mock capture device support requires a newer WebKit build'); + + await context.grantPermissions(['camera', 'microphone'], { origin: server.PREFIX }); + await page.goto(server.EMPTY_PAGE); + expect(await getUserMedia(page, { video: true, audio: true })).toEqual({ + tracks: [ + { kind: 'audio', live: true }, + { kind: 'video', live: true }, + ], + }); + }); + + it('should reject when no permission is granted', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/2973' } + }, async ({ page, server, isFrozenWebkit }) => { + it.skip(isFrozenWebkit, 'Mock capture device support requires a newer WebKit build'); + + await page.goto(server.EMPTY_PAGE); + expect(await getUserMedia(page, { video: true, audio: true })).toEqual({ error: 'NotAllowedError' }); + }); + + it('should gate audio and video independently', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/2973' } + }, async ({ page, context, server, isFrozenWebkit }) => { + it.skip(isFrozenWebkit, 'Mock capture device support requires a newer WebKit build'); + + await context.grantPermissions(['camera'], { origin: server.PREFIX }); + await page.goto(server.EMPTY_PAGE); + // Camera-only request is allowed. + expect(await getUserMedia(page, { video: true })).toEqual({ tracks: [{ kind: 'video', live: true }] }); + // Microphone request is rejected because it was not granted. + expect(await getUserMedia(page, { audio: true })).toEqual({ error: 'NotAllowedError' }); + }); + + it('should stop capturing after permissions are cleared', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/2973' } + }, async ({ page, context, server, isFrozenWebkit }) => { + it.skip(isFrozenWebkit, 'Mock capture device support requires a newer WebKit build'); + + await context.grantPermissions(['camera'], { origin: server.PREFIX }); + await page.goto(server.EMPTY_PAGE); + expect(await getUserMedia(page, { video: true })).toEqual({ tracks: [{ kind: 'video', live: true }] }); + await context.clearPermissions(); + expect(await getUserMedia(page, { video: true })).toEqual({ error: 'NotAllowedError' }); + }); +});