diff --git a/.github/workflows/create_test_report.yml b/.github/workflows/create_test_report.yml
index ddf32c64b17d2..7850e4f1c07b1 100644
--- a/.github/workflows/create_test_report.yml
+++ b/.github/workflows/create_test_report.yml
@@ -10,10 +10,11 @@ jobs:
pull-requests: write
checks: write
statuses: write
- id-token: write # This is required for OIDC login (azure/login) to succeed
contents: read # This is required for actions/checkout to succeed
if: ${{ github.event.workflow_run.event == 'pull_request' || github.event.workflow_run.event == 'push' }}
runs-on: ubuntu-latest
+ env:
+ MARKDOWN_OUTPUT_FILE: ${{ github.workspace }}/report.md
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
@@ -32,28 +33,48 @@ jobs:
run: |
npx playwright merge-reports --config .github/workflows/merge.config.ts ./all-blob-reports
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_OPTIONS: --max-old-space-size=8192
- HTML_REPORT_URL: 'https://mspwblobreport.z1.web.core.windows.net/run-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}-${{ github.sha }}/index.html'
WORKFLOW_RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
- - name: Azure Login
- uses: azure/login@v3
+ - name: Upload HTML report
+ id: upload-report
+ uses: actions/upload-artifact@v7
with:
- client-id: ${{ secrets.AZURE_BLOB_REPORTS_CLIENT_ID }}
- tenant-id: ${{ secrets.AZURE_BLOB_REPORTS_TENANT_ID }}
- subscription-id: ${{ secrets.AZURE_BLOB_REPORTS_SUBSCRIPTION_ID }}
+ path: playwright-report/index.html
+ archive: false # Upload as a single, browser-openable file (no zip)
+ retention-days: 30
- - name: Upload HTML report to Azure
- id: upload-report
+ # The triggering workflow ran on a pull_request event, but workflow_run.pull_requests is
+ # empty for PRs from forks, so resolve the number from the head repo + branch instead.
+ - name: Resolve PR number
+ if: ${{ github.event.workflow_run.event == 'pull_request' }}
+ id: pr
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- REPORT_DIR='run-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}-${{ github.sha }}'
- azcopy cp --recursive "./playwright-report/*" "https://mspwblobreport.blob.core.windows.net/\$web/$REPORT_DIR"
- REPORT_URL="https://mspwblobreport.z1.web.core.windows.net/$REPORT_DIR/index.html"
- echo "Report url: $REPORT_URL"
- echo "reportUrl=$REPORT_URL" >> "$GITHUB_OUTPUT"
+ NUMBER=$(gh pr view --repo "${{ github.repository }}" \
+ "${{ github.event.workflow_run.head_repository.owner.login }}:${{ github.event.workflow_run.head_branch }}" \
+ --json number --jq '.number' 2>/dev/null || true)
+ echo "number=$NUMBER" >> "$GITHUB_OUTPUT"
+
+ - name: Post report comment to PR
+ if: ${{ steps.pr.outputs.number }}
+ uses: actions/github-script@v8
env:
- AZCOPY_AUTO_LOGIN_TYPE: AZCLI
+ HTML_REPORT_URL: ${{ steps.upload-report.outputs.artifact-url }}
+ PR_NUMBER: ${{ steps.pr.outputs.number }}
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const { postReportComment } = require('./tests/config/postReportComment');
+ await postReportComment({
+ github,
+ context,
+ core,
+ reportFile: process.env.MARKDOWN_OUTPUT_FILE,
+ prNumber: +process.env.PR_NUMBER,
+ reportUrl: process.env.HTML_REPORT_URL,
+ });
- name: Publish Report URL as Commit Status
uses: actions/github-script@v9
@@ -64,6 +85,6 @@ jobs:
repo: context.repo.repo,
sha: '${{ github.event.workflow_run.head_sha }}',
state: 'success',
- target_url: '${{ steps.upload-report.outputs.reportUrl }}',
+ target_url: '${{ steps.upload-report.outputs.artifact-url }}',
context: 'HTML Report (${{ github.event.workflow_run.name }})',
});
diff --git a/.github/workflows/merge.config.ts b/.github/workflows/merge.config.ts
index 222b728f7c134..5d4588b2a4a52 100644
--- a/.github/workflows/merge.config.ts
+++ b/.github/workflows/merge.config.ts
@@ -1,4 +1,4 @@
export default {
testDir: '../../tests',
- reporter: [[require.resolve('../../tests/config/ghaMarkdownReporter')], ['html']]
-};
\ No newline at end of file
+ reporter: [[require.resolve('../../tests/config/markdownReporter')], ['html']],
+};
diff --git a/README.md b/README.md
index e17f0f357cded..f94183a0c9cd9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# 🎠Playwright
-[](https://www.npmjs.com/package/playwright) [](https://www.chromium.org/Home) [](https://www.mozilla.org/en-US/firefox/new/) [](https://webkit.org/) [](https://aka.ms/playwright/discord)
+[](https://www.npmjs.com/package/playwright) [](https://www.chromium.org/Home) [](https://www.mozilla.org/en-US/firefox/new/) [](https://webkit.org/) [](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 150.0.7871.24 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Chromium1 150.0.7871.46 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit 26.5 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox 151.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
diff --git a/packages/injected/src/injectedScript.ts b/packages/injected/src/injectedScript.ts
index 6c265ae8ff9dc..17af70020bee0 100644
--- a/packages/injected/src/injectedScript.ts
+++ b/packages/injected/src/injectedScript.ts
@@ -43,20 +43,9 @@ import type { SelectorEngine, SelectorRoot } from './selectorEngine';
import type { GenerateSelectorOptions } from './selectorGenerator';
import type { ElementText, TextMatcher } from './selectorUtils';
import type { Builtins } from './utilityScript';
+import type { ExpectedTextValue, Point, Rect } from '@protocol/structs';
-type ExpectedTextValue = {
- string?: string,
- regexSource?: string,
- regexFlags?: string,
- matchSubstring?: boolean,
- ignoreCase?: boolean,
- normalizeWhiteSpace?: boolean,
-};
-
-type Point = { x: number, y: number };
-type Rect = Point & { width: number, height: number };
-
export type FrameExpectParams = {
selector?: string,
expression: string,
diff --git a/packages/injected/src/storageScript.ts b/packages/injected/src/storageScript.ts
index 13ec974c011e7..2583b2c3c3e63 100644
--- a/packages/injected/src/storageScript.ts
+++ b/packages/injected/src/storageScript.ts
@@ -16,42 +16,9 @@
import { parseEvaluationResultValue, serializeAsCallArgument } from '@isomorphic/utilityScriptSerializers';
-type NameValue = { name: string, value: string };
-
-type IndexedDBDatabase = {
- name: string,
- version: number,
- stores: {
- name: string,
- autoIncrement: boolean,
- keyPath?: string,
- keyPathArray?: string[],
- records: {
- key?: any,
- keyEncoded?: any,
- value?: any,
- valueEncoded?: any,
- }[],
- indexes: {
- name: string,
- keyPath?: string,
- keyPathArray?: string[],
- multiEntry: boolean,
- unique: boolean,
- }[],
- }[],
-};
-
-type SetOriginStorage = {
- origin: string,
- localStorage: NameValue[],
- indexedDB?: IndexedDBDatabase[],
-};
-
-export type SerializedStorage = {
- localStorage: NameValue[],
- indexedDB?: IndexedDBDatabase[],
-};
+import type { IndexedDBDatabase, OriginStorage, SetOriginStorage } from '@protocol/structs';
+
+export type SerializedStorage = Omit;
export class StorageScript {
private _isFirefox: boolean;
diff --git a/packages/isomorphic/trace/traceUtils.ts b/packages/isomorphic/trace/traceUtils.ts
index aa11c397aca4f..9873a63950f7b 100644
--- a/packages/isomorphic/trace/traceUtils.ts
+++ b/packages/isomorphic/trace/traceUtils.ts
@@ -15,11 +15,7 @@
*/
import type { StackFrame } from '../stackTrace';
-
-type ClientSideCallMetadata = {
- id: number,
- stack?: StackFrame[],
-};
+import type { ClientSideCallMetadata } from '@protocol/structs';
export type SerializedStackFrame = [number, number, number, string];
export type SerializedStack = [number, SerializedStackFrame[]];
diff --git a/packages/playwright-core/browsers.json b/packages/playwright-core/browsers.json
index 8235994ac505c..5261809f8319b 100644
--- a/packages/playwright-core/browsers.json
+++ b/packages/playwright-core/browsers.json
@@ -3,16 +3,16 @@
"browsers": [
{
"name": "chromium",
- "revision": "1229",
+ "revision": "1231",
"installByDefault": true,
- "browserVersion": "150.0.7871.24",
+ "browserVersion": "150.0.7871.46",
"title": "Chrome for Testing"
},
{
"name": "chromium-headless-shell",
- "revision": "1229",
+ "revision": "1231",
"installByDefault": true,
- "browserVersion": "150.0.7871.24",
+ "browserVersion": "150.0.7871.46",
"title": "Chrome Headless Shell"
},
{
diff --git a/packages/playwright-core/src/client/channels.d.ts b/packages/playwright-core/src/client/channels.d.ts
index c66c5f2b5f249..d797efe34ae34 100644
--- a/packages/playwright-core/src/client/channels.d.ts
+++ b/packages/playwright-core/src/client/channels.d.ts
@@ -15,10 +15,8 @@
*/
// This file is generated by generate_channels.js, do not edit manually.
-export type Binary = Buffer;
-
-export interface Channel {
-}
+import type { Binary, Channel, AndroidWebView, AndroidSelector, AndroidElementInfo, APIResponse, Metadata, ClientSideCallMetadata, SDKLanguage, WaitInfo, SetNetworkCookie, NetworkCookie, ResourceTiming, SecurityDetails, RequestSizes, RemoteAddr, ExpectedTextValue, SelectorEngine, FormField, LifecycleEvent, ConsoleMessagesFilter, RecorderSource, IndexedDBDatabase, SetOriginStorage, OriginStorage, RecordHarOptions, SerializedValue, SerializedArgument, SerializedError, StackFrame, VirtualCredential, Point, Rect, URLPattern, NameValue } from '@protocol/structs';
+export type { Binary, Channel, AndroidWebView, AndroidSelector, AndroidElementInfo, APIResponse, Metadata, ClientSideCallMetadata, SDKLanguage, WaitInfo, SetNetworkCookie, NetworkCookie, ResourceTiming, SecurityDetails, RequestSizes, RemoteAddr, ExpectedTextValue, SelectorEngine, FormField, LifecycleEvent, ConsoleMessagesFilter, RecorderSource, IndexedDBDatabase, SetOriginStorage, OriginStorage, RecordHarOptions, SerializedValue, SerializedArgument, SerializedError, StackFrame, VirtualCredential, Point, Rect, URLPattern, NameValue } from '@protocol/structs';
// ----------- Initializer Traits -----------
export type InitializerTraits =
@@ -584,56 +582,6 @@ export interface AndroidDeviceEvents {
'webViewRemoved': AndroidDeviceWebViewRemovedEvent;
}
-export type AndroidWebView = {
- pid: number,
- pkg: string,
- socketName: string,
-};
-
-export type AndroidSelector = {
- checkable?: boolean,
- checked?: boolean,
- clazz?: string,
- clickable?: boolean,
- depth?: number,
- desc?: string,
- enabled?: boolean,
- focusable?: boolean,
- focused?: boolean,
- hasChild?: {
- androidSelector: AndroidSelector,
- },
- hasDescendant?: {
- androidSelector: AndroidSelector,
- maxDepth?: number,
- },
- longClickable?: boolean,
- pkg?: string,
- res?: string,
- scrollable?: boolean,
- selected?: boolean,
- text?: string,
-};
-
-export type AndroidElementInfo = {
- children?: AndroidElementInfo[],
- clazz: string,
- desc: string,
- res: string,
- pkg: string,
- text: string,
- bounds: Rect,
- checkable: boolean,
- checked: boolean,
- clickable: boolean,
- enabled: boolean,
- focusable: boolean,
- focused: boolean,
- longClickable: boolean,
- scrollable: boolean,
- selected: boolean,
-};
-
// ----------- APIRequestContext -----------
export type APIRequestContextInitializer = {
tracing: TracingChannel,
@@ -728,16 +676,6 @@ export type APIRequestContextDisposeResult = void;
export interface APIRequestContextEvents {
}
-export type APIResponse = {
- fetchUid: string,
- url: string,
- status: number,
- statusText: string,
- headers: NameValue[],
- securityDetails?: SecurityDetails,
- serverAddr?: RemoteAddr,
-};
-
// ----------- Artifact -----------
export type ArtifactInitializer = {
absolutePath: string,
@@ -2092,23 +2030,6 @@ export type BrowserTypeConnectToWorkerResult = {
export interface BrowserTypeEvents {
}
-export type Metadata = {
- location?: {
- file: string,
- line?: number,
- column?: number,
- },
- title?: string,
- internal?: boolean,
- stepId?: string,
-};
-
-export type ClientSideCallMetadata = {
- id: number,
- stack?: StackFrame[],
-};
-
-export type SDKLanguage = 'javascript' | 'python' | 'java' | 'csharp';
// ----------- Disposable -----------
export type DisposableInitializer = {};
export interface DisposableEventTarget {
@@ -2124,14 +2045,6 @@ export type DisposableDisposeResult = void;
export interface DisposableEvents {
}
-export type WaitInfo = {
- waitId: string,
- phase: 'before' | 'after' | 'log',
- event?: string,
- message?: string,
- error?: string,
-};
-
// ----------- Electron -----------
export type ElectronInitializer = {};
export interface ElectronEventTarget {
@@ -3713,33 +3626,6 @@ export type LocalUtilsGlobToRegexResult = {
export interface LocalUtilsEvents {
}
-export type SetNetworkCookie = {
- name: string,
- value: string,
- url?: string,
- domain?: string,
- path?: string,
- expires?: number,
- httpOnly?: boolean,
- secure?: boolean,
- sameSite?: 'Strict' | 'Lax' | 'None',
- partitionKey?: string,
- _crHasCrossSiteAncestor?: boolean,
-};
-
-export type NetworkCookie = {
- name: string,
- value: string,
- domain: string,
- path: string,
- expires: number,
- httpOnly: boolean,
- secure: boolean,
- sameSite: 'Strict' | 'Lax' | 'None',
- partitionKey?: string,
- _crHasCrossSiteAncestor?: boolean,
-};
-
// ----------- Request -----------
export type RequestInitializer = {
frame?: FrameChannel,
@@ -3921,17 +3807,6 @@ export interface WebSocketRouteEvents {
'closeServer': WebSocketRouteCloseServerEvent;
}
-export type ResourceTiming = {
- startTime: number,
- domainLookupStart: number,
- domainLookupEnd: number,
- connectStart: number,
- secureConnectionStart: number,
- connectEnd: number,
- requestStart: number,
- responseStart: number,
-};
-
// ----------- Response -----------
export type ResponseInitializer = {
request: RequestChannel,
@@ -3987,26 +3862,6 @@ export type ResponseSizesResult = {
export interface ResponseEvents {
}
-export type SecurityDetails = {
- issuer?: string,
- protocol?: string,
- subjectName?: string,
- validFrom?: number,
- validTo?: number,
-};
-
-export type RequestSizes = {
- requestBodySize: number,
- requestHeadersSize: number,
- responseBodySize: number,
- responseHeadersSize: number,
-};
-
-export type RemoteAddr = {
- ipAddress: string,
- port: number,
-};
-
// ----------- WebSocket -----------
export type WebSocketInitializer = {
url: string,
@@ -5110,93 +4965,6 @@ export interface JsonPipeEvents {
'closed': JsonPipeClosedEvent;
}
-export type ExpectedTextValue = {
- string?: string,
- regexSource?: string,
- regexFlags?: string,
- matchSubstring?: boolean,
- ignoreCase?: boolean,
- normalizeWhiteSpace?: boolean,
-};
-
-export type SelectorEngine = {
- name: string,
- source: string,
- contentScript?: boolean,
-};
-
-export type FormField = {
- name: string,
- value?: string,
- file?: {
- name: string,
- mimeType?: string,
- buffer: Binary,
- },
-};
-
-export type LifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle' | 'commit';
-export type ConsoleMessagesFilter = 'all' | 'since-navigation';
-export type RecorderSource = {
- isRecorded: boolean,
- id: string,
- label: string,
- text: string,
- language: string,
- highlight: {
- line: number,
- type: string,
- }[],
- revealLine?: number,
- group?: string,
-};
-
-export type IndexedDBDatabase = {
- name: string,
- version: number,
- stores: {
- name: string,
- autoIncrement: boolean,
- keyPath?: string,
- keyPathArray?: string[],
- records: {
- key?: any,
- keyEncoded?: any,
- value?: any,
- valueEncoded?: any,
- }[],
- indexes: {
- name: string,
- keyPath?: string,
- keyPathArray?: string[],
- multiEntry: boolean,
- unique: boolean,
- }[],
- }[],
-};
-
-export type SetOriginStorage = {
- origin: string,
- localStorage: NameValue[],
- indexedDB?: IndexedDBDatabase[],
-};
-
-export type OriginStorage = {
- origin: string,
- localStorage: NameValue[],
- indexedDB?: IndexedDBDatabase[],
-};
-
-export type RecordHarOptions = {
- content?: 'embed' | 'attach' | 'omit',
- mode?: 'full' | 'minimal',
- urlGlob?: string,
- urlRegexSource?: string,
- urlRegexFlags?: string,
- harPath?: string,
- resourcesDir?: string,
-};
-
// ----------- CDPSession -----------
export type CDPSessionInitializer = {};
export interface CDPSessionEventTarget {
@@ -5339,94 +5107,6 @@ export type DialogDismissResult = void;
export interface DialogEvents {
}
-export type SerializedValue = {
- n?: number,
- b?: boolean,
- s?: string,
- v?: 'null' | 'undefined' | 'NaN' | 'Infinity' | '-Infinity' | '-0',
- d?: string,
- u?: string,
- bi?: string,
- ta?: {
- b: Binary,
- k: 'i8' | 'ui8' | 'ui8c' | 'i16' | 'ui16' | 'i32' | 'ui32' | 'f32' | 'f64' | 'bi64' | 'bui64',
- },
- e?: {
- m: string,
- n: string,
- s: string,
- },
- r?: {
- p: string,
- f: string,
- },
- a?: SerializedValue[],
- o?: {
- k: string,
- v: SerializedValue,
- }[],
- h?: number,
- id?: number,
- ref?: number,
-};
-
-export type SerializedArgument = {
- value: SerializedValue,
- handles: Channel[],
-};
-
-export type SerializedError = {
- error?: {
- message: string,
- name: string,
- stack?: string,
- },
- value?: SerializedValue,
-};
-
-export type StackFrame = {
- file: string,
- line: number,
- column: number,
- function?: string,
-};
-
-export type VirtualCredential = {
- id: string,
- rpId: string,
- userHandle: string,
- privateKey: string,
- publicKey: string,
-};
-
-export type Point = {
- x: number,
- y: number,
-};
-
-export type Rect = {
- x: number,
- y: number,
- width: number,
- height: number,
-};
-
-export type URLPattern = {
- hash: string,
- hostname: string,
- password: string,
- pathname: string,
- port: string,
- protocol: string,
- search: string,
- username: string,
-};
-
-export type NameValue = {
- name: string,
- value: string,
-};
-
// ----------- Tracing -----------
export type TracingInitializer = {};
export interface TracingEventTarget {
diff --git a/packages/playwright-core/src/protocol/serializers.ts b/packages/playwright-core/src/protocol/serializers.ts
index ccf795af15987..020421c646381 100644
--- a/packages/playwright-core/src/protocol/serializers.ts
+++ b/packages/playwright-core/src/protocol/serializers.ts
@@ -14,36 +14,7 @@
* limitations under the License.
*/
-export type SerializedValue = {
- n?: number,
- b?: boolean,
- s?: string,
- v?: 'null' | 'undefined' | 'NaN' | 'Infinity' | '-Infinity' | '-0',
- d?: string,
- u?: string,
- bi?: string,
- ta?: {
- b: Buffer,
- k: 'i8' | 'ui8' | 'ui8c' | 'i16' | 'ui16' | 'i32' | 'ui32' | 'f32' | 'f64' | 'bi64' | 'bui64',
- },
- e?: {
- m: string,
- n: string,
- s: string,
- },
- r?: {
- p: string,
- f: string,
- },
- a?: SerializedValue[],
- o?: {
- k: string,
- v: SerializedValue,
- }[],
- h?: number,
- id?: number,
- ref?: number,
-};
+import type { SerializedValue } from '@protocol/structs';
export function parseSerializedValue(value: SerializedValue, handles: any[] | undefined): any {
return innerParseSerializedValue(value, handles, new Map(), []);
diff --git a/packages/playwright-core/src/server/channels.d.ts b/packages/playwright-core/src/server/channels.d.ts
index 153920cac69b2..a28946f3b63a1 100644
--- a/packages/playwright-core/src/server/channels.d.ts
+++ b/packages/playwright-core/src/server/channels.d.ts
@@ -18,10 +18,8 @@
import type { Progress } from './progress';
-export type Binary = Buffer;
-
-export interface Channel {
-}
+import type { Binary, Channel, AndroidWebView, AndroidSelector, AndroidElementInfo, APIResponse, Metadata, ClientSideCallMetadata, SDKLanguage, WaitInfo, SetNetworkCookie, NetworkCookie, ResourceTiming, SecurityDetails, RequestSizes, RemoteAddr, ExpectedTextValue, SelectorEngine, FormField, LifecycleEvent, ConsoleMessagesFilter, RecorderSource, IndexedDBDatabase, SetOriginStorage, OriginStorage, RecordHarOptions, SerializedValue, SerializedArgument, SerializedError, StackFrame, VirtualCredential, Point, Rect, URLPattern, NameValue } from '@protocol/structs';
+export type { Binary, Channel, AndroidWebView, AndroidSelector, AndroidElementInfo, APIResponse, Metadata, ClientSideCallMetadata, SDKLanguage, WaitInfo, SetNetworkCookie, NetworkCookie, ResourceTiming, SecurityDetails, RequestSizes, RemoteAddr, ExpectedTextValue, SelectorEngine, FormField, LifecycleEvent, ConsoleMessagesFilter, RecorderSource, IndexedDBDatabase, SetOriginStorage, OriginStorage, RecordHarOptions, SerializedValue, SerializedArgument, SerializedError, StackFrame, VirtualCredential, Point, Rect, URLPattern, NameValue } from '@protocol/structs';
// ----------- Initializer Traits -----------
export type InitializerTraits =
@@ -587,56 +585,6 @@ export interface AndroidDeviceEvents {
'webViewRemoved': AndroidDeviceWebViewRemovedEvent;
}
-export type AndroidWebView = {
- pid: number,
- pkg: string,
- socketName: string,
-};
-
-export type AndroidSelector = {
- checkable?: boolean,
- checked?: boolean,
- clazz?: string,
- clickable?: boolean,
- depth?: number,
- desc?: string,
- enabled?: boolean,
- focusable?: boolean,
- focused?: boolean,
- hasChild?: {
- androidSelector: AndroidSelector,
- },
- hasDescendant?: {
- androidSelector: AndroidSelector,
- maxDepth?: number,
- },
- longClickable?: boolean,
- pkg?: string,
- res?: string,
- scrollable?: boolean,
- selected?: boolean,
- text?: string,
-};
-
-export type AndroidElementInfo = {
- children?: AndroidElementInfo[],
- clazz: string,
- desc: string,
- res: string,
- pkg: string,
- text: string,
- bounds: Rect,
- checkable: boolean,
- checked: boolean,
- clickable: boolean,
- enabled: boolean,
- focusable: boolean,
- focused: boolean,
- longClickable: boolean,
- scrollable: boolean,
- selected: boolean,
-};
-
// ----------- APIRequestContext -----------
export type APIRequestContextInitializer = {
tracing: TracingChannel,
@@ -731,16 +679,6 @@ export type APIRequestContextDisposeResult = void;
export interface APIRequestContextEvents {
}
-export type APIResponse = {
- fetchUid: string,
- url: string,
- status: number,
- statusText: string,
- headers: NameValue[],
- securityDetails?: SecurityDetails,
- serverAddr?: RemoteAddr,
-};
-
// ----------- Artifact -----------
export type ArtifactInitializer = {
absolutePath: string,
@@ -2095,23 +2033,6 @@ export type BrowserTypeConnectToWorkerResult = {
export interface BrowserTypeEvents {
}
-export type Metadata = {
- location?: {
- file: string,
- line?: number,
- column?: number,
- },
- title?: string,
- internal?: boolean,
- stepId?: string,
-};
-
-export type ClientSideCallMetadata = {
- id: number,
- stack?: StackFrame[],
-};
-
-export type SDKLanguage = 'javascript' | 'python' | 'java' | 'csharp';
// ----------- Disposable -----------
export type DisposableInitializer = {};
export interface DisposableEventTarget {
@@ -2127,14 +2048,6 @@ export type DisposableDisposeResult = void;
export interface DisposableEvents {
}
-export type WaitInfo = {
- waitId: string,
- phase: 'before' | 'after' | 'log',
- event?: string,
- message?: string,
- error?: string,
-};
-
// ----------- Electron -----------
export type ElectronInitializer = {};
export interface ElectronEventTarget {
@@ -3716,33 +3629,6 @@ export type LocalUtilsGlobToRegexResult = {
export interface LocalUtilsEvents {
}
-export type SetNetworkCookie = {
- name: string,
- value: string,
- url?: string,
- domain?: string,
- path?: string,
- expires?: number,
- httpOnly?: boolean,
- secure?: boolean,
- sameSite?: 'Strict' | 'Lax' | 'None',
- partitionKey?: string,
- _crHasCrossSiteAncestor?: boolean,
-};
-
-export type NetworkCookie = {
- name: string,
- value: string,
- domain: string,
- path: string,
- expires: number,
- httpOnly: boolean,
- secure: boolean,
- sameSite: 'Strict' | 'Lax' | 'None',
- partitionKey?: string,
- _crHasCrossSiteAncestor?: boolean,
-};
-
// ----------- Request -----------
export type RequestInitializer = {
frame?: FrameChannel,
@@ -3924,17 +3810,6 @@ export interface WebSocketRouteEvents {
'closeServer': WebSocketRouteCloseServerEvent;
}
-export type ResourceTiming = {
- startTime: number,
- domainLookupStart: number,
- domainLookupEnd: number,
- connectStart: number,
- secureConnectionStart: number,
- connectEnd: number,
- requestStart: number,
- responseStart: number,
-};
-
// ----------- Response -----------
export type ResponseInitializer = {
request: RequestChannel,
@@ -3990,26 +3865,6 @@ export type ResponseSizesResult = {
export interface ResponseEvents {
}
-export type SecurityDetails = {
- issuer?: string,
- protocol?: string,
- subjectName?: string,
- validFrom?: number,
- validTo?: number,
-};
-
-export type RequestSizes = {
- requestBodySize: number,
- requestHeadersSize: number,
- responseBodySize: number,
- responseHeadersSize: number,
-};
-
-export type RemoteAddr = {
- ipAddress: string,
- port: number,
-};
-
// ----------- WebSocket -----------
export type WebSocketInitializer = {
url: string,
@@ -5113,93 +4968,6 @@ export interface JsonPipeEvents {
'closed': JsonPipeClosedEvent;
}
-export type ExpectedTextValue = {
- string?: string,
- regexSource?: string,
- regexFlags?: string,
- matchSubstring?: boolean,
- ignoreCase?: boolean,
- normalizeWhiteSpace?: boolean,
-};
-
-export type SelectorEngine = {
- name: string,
- source: string,
- contentScript?: boolean,
-};
-
-export type FormField = {
- name: string,
- value?: string,
- file?: {
- name: string,
- mimeType?: string,
- buffer: Binary,
- },
-};
-
-export type LifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle' | 'commit';
-export type ConsoleMessagesFilter = 'all' | 'since-navigation';
-export type RecorderSource = {
- isRecorded: boolean,
- id: string,
- label: string,
- text: string,
- language: string,
- highlight: {
- line: number,
- type: string,
- }[],
- revealLine?: number,
- group?: string,
-};
-
-export type IndexedDBDatabase = {
- name: string,
- version: number,
- stores: {
- name: string,
- autoIncrement: boolean,
- keyPath?: string,
- keyPathArray?: string[],
- records: {
- key?: any,
- keyEncoded?: any,
- value?: any,
- valueEncoded?: any,
- }[],
- indexes: {
- name: string,
- keyPath?: string,
- keyPathArray?: string[],
- multiEntry: boolean,
- unique: boolean,
- }[],
- }[],
-};
-
-export type SetOriginStorage = {
- origin: string,
- localStorage: NameValue[],
- indexedDB?: IndexedDBDatabase[],
-};
-
-export type OriginStorage = {
- origin: string,
- localStorage: NameValue[],
- indexedDB?: IndexedDBDatabase[],
-};
-
-export type RecordHarOptions = {
- content?: 'embed' | 'attach' | 'omit',
- mode?: 'full' | 'minimal',
- urlGlob?: string,
- urlRegexSource?: string,
- urlRegexFlags?: string,
- harPath?: string,
- resourcesDir?: string,
-};
-
// ----------- CDPSession -----------
export type CDPSessionInitializer = {};
export interface CDPSessionEventTarget {
@@ -5342,94 +5110,6 @@ export type DialogDismissResult = void;
export interface DialogEvents {
}
-export type SerializedValue = {
- n?: number,
- b?: boolean,
- s?: string,
- v?: 'null' | 'undefined' | 'NaN' | 'Infinity' | '-Infinity' | '-0',
- d?: string,
- u?: string,
- bi?: string,
- ta?: {
- b: Binary,
- k: 'i8' | 'ui8' | 'ui8c' | 'i16' | 'ui16' | 'i32' | 'ui32' | 'f32' | 'f64' | 'bi64' | 'bui64',
- },
- e?: {
- m: string,
- n: string,
- s: string,
- },
- r?: {
- p: string,
- f: string,
- },
- a?: SerializedValue[],
- o?: {
- k: string,
- v: SerializedValue,
- }[],
- h?: number,
- id?: number,
- ref?: number,
-};
-
-export type SerializedArgument = {
- value: SerializedValue,
- handles: Channel[],
-};
-
-export type SerializedError = {
- error?: {
- message: string,
- name: string,
- stack?: string,
- },
- value?: SerializedValue,
-};
-
-export type StackFrame = {
- file: string,
- line: number,
- column: number,
- function?: string,
-};
-
-export type VirtualCredential = {
- id: string,
- rpId: string,
- userHandle: string,
- privateKey: string,
- publicKey: string,
-};
-
-export type Point = {
- x: number,
- y: number,
-};
-
-export type Rect = {
- x: number,
- y: number,
- width: number,
- height: number,
-};
-
-export type URLPattern = {
- hash: string,
- hostname: string,
- password: string,
- pathname: string,
- port: string,
- protocol: string,
- search: string,
- username: string,
-};
-
-export type NameValue = {
- name: string,
- value: string,
-};
-
// ----------- Tracing -----------
export type TracingInitializer = {};
export interface TracingEventTarget {
diff --git a/packages/playwright-core/src/server/deviceDescriptorsSource.json b/packages/playwright-core/src/server/deviceDescriptorsSource.json
index 1a3787c1379ce..7af8c4d97220e 100644
--- a/packages/playwright-core/src/server/deviceDescriptorsSource.json
+++ b/packages/playwright-core/src/server/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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-S921U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-S921U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-A556B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-A556B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-X710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; SM-X710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F956U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F966U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F741U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; SM-F761U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 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/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 12; Pixel 6a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 13; Pixel 7a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 8a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 14; Pixel 9 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 16; Pixel 10 Pro XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Mobile Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Safari/537.36 Edg/150.0.7871.24",
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 Safari/537.36 Edg/150.0.7871.46",
"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/150.0.7871.24 Safari/537.36",
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 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/150.0.7871.24 Safari/537.36 Edg/150.0.7871.24",
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.7871.46 Safari/537.36 Edg/150.0.7871.46",
"screen": {
"width": 1920,
"height": 1080
diff --git a/packages/protocol/src/structs.d.ts b/packages/protocol/src/structs.d.ts
new file mode 100644
index 0000000000000..a44c990626d31
--- /dev/null
+++ b/packages/protocol/src/structs.d.ts
@@ -0,0 +1,344 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file is generated by generate_channels.js, do not edit manually.
+
+export type Binary = Buffer;
+
+export interface Channel {
+}
+
+export type AndroidWebView = {
+ pid: number,
+ pkg: string,
+ socketName: string,
+};
+
+export type AndroidSelector = {
+ checkable?: boolean,
+ checked?: boolean,
+ clazz?: string,
+ clickable?: boolean,
+ depth?: number,
+ desc?: string,
+ enabled?: boolean,
+ focusable?: boolean,
+ focused?: boolean,
+ hasChild?: {
+ androidSelector: AndroidSelector,
+ },
+ hasDescendant?: {
+ androidSelector: AndroidSelector,
+ maxDepth?: number,
+ },
+ longClickable?: boolean,
+ pkg?: string,
+ res?: string,
+ scrollable?: boolean,
+ selected?: boolean,
+ text?: string,
+};
+
+export type AndroidElementInfo = {
+ children?: AndroidElementInfo[],
+ clazz: string,
+ desc: string,
+ res: string,
+ pkg: string,
+ text: string,
+ bounds: Rect,
+ checkable: boolean,
+ checked: boolean,
+ clickable: boolean,
+ enabled: boolean,
+ focusable: boolean,
+ focused: boolean,
+ longClickable: boolean,
+ scrollable: boolean,
+ selected: boolean,
+};
+
+export type APIResponse = {
+ fetchUid: string,
+ url: string,
+ status: number,
+ statusText: string,
+ headers: NameValue[],
+ securityDetails?: SecurityDetails,
+ serverAddr?: RemoteAddr,
+};
+
+export type Metadata = {
+ location?: {
+ file: string,
+ line?: number,
+ column?: number,
+ },
+ title?: string,
+ internal?: boolean,
+ stepId?: string,
+};
+
+export type ClientSideCallMetadata = {
+ id: number,
+ stack?: StackFrame[],
+};
+
+export type SDKLanguage = 'javascript' | 'python' | 'java' | 'csharp';
+
+export type WaitInfo = {
+ waitId: string,
+ phase: 'before' | 'after' | 'log',
+ event?: string,
+ message?: string,
+ error?: string,
+};
+
+export type SetNetworkCookie = {
+ name: string,
+ value: string,
+ url?: string,
+ domain?: string,
+ path?: string,
+ expires?: number,
+ httpOnly?: boolean,
+ secure?: boolean,
+ sameSite?: 'Strict' | 'Lax' | 'None',
+ partitionKey?: string,
+ _crHasCrossSiteAncestor?: boolean,
+};
+
+export type NetworkCookie = {
+ name: string,
+ value: string,
+ domain: string,
+ path: string,
+ expires: number,
+ httpOnly: boolean,
+ secure: boolean,
+ sameSite: 'Strict' | 'Lax' | 'None',
+ partitionKey?: string,
+ _crHasCrossSiteAncestor?: boolean,
+};
+
+export type ResourceTiming = {
+ startTime: number,
+ domainLookupStart: number,
+ domainLookupEnd: number,
+ connectStart: number,
+ secureConnectionStart: number,
+ connectEnd: number,
+ requestStart: number,
+ responseStart: number,
+};
+
+export type SecurityDetails = {
+ issuer?: string,
+ protocol?: string,
+ subjectName?: string,
+ validFrom?: number,
+ validTo?: number,
+};
+
+export type RequestSizes = {
+ requestBodySize: number,
+ requestHeadersSize: number,
+ responseBodySize: number,
+ responseHeadersSize: number,
+};
+
+export type RemoteAddr = {
+ ipAddress: string,
+ port: number,
+};
+
+export type ExpectedTextValue = {
+ string?: string,
+ regexSource?: string,
+ regexFlags?: string,
+ matchSubstring?: boolean,
+ ignoreCase?: boolean,
+ normalizeWhiteSpace?: boolean,
+};
+
+export type SelectorEngine = {
+ name: string,
+ source: string,
+ contentScript?: boolean,
+};
+
+export type FormField = {
+ name: string,
+ value?: string,
+ file?: {
+ name: string,
+ mimeType?: string,
+ buffer: Binary,
+ },
+};
+
+export type LifecycleEvent = 'load' | 'domcontentloaded' | 'networkidle' | 'commit';
+
+export type ConsoleMessagesFilter = 'all' | 'since-navigation';
+
+export type RecorderSource = {
+ isRecorded: boolean,
+ id: string,
+ label: string,
+ text: string,
+ language: string,
+ highlight: {
+ line: number,
+ type: string,
+ }[],
+ revealLine?: number,
+ group?: string,
+};
+
+export type IndexedDBDatabase = {
+ name: string,
+ version: number,
+ stores: {
+ name: string,
+ autoIncrement: boolean,
+ keyPath?: string,
+ keyPathArray?: string[],
+ records: {
+ key?: any,
+ keyEncoded?: any,
+ value?: any,
+ valueEncoded?: any,
+ }[],
+ indexes: {
+ name: string,
+ keyPath?: string,
+ keyPathArray?: string[],
+ multiEntry: boolean,
+ unique: boolean,
+ }[],
+ }[],
+};
+
+export type SetOriginStorage = {
+ origin: string,
+ localStorage: NameValue[],
+ indexedDB?: IndexedDBDatabase[],
+};
+
+export type OriginStorage = {
+ origin: string,
+ localStorage: NameValue[],
+ indexedDB?: IndexedDBDatabase[],
+};
+
+export type RecordHarOptions = {
+ content?: 'embed' | 'attach' | 'omit',
+ mode?: 'full' | 'minimal',
+ urlGlob?: string,
+ urlRegexSource?: string,
+ urlRegexFlags?: string,
+ harPath?: string,
+ resourcesDir?: string,
+};
+
+export type SerializedValue = {
+ n?: number,
+ b?: boolean,
+ s?: string,
+ v?: 'null' | 'undefined' | 'NaN' | 'Infinity' | '-Infinity' | '-0',
+ d?: string,
+ u?: string,
+ bi?: string,
+ ta?: {
+ b: Binary,
+ k: 'i8' | 'ui8' | 'ui8c' | 'i16' | 'ui16' | 'i32' | 'ui32' | 'f32' | 'f64' | 'bi64' | 'bui64',
+ },
+ e?: {
+ m: string,
+ n: string,
+ s: string,
+ },
+ r?: {
+ p: string,
+ f: string,
+ },
+ a?: SerializedValue[],
+ o?: {
+ k: string,
+ v: SerializedValue,
+ }[],
+ h?: number,
+ id?: number,
+ ref?: number,
+};
+
+export type SerializedArgument = {
+ value: SerializedValue,
+ handles: Channel[],
+};
+
+export type SerializedError = {
+ error?: {
+ message: string,
+ name: string,
+ stack?: string,
+ },
+ value?: SerializedValue,
+};
+
+export type StackFrame = {
+ file: string,
+ line: number,
+ column: number,
+ function?: string,
+};
+
+export type VirtualCredential = {
+ id: string,
+ rpId: string,
+ userHandle: string,
+ privateKey: string,
+ publicKey: string,
+};
+
+export type Point = {
+ x: number,
+ y: number,
+};
+
+export type Rect = {
+ x: number,
+ y: number,
+ width: number,
+ height: number,
+};
+
+export type URLPattern = {
+ hash: string,
+ hostname: string,
+ password: string,
+ pathname: string,
+ port: string,
+ protocol: string,
+ search: string,
+ username: string,
+};
+
+export type NameValue = {
+ name: string,
+ value: string,
+};
+
diff --git a/tests/config/ghaMarkdownReporter.ts b/tests/config/markdownReporter.ts
similarity index 50%
rename from tests/config/ghaMarkdownReporter.ts
rename to tests/config/markdownReporter.ts
index 548e2a2452772..3d477e4a9786c 100644
--- a/tests/config/ghaMarkdownReporter.ts
+++ b/tests/config/markdownReporter.ts
@@ -17,19 +17,19 @@
import fs from 'fs';
import path from 'path';
-import type { MetadataWithCommitInfo } from '@testIsomorphic/types';
-import type { IssueCommentEdge, Repository } from '@octokit/graphql-schema';
import type { FullConfig, FullResult, Reporter, Suite, TestCase, TestError } from '@playwright/test/reporter';
type MarkdownReporterOptions = {
configDir: string, // TODO: make it public?
- outputFile?: string;
};
+// Produces the markdown summary of a merged report and writes it to a file. The actual PR
+// comment is posted by a separate workflow step (see postReportComment.js) once the HTML
+// report has been uploaded as an artifact and its URL is known.
class MarkdownReporter implements Reporter {
private _options: MarkdownReporterOptions;
private _fatalErrors: TestError[] = [];
- protected _config!: FullConfig;
+ private _config!: FullConfig;
private _suite!: Suite;
constructor(options: MarkdownReporterOptions) {
@@ -82,24 +82,24 @@ class MarkdownReporter implements Reporter {
lines.push(`**${summary.expected} passed${skipped}${didNotRun}**`);
lines.push(``);
- await this.publishReport(lines.join('\n'));
+ await this._writeReport(lines.join('\n'));
}
- protected async publishReport(report: string): Promise {
- const maybeRelativeFile = this._options.outputFile || 'report.md';
+ private async _writeReport(report: string): Promise {
+ const maybeRelativeFile = process.env.MARKDOWN_OUTPUT_FILE || 'report.md';
const reportFile = path.resolve(this._options.configDir, maybeRelativeFile);
await fs.promises.mkdir(path.dirname(reportFile), { recursive: true });
await fs.promises.writeFile(reportFile, report);
}
- protected _incompleteRunWarning(): string | undefined {
+ private _incompleteRunWarning(): string | undefined {
const conclusion = process.env.WORKFLOW_RUN_CONCLUSION;
if (!conclusion || conclusion === 'success' || conclusion === 'failure')
return undefined;
return `> [!WARNING]\n> The triggering workflow run ended with status \`${conclusion}\`. Results below may be incomplete — blob reports from cancelled or timed-out shards are missing, so passing/failing counts do not reflect the full test suite.`;
}
- protected _generateSummary() {
+ private _generateSummary() {
let didNotRun = 0;
let skipped = 0;
let expected = 0;
@@ -158,134 +158,4 @@ function formatTestTitle(rootDir: string, test: TestCase): string {
return `${testTitle}${extraTags.length ? ' ' + formattedTags : ''}`;
}
-class GHAMarkdownReporter extends MarkdownReporter {
- private octokit: ReturnType;
- private context: typeof import('@actions/github').context;
- private core: typeof import('@actions/core');
-
- override async publishReport(report: string) {
- this.core = await import('@actions/core');
- const token = process.env.GITHUB_TOKEN || this.core.getInput('github-token');
- if (!token) {
- this.core.setFailed('Missing "github-token" input');
- throw new Error('Missing "github-token" input');
- }
- const { context, getOctokit } = await import('@actions/github');
- this.context = context;
- this.octokit = getOctokit(token);
-
- this.core.info('Publishing report to PR.');
- const { prNumber, prHref } = this.pullRequestFromMetadata();
- if (!prNumber) {
- this.core.info(`No PR number found, skipping GHA comment. PR href: ${prHref}`);
- return;
- }
- this.core.info(`Posting comment to PR ${prHref}`);
-
- const prNodeId = await this.collapsePreviousComments(prNumber);
- if (!prNodeId) {
- this.core.warning(`No PR node ID found, skipping GHA comment. PR href: ${prHref}`);
- return;
- }
- await this.addNewReportComment(prNodeId, report);
- }
-
- private async collapsePreviousComments(prNumber: number) {
- const { owner, repo } = this.context.repo;
- const data = await this.octokit.graphql<{ repository: Repository }>(`
- query($owner: String!, $repo: String!, $prNumber: Int!) {
- repository(owner: $owner, name: $repo) {
- pullRequest(number: $prNumber) {
- id
- comments(last: 100) {
- nodes {
- id
- body
- author {
- __typename
- login
- }
- }
- }
- }
- }
- }
- `, { owner, repo, prNumber });
- const comments = data.repository.pullRequest?.comments.nodes?.filter(comment =>
- comment?.author?.__typename === 'Bot' &&
- comment?.author?.login === 'github-actions' &&
- comment.body?.includes(this._magicComment()));
- const prId = data.repository.pullRequest?.id;
- if (!comments?.length)
- return prId;
- const variableDecls = comments.map((_, i) => `$id${i}: ID!`).join(', ');
- const mutations = comments.map((_, i) =>
- `m${i}: minimizeComment(input: { subjectId: $id${i}, classifier: OUTDATED }) { clientMutationId }`);
- const subjectIds = Object.fromEntries(comments.map((comment, i) => [`id${i}`, comment!.id]));
- await this.octokit.graphql(`
- mutation(${variableDecls}) {
- ${mutations.join('\n')}
- }
- `, subjectIds);
- return prId;
- }
-
- private _magicComment() {
- return ``;
- }
-
- private _workflowRunName() {
- // When used via 'workflow_run' event.
- const workflowRunName = this.context.payload.workflow_run?.name;
- if (workflowRunName)
- return workflowRunName;
- // When used via 'pull_request'/'push' event.
- // This is the name of the workflow file, e.g. 'ci.yml' or name if set.
- return process.env.GITHUB_WORKFLOW;
- }
-
- private async addNewReportComment(prNodeId: string, report: string) {
- const reportUrl = process.env.HTML_REPORT_URL;
- const mergeWorkflowUrl = `${this.context.serverUrl}/${this.context.repo.owner}/${this.context.repo.repo}/actions/runs/${this.context.runId}`;
-
- const body = formatComment([
- this._magicComment(),
- `### ${reportUrl ? `[Test results](${reportUrl})` : 'Test results'} for "${this._workflowRunName()}"`,
- report,
- '',
- '---',
- '',
- `Merge [workflow run](${mergeWorkflowUrl}).`
- ]);
-
- const response = await this.octokit.graphql<{ addComment: { commentEdge: IssueCommentEdge } }>(`
- mutation($subjectId: ID!, $body: String!) {
- addComment(input: {subjectId: $subjectId, body: $body}) {
- commentEdge {
- node {
- ... on IssueComment {
- url
- }
- }
- }
- }
- }
- `, { subjectId: prNodeId, body });
- this.core.info(`Posted comment: ${response.addComment.commentEdge.node?.url}`);
- }
-
- private pullRequestFromMetadata() {
- const metadata = this._config.metadata as MetadataWithCommitInfo;
- const prHref = metadata.ci?.prHref;
- return { prNumber: parseInt(prHref?.split('/').pop() ?? '', 10), prHref };
- }
-}
-
-function formatComment(lines: string[]) {
- let body = lines.join('\n');
- if (body.length > 65535)
- body = body.substring(0, 65000) + `... ${body.length - 65000} more characters`;
- return body;
-}
-
-export default GHAMarkdownReporter;
+export default MarkdownReporter;
diff --git a/tests/config/postReportComment.js b/tests/config/postReportComment.js
new file mode 100644
index 0000000000000..55378d3a1880d
--- /dev/null
+++ b/tests/config/postReportComment.js
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const fs = require('fs');
+const path = require('path');
+
+/**
+ * @param {{ github: any, context: any, core: any, reportFile: string, prNumber: number, reportUrl?: string }} params
+ */
+async function postReportComment({ github, context, core, reportFile, prNumber, reportUrl }) {
+ if (!prNumber) {
+ core.info('No PR number provided, skipping GHA comment.');
+ return;
+ }
+ const report = fs.readFileSync(path.resolve(process.cwd(), reportFile), 'utf8');
+ core.info(`Posting comment to PR #${prNumber}`);
+
+ const prNodeId = await collapsePreviousComments(github, context, prNumber);
+ if (!prNodeId) {
+ core.warning(`No PR node ID found for #${prNumber}, skipping GHA comment.`);
+ return;
+ }
+ const url = await addNewReportComment(github, context, prNodeId, report, reportUrl);
+ core.info(`Posted comment: ${url}`);
+}
+
+function workflowRunName(context) {
+ // When used via 'workflow_run' event.
+ const name = context.payload.workflow_run?.name;
+ if (name)
+ return name;
+ // When used via 'pull_request'/'push' event.
+ return process.env.GITHUB_WORKFLOW;
+}
+
+function magicComment(context) {
+ return ``;
+}
+
+async function collapsePreviousComments(github, context, prNumber) {
+ const { owner, repo } = context.repo;
+ const data = await github.graphql(`
+ query($owner: String!, $repo: String!, $prNumber: Int!) {
+ repository(owner: $owner, name: $repo) {
+ pullRequest(number: $prNumber) {
+ id
+ comments(last: 100) {
+ nodes {
+ id
+ body
+ author {
+ __typename
+ login
+ }
+ }
+ }
+ }
+ }
+ }
+ `, { owner, repo, prNumber });
+ const comments = data.repository.pullRequest?.comments.nodes?.filter(comment =>
+ comment?.author?.__typename === 'Bot' &&
+ comment?.author?.login === 'github-actions' &&
+ comment.body?.includes(magicComment(context)));
+ const prId = data.repository.pullRequest?.id;
+ if (!comments?.length)
+ return prId;
+ const variableDecls = comments.map((_, i) => `$id${i}: ID!`).join(', ');
+ const mutations = comments.map((_, i) =>
+ `m${i}: minimizeComment(input: { subjectId: $id${i}, classifier: OUTDATED }) { clientMutationId }`);
+ const subjectIds = Object.fromEntries(comments.map((comment, i) => [`id${i}`, comment.id]));
+ await github.graphql(`
+ mutation(${variableDecls}) {
+ ${mutations.join('\n')}
+ }
+ `, subjectIds);
+ return prId;
+}
+
+async function addNewReportComment(github, context, prNodeId, report, reportUrl) {
+ const mergeWorkflowUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
+
+ const body = formatComment([
+ magicComment(context),
+ `### ${reportUrl ? `[Test results](${reportUrl})` : 'Test results'} for "${workflowRunName(context)}"`,
+ report,
+ '',
+ '---',
+ '',
+ `Merge [workflow run](${mergeWorkflowUrl}).`
+ ]);
+
+ const response = await github.graphql(`
+ mutation($subjectId: ID!, $body: String!) {
+ addComment(input: {subjectId: $subjectId, body: $body}) {
+ commentEdge {
+ node {
+ ... on IssueComment {
+ url
+ }
+ }
+ }
+ }
+ }
+ `, { subjectId: prNodeId, body });
+ return response.addComment.commentEdge.node?.url;
+}
+
+function formatComment(lines) {
+ let body = lines.join('\n');
+ if (body.length > 65535)
+ body = body.substring(0, 65000) + `... ${body.length - 65000} more characters`;
+ return body;
+}
+
+module.exports = { postReportComment };
diff --git a/tsconfig.json b/tsconfig.json
index a027e586c8ff4..c26c7fc9c6851 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -16,6 +16,7 @@
"@injected/*": ["./packages/injected/src/*"],
"@isomorphic/*": ["./packages/isomorphic/*"],
"@utils/*": ["./packages/utils/*"],
+ "@protocol/*": ["./packages/protocol/src/*"],
"@recorder/*": ["./packages/recorder/src/*"],
"@testIsomorphic/*": ["./packages/playwright/src/isomorphic/*"],
"@trace/*": ["./packages/trace/src/*"],
diff --git a/utils/generate_channels.js b/utils/generate_channels.js
index cb03c6430ab63..374d334fa8a34 100755
--- a/utils/generate_channels.js
+++ b/utils/generate_channels.js
@@ -131,10 +131,8 @@ function channelsHeader(target) {
import type { Progress } from './progress';
` : '') + `
-export type Binary = Buffer;
-
-export interface Channel {
-}
+import type { Binary, Channel, ${structNames.join(', ')} } from '@protocol/structs';
+export type { Binary, Channel, ${structNames.join(', ')} } from '@protocol/structs';
`];
}
@@ -197,6 +195,13 @@ for (const [name, value] of Object.entries(protocol)) {
mixins.set(name, value);
}
+// Struct types (objects and enums) are identical for the client and the server,
+// so they are generated once into a shared structs.d.ts file that both the
+// client and the server channels.d.ts import and re-export.
+const structNames = Object.entries(protocol)
+ .filter(([, value]) => value.type === 'object' || value.type === 'enum')
+ .map(([name]) => name);
+
const derivedClasses = new Map();
for (const [name, item] of Object.entries(protocol)) {
if (item.type === 'interface' && item.extends) {
@@ -371,12 +376,8 @@ function generateChannels(target) {
} else if (item.type === 'object') {
const inner = objectType(item.properties, '');
- channels_ts.push(`export type ${name} = ${inner.ts};`);
- channels_ts.push(``);
addScheme(name, inner.scheme);
} else if (item.type === 'enum') {
- const ts = item.literals.map(literal => `'${literal}'`).join(' | ');
- channels_ts.push(`export type ${name} = ${ts};`)
addScheme(name, `tEnum([${item.literals.map(literal => `'${literal}'`).join(', ')}])`);
}
}
@@ -384,6 +385,50 @@ function generateChannels(target) {
return channels_ts;
}
+function structsHeader() {
+ return `/**
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file is generated by ${path.basename(__filename).split(path.sep).join(path.posix.sep)}, do not edit manually.
+
+export type Binary = Buffer;
+
+export interface Channel {
+}
+`;
+}
+
+function generateStructs() {
+ const structs_ts = [structsHeader()];
+ for (const [name, item] of Object.entries(protocol)) {
+ if (item.type === 'object') {
+ const inner = objectType(item.properties, '');
+ structs_ts.push(`export type ${name} = ${inner.ts};`);
+ structs_ts.push(``);
+ } else if (item.type === 'enum') {
+ const ts = item.literals.map(literal => `'${literal}'`).join(' | ');
+ structs_ts.push(`export type ${name} = ${ts};`);
+ structs_ts.push(``);
+ }
+ }
+ return structs_ts;
+}
+
+const structs_ts = generateStructs();
+
const client_channels_ts = generateChannels('Channel');
metainfo_ts.push(`export type MethodMetainfo = { internal?: boolean, title?: string, slowMo?: boolean, snapshot?: boolean, pause?: boolean, isAutoWaiting?: boolean, input?: boolean, group?: string };
@@ -416,6 +461,7 @@ function writeFile(filePath, content) {
fs.writeFileSync(filePath, content, 'utf8');
}
+writeFile(path.join(__dirname, '..', 'packages', 'protocol', 'src', 'structs.d.ts'), structs_ts.join('\n') + '\n');
writeFile(path.join(__dirname, '..', 'packages', 'playwright-core', 'src', 'client', 'channels.d.ts'), client_channels_ts.join('\n') + '\n');
writeFile(path.join(__dirname, '..', 'packages', 'playwright-core', 'src', 'server', 'channels.d.ts'), server_channels_ts.join('\n') + '\n');
writeFile(path.join(__dirname, '..', 'packages', 'isomorphic', 'protocolMetainfo.ts'), metainfoContent);