Compare commits

...

23 commits

Author SHA1 Message Date
Andrey Lushnikov 64a18acf81
chore: mark 1.29.2 (#19913) 2023-01-05 23:49:42 -08:00
Michael Glass 9e7001557e cherry-pick(#19771): fix(playwright-test): _removeOutputDirs called without await always returns truthy
SHA: 13c5019ac9
2023-01-05 15:47:42 -08:00
Playwright Service b8b1c40cf3
chery-pick(#19843): chore: update .net generator with deprecated/discouraged (#19844)
This PR cherry-picks the following commits:

- 599ae30313

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-03 23:04:45 +01:00
Ross Wollman 6eec55cffd
cherry-pick(#19759): fix(driver): avoid polluting stdout (#19784)
Relates microsoft/playwright-python#1699.
2023-01-02 14:26:26 +01:00
Playwright Service cc00c207af
chery-pick(#19783): chore: bump json5 to 2.2.2 (#19792)
This PR cherry-picks the following commits:

- fc56afb990

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-02 14:17:41 +01:00
Dmitry Gozman 5f3e3134bf
cherry-pick(#19723): fix(launchServer): disable socks by default (#19725)
Socks does not support ipV6 yet.
2022-12-27 11:38:11 -08:00
Andrey Lushnikov 0bdca2b913
chore: mark v1.29.1 (#19633) 2022-12-21 13:19:32 -08:00
Dmitry Gozman f2916d4ced
cherry-pick(#19627): fix(screenshot): account for screenshot === undefined (#19631) 2022-12-21 11:14:30 -08:00
Playwright Service db88d4ba0f
chery-pick(#19625): chore: bring ubuntu bionic back (#19629)
This PR cherry-picks the following commits:

- 7508c574e1

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-21 10:25:45 -08:00
Playwright Service 5d07c48e17
chery-pick(#19617): feat(chromium): roll to r1041 (#19623)
This PR cherry-picks the following commits:

- acd3837484

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-21 10:25:26 -08:00
Playwright Service 25c747d5ef
chery-pick(#19605): chore: fix docs roll (#19608)
This PR cherry-picks the following commits:

- 51782cfa5d

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-20 22:07:17 +01:00
Playwright Service ae7a8d2aa7
chery-pick(#19573): docs: add 1.29 language port release notes (#19606)
This PR cherry-picks the following commits:

- 3555dbd4b4

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-20 21:53:30 +01:00
Playwright Service 5c0e23d6aa
chery-pick(#19596): fix: render discouraged / deprecated types (#19598)
This PR cherry-picks the following commits:

- bb2a2c7331

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-20 21:53:21 +01:00
Pavel Feldman 0237b7b742 cherry-pick(#19601): fix(electron): fix the directory app path 2022-12-20 12:52:38 -08:00
Pavel Feldman e78bd2436c cherry-pick(#19599): fix(electron): allow using pre-ready apis 2022-12-20 10:59:19 -08:00
Andrey Lushnikov d10cc91cf6 cherry-pick(#19580): fix: properly handle negated timed-out toPass matcher 2022-12-20 08:43:56 -08:00
Pavel Feldman efa3756c16 cherry-pick(#19574): chore: replace worker index w/ parallel index in the docs 2022-12-19 14:23:44 -08:00
Yury Semikhatsky 00895e36d4
cherry-pick(#19532): docs: remove Serializable from Route.*.postData in java (#19533) 2022-12-16 11:21:51 -08:00
Yury Semikhatsky 0cf3ec2e64
cherry-pick(#19527): docs: route.fetch.postData in java (#19528) 2022-12-16 10:16:40 -08:00
Andrey Lushnikov 5c3be309df
chore: mark 1.29.0 (#19491) 2022-12-16 09:49:56 -08:00
Andrey Lushnikov a100191ec9 cherry-pick(#19497): chore: release notes 1.29
Signed-off-by: Andrey Lushnikov <aslushnikov@gmail.com>
Co-authored-by: Max Schmitt <max@schmitt.mx>
2022-12-16 09:48:53 -08:00
Playwright Service 4b871153d0
chery-pick(#19509): docs: fix locator all since version (#19521)
This PR cherry-picks the following commits:

- 1e31afd9d7
2022-12-16 18:19:51 +01:00
Playwright Service 8a9692e2c5
chery-pick(#19507): docs: fix HTML snippets (#19508)
This PR cherry-picks the following commits:

- ba8a6c4b08
2022-12-16 18:19:35 +01:00
47 changed files with 1029 additions and 378 deletions

View file

@ -7,7 +7,7 @@ a way to find element(s) on the page at any moment. Locator can be created with
[Learn more about locators](../locators.md). [Learn more about locators](../locators.md).
## async method: Locator.all ## async method: Locator.all
* since: v1.14 * since: v1.29
- returns: <[Array]<[Locator]>> - returns: <[Array]<[Locator]>>
When locator points to a list of elements, returns array of locators, pointing When locator points to a list of elements, returns array of locators, pointing

View file

@ -114,11 +114,18 @@ If set changes the request method (e.g. GET or POST).
### option: Route.continue.postData ### option: Route.continue.postData
* since: v1.8 * since: v1.8
* langs: js, python, java * langs: js, python
- `postData` <[string]|[Buffer]|[Serializable]> - `postData` <[string]|[Buffer]|[Serializable]>
If set changes the post data of request. If set changes the post data of request.
### option: Route.continue.postData
* since: v1.8
* langs: java
- `postData` <[string]|[Buffer]>
If set changes the post data of request.
### option: Route.continue.postData ### option: Route.continue.postData
* since: v1.8 * since: v1.8
* langs: csharp * langs: csharp
@ -390,11 +397,18 @@ If set changes the request method (e.g. GET or POST).
### option: Route.fallback.postData ### option: Route.fallback.postData
* since: v1.23 * since: v1.23
* langs: js, python, java * langs: js, python
- `postData` <[string]|[Buffer]|[Serializable]> - `postData` <[string]|[Buffer]|[Serializable]>
If set changes the post data of request. If set changes the post data of request.
### option: Route.fallback.postData
* since: v1.23
* langs: java
- `postData` <[string]|[Buffer]>
If set changes the post data of request.
### option: Route.fallback.postData ### option: Route.fallback.postData
* since: v1.23 * since: v1.23
* langs: csharp * langs: csharp
@ -480,8 +494,21 @@ If set changes the request URL. New URL must have same protocol as original one.
If set changes the request method (e.g. GET or POST). If set changes the request method (e.g. GET or POST).
### option: Route.fetch.postData = %%-js-python-csharp-fetch-option-post-data-%% ### option: Route.fetch.postData
* langs: js, python
* since: v1.29 * since: v1.29
- `postData` <[string]|[Buffer]|[Serializable]>
Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string
and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` header will be
set to `application/octet-stream` if not explicitly set.
### option: Route.fetch.postData
* langs: java
* since: v1.29
- `postData` <[string]|[Buffer]>
If set changes the post data of request.
### option: Route.fetch.postData ### option: Route.fetch.postData
* since: v1.29 * since: v1.29
@ -611,28 +638,11 @@ Optional response body as raw bytes.
### option: Route.fulfill.json ### option: Route.fulfill.json
* since: v1.29 * since: v1.29
* langs: js, python * langs: js, python, csharp
- `json` <[Serializable]> - `json` <[Serializable]>
JSON response. This method will set the content type to `application/json` if not set. JSON response. This method will set the content type to `application/json` if not set.
### option: Route.fulfill.json
* since: v1.29
* langs: csharp
- `json` <[JsonElement]>
JSON response. This method will set the content type to `application/json` if not set.
**Usage**
```csharp
await page.RouteAsync("https://dog.ceo/api/breeds/list/all", async route =>
{
var json = /* JsonElement with test payload */;
await route.FulfillAsync(new () { Json: json });
});
```
### option: Route.fulfill.path ### option: Route.fulfill.path
* since: v1.8 * since: v1.8
- `path` <[path]> - `path` <[path]>

View file

@ -2,8 +2,7 @@
* since: v1.8 * since: v1.8
* extends: [Error] * extends: [Error]
TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g. [`method: TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g. [`method: Locator.waitFor`] or [`method: BrowserType.launch`].
Locator.waitFor`] or [`method: BrowserType.launch`].
```js ```js
const playwright = require('playwright'); const playwright = require('playwright');

View file

@ -389,14 +389,6 @@ Allows to set post data of the request. If the data parameter is an object, it w
and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` header will be and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` header will be
set to `application/octet-stream` if not explicitly set. set to `application/octet-stream` if not explicitly set.
## js-python-csharp-fetch-option-post-data
* langs: js, python, csharp
- `postData` <[string]|[Buffer]|[Serializable]>
Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string
and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` header will be
set to `application/octet-stream` if not explicitly set.
## js-python-csharp-fetch-option-ignorehttpserrors ## js-python-csharp-fetch-option-ignorehttpserrors
* langs: js, python, csharp * langs: js, python, csharp
- `ignoreHTTPSErrors` <[boolean]> - `ignoreHTTPSErrors` <[boolean]>

View file

@ -319,46 +319,9 @@ export default globalSetup;
By default, Playwright Test runs tests in parallel. If you reuse a single signed-in state for all your tests, this usually leads to the same account being signed in from multiple tests at the same time. If this behavior is undesirable for your application, you can sign in with a different account in each [worker process](./test-parallel.md#worker-processes) created by Playwright Test. By default, Playwright Test runs tests in parallel. If you reuse a single signed-in state for all your tests, this usually leads to the same account being signed in from multiple tests at the same time. If this behavior is undesirable for your application, you can sign in with a different account in each [worker process](./test-parallel.md#worker-processes) created by Playwright Test.
In this example we [override `storageState` fixture](./test-fixtures.md#overriding-fixtures) and ensure we only sign in once per worker, using [`property: TestInfo.workerIndex`] to differentiate between workers. In this example we [override `storageState` fixture](./test-fixtures.md#overriding-fixtures) and ensure we only sign in once per worker, using [`property: TestInfo.parallelIndex`] to differentiate between workers.
```js tab=js-js ```js
// fixtures.js
const { test: base } = require('@playwright/test');
const users = [
{ username: 'user-1', password: 'password-1' },
{ username: 'user-2', password: 'password-2' },
// ... put your test users here ...
];
exports.test = base.extend({
storageState: async ({ browser }, use, testInfo) => {
// Override storage state, use worker index to look up logged-in info and generate it lazily.
const fileName = path.join(testInfo.project.outputDir, 'storage-' + testInfo.workerIndex);
if (!fs.existsSync(fileName)) {
// Make sure we are not using any other storage state.
const page = await browser.newPage({ storageState: undefined });
await page.goto('https://github.com/login');
await page.getByLabel('User Name').fill(users[testInfo.workerIndex].username);
await page.getByLabel('Password').fill(users[testInfo.workerIndex].password);
await page.getByText('Sign in').click();
await page.context().storageState({ path: fileName });
await page.close();
}
await use(fileName);
},
});
exports.expect = base.expect;
// example.spec.js
const { test, expect } = require('./fixtures');
test('test', async ({ page }) => {
// page is signed in.
});
```
```js tab=js-ts
// fixtures.ts // fixtures.ts
import { test as baseTest } from '@playwright/test'; import { test as baseTest } from '@playwright/test';
export { expect } from '@playwright/test'; export { expect } from '@playwright/test';
@ -371,15 +334,15 @@ const users = [
export const test = baseTest.extend({ export const test = baseTest.extend({
storageState: async ({ browser }, use, testInfo) => { storageState: async ({ browser }, use, testInfo) => {
// Override storage state, use worker index to look up logged-in info and generate it lazily. // Override storage state, use parallel index to look up logged-in info and generate it lazily.
const fileName = path.join(testInfo.project.outputDir, 'storage-' + testInfo.workerIndex); const fileName = path.join(testInfo.project.outputDir, 'storage-' + testInfo.parallelIndex);
if (!fs.existsSync(fileName)) { if (!fs.existsSync(fileName)) {
// Make sure we are not using any other storage state. // Make sure we are not using any other storage state.
const page = await browser.newPage({ storageState: undefined }); const page = await browser.newPage({ storageState: undefined });
await page.goto('https://github.com/login'); await page.goto('https://github.com/login');
// Create a unique username for each worker. // Create a unique username for each worker.
await page.getByLabel('User Name').fill(users[testInfo.workerIndex].username); await page.getByLabel('User Name').fill(users[testInfo.parallelIndex].username);
await page.getByLabel('Password').fill(users[testInfo.workerIndex].password); await page.getByLabel('Password').fill(users[testInfo.parallelIndex].password);
await page.getByText('Sign in').click(); await page.getByText('Sign in').click();
await page.context().storageState({ path: fileName }); await page.context().storageState({ path: fileName });
await page.close(); await page.close();

View file

@ -176,7 +176,7 @@ steps:
name: 'Playwright Tests' name: 'Playwright Tests'
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: mcr.microsoft.com/playwright:v1.29.0-focal image: mcr.microsoft.com/playwright:v1.29.2-focal
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
@ -194,7 +194,7 @@ steps:
name: 'Playwright Tests' name: 'Playwright Tests'
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: mcr.microsoft.com/playwright:v1.29.0-focal image: mcr.microsoft.com/playwright:v1.29.2-focal
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up Python - name: Set up Python
@ -218,7 +218,7 @@ steps:
name: 'Playwright Tests' name: 'Playwright Tests'
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: mcr.microsoft.com/playwright:v1.29.0-focal image: mcr.microsoft.com/playwright:v1.29.2-focal
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-java@v3 - uses: actions/setup-java@v3
@ -239,7 +239,7 @@ steps:
name: 'Playwright Tests' name: 'Playwright Tests'
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: mcr.microsoft.com/playwright:v1.29.0-focal image: mcr.microsoft.com/playwright:v1.29.2-focal
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup dotnet - name: Setup dotnet
@ -264,7 +264,7 @@ steps:
name: 'Playwright Tests - ${{ matrix.project }} - Shard ${{ matrix.shardIndex }} of ${{ matrix.shardTotal }}' name: 'Playwright Tests - ${{ matrix.project }} - Shard ${{ matrix.shardIndex }} of ${{ matrix.shardTotal }}'
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: mcr.microsoft.com/playwright:v1.29.0-focal image: mcr.microsoft.com/playwright:v1.29.2-focal
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -299,7 +299,7 @@ jobs:
- deployment: Run_E2E_Tests - deployment: Run_E2E_Tests
pool: pool:
vmImage: ubuntu-20.04 vmImage: ubuntu-20.04
container: mcr.microsoft.com/playwright:v1.29.0-focal container: mcr.microsoft.com/playwright:v1.29.2-focal
environment: testing environment: testing
strategy: strategy:
runOnce: runOnce:
@ -325,7 +325,7 @@ jobs:
- deployment: Run_E2E_Tests - deployment: Run_E2E_Tests
pool: pool:
vmImage: ubuntu-20.04 vmImage: ubuntu-20.04
container: mcr.microsoft.com/playwright:v1.29.0-focal container: mcr.microsoft.com/playwright:v1.29.2-focal
environment: testing environment: testing
strategy: strategy:
runOnce: runOnce:
@ -369,7 +369,7 @@ Running Playwright on CircleCI is very similar to running on GitHub Actions. In
executors: executors:
pw-focal-development: pw-focal-development:
docker: docker:
- image: mcr.microsoft.com/playwright:v1.29.0-focal - image: mcr.microsoft.com/playwright:v1.29.2-focal
environment: environment:
NODE_ENV: development # Needed if playwright is in `devDependencies` NODE_ENV: development # Needed if playwright is in `devDependencies`
``` ```
@ -405,7 +405,7 @@ to run tests on Jenkins.
```groovy ```groovy
pipeline { pipeline {
agent { docker { image 'mcr.microsoft.com/playwright:v1.29.0-focal' } } agent { docker { image 'mcr.microsoft.com/playwright:v1.29.2-focal' } }
stages { stages {
stage('e2e-tests') { stage('e2e-tests') {
steps { steps {
@ -423,7 +423,7 @@ pipeline {
Bitbucket Pipelines can use public [Docker images as build environments](https://confluence.atlassian.com/bitbucket/use-docker-images-as-build-environments-792298897.html). To run Playwright tests on Bitbucket, use our public Docker image ([see Dockerfile](./docker.md)). Bitbucket Pipelines can use public [Docker images as build environments](https://confluence.atlassian.com/bitbucket/use-docker-images-as-build-environments-792298897.html). To run Playwright tests on Bitbucket, use our public Docker image ([see Dockerfile](./docker.md)).
```yml ```yml
image: mcr.microsoft.com/playwright:v1.29.0-focal image: mcr.microsoft.com/playwright:v1.29.2-focal
``` ```
### GitLab CI ### GitLab CI
@ -436,7 +436,7 @@ stages:
tests: tests:
stage: test stage: test
image: mcr.microsoft.com/playwright:v1.29.0-focal image: mcr.microsoft.com/playwright:v1.29.2-focal
script: script:
... ...
``` ```
@ -452,7 +452,7 @@ stages:
tests: tests:
stage: test stage: test
image: mcr.microsoft.com/playwright:v1.29.0-focal image: mcr.microsoft.com/playwright:v1.29.2-focal
parallel: 7 parallel: 7
script: script:
- npm ci - npm ci
@ -467,7 +467,7 @@ stages:
tests: tests:
stage: test stage: test
image: mcr.microsoft.com/playwright:v1.29.0-focal image: mcr.microsoft.com/playwright:v1.29.2-focal
parallel: parallel:
matrix: matrix:
- PROJECT: ['chromium', 'webkit'] - PROJECT: ['chromium', 'webkit']

View file

@ -14,19 +14,19 @@ This image is published on [Docker Hub].
### Pull the image ### Pull the image
```bash js ```bash js
docker pull mcr.microsoft.com/playwright:v1.29.0-focal docker pull mcr.microsoft.com/playwright:v1.29.2-focal
``` ```
```bash python ```bash python
docker pull mcr.microsoft.com/playwright/python:v1.29.0-focal docker pull mcr.microsoft.com/playwright/python:v1.29.2-focal
``` ```
```bash csharp ```bash csharp
docker pull mcr.microsoft.com/playwright/dotnet:v1.29.0-focal docker pull mcr.microsoft.com/playwright/dotnet:v1.29.2-focal
``` ```
```bash java ```bash java
docker pull mcr.microsoft.com/playwright/java:v1.29.0-focal docker pull mcr.microsoft.com/playwright/java:v1.29.2-focal
``` ```
### Run the image ### Run the image
@ -38,19 +38,19 @@ By default, the Docker image will use the `root` user to run the browsers. This
On trusted websites, you can avoid creating a separate user and use root for it since you trust the code which will run on the browsers. On trusted websites, you can avoid creating a separate user and use root for it since you trust the code which will run on the browsers.
```bash js ```bash js
docker run -it --rm --ipc=host mcr.microsoft.com/playwright:v1.29.0-focal /bin/bash docker run -it --rm --ipc=host mcr.microsoft.com/playwright:v1.29.2-focal /bin/bash
``` ```
```bash python ```bash python
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/python:v1.29.0-focal /bin/bash docker run -it --rm --ipc=host mcr.microsoft.com/playwright/python:v1.29.2-focal /bin/bash
``` ```
```bash csharp ```bash csharp
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/dotnet:v1.29.0-focal /bin/bash docker run -it --rm --ipc=host mcr.microsoft.com/playwright/dotnet:v1.29.2-focal /bin/bash
``` ```
```bash java ```bash java
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/java:v1.29.0-focal /bin/bash docker run -it --rm --ipc=host mcr.microsoft.com/playwright/java:v1.29.2-focal /bin/bash
``` ```
#### Crawling and scraping #### Crawling and scraping
@ -58,19 +58,19 @@ docker run -it --rm --ipc=host mcr.microsoft.com/playwright/java:v1.29.0-focal /
On untrusted websites, it's recommended to use a separate user for launching the browsers in combination with the seccomp profile. Inside the container or if you are using the Docker image as a base image you have to use `adduser` for it. On untrusted websites, it's recommended to use a separate user for launching the browsers in combination with the seccomp profile. Inside the container or if you are using the Docker image as a base image you have to use `adduser` for it.
```bash js ```bash js
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright:v1.29.0-focal /bin/bash docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright:v1.29.2-focal /bin/bash
``` ```
```bash python ```bash python
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/python:v1.29.0-focal /bin/bash docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/python:v1.29.2-focal /bin/bash
``` ```
```bash csharp ```bash csharp
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/dotnet:v1.29.0-focal /bin/bash docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/dotnet:v1.29.2-focal /bin/bash
``` ```
```bash java ```bash java
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/java:v1.29.0-focal /bin/bash docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/java:v1.29.2-focal /bin/bash
``` ```
[`seccomp_profile.json`](https://github.com/microsoft/playwright/blob/main/utils/docker/seccomp_profile.json) is needed to run Chromium with sandbox. This is a [default Docker seccomp profile](https://github.com/docker/engine/blob/d0d99b04cf6e00ed3fc27e81fc3d94e7eda70af3/profiles/seccomp/default.json) with extra user namespace cloning permissions: [`seccomp_profile.json`](https://github.com/microsoft/playwright/blob/main/utils/docker/seccomp_profile.json) is needed to run Chromium with sandbox. This is a [default Docker seccomp profile](https://github.com/docker/engine/blob/d0d99b04cf6e00ed3fc27e81fc3d94e7eda70af3/profiles/seccomp/default.json) with extra user namespace cloning permissions:

View file

@ -815,7 +815,7 @@ Consider the following DOM structure where we want to click on the buy button of
<h3>Product 2</h3> <h3>Product 2</h3>
<button>Add to cart</button> <button>Add to cart</button>
</li> </li>
<ul> </ul>
``` ```
### Filter by text ### Filter by text
@ -854,7 +854,7 @@ page.get_by_role("listitem").filter(has_text="Product 2").get_by_role(
await page await page
.GetByRole(AriaRole.Listitem) .GetByRole(AriaRole.Listitem)
.Filter(new() { HasText = "Product 2" }) .Filter(new() { HasText = "Product 2" })
.GetByRole(AriaRole.Button, new () { Name = "Add to cart" }) .GetByRole(AriaRole.Button, new() { Name = "Add to cart" })
.ClickAsync(); .ClickAsync();
``` ```
@ -893,7 +893,7 @@ page.get_by_role("listitem").filter(has_text=re.compile("Product 2")).get_by_rol
await page await page
.GetByRole(AriaRole.Listitem) .GetByRole(AriaRole.Listitem)
.Filter(new() { HasTextRegex = new Regex("Product 2") }) .Filter(new() { HasTextRegex = new Regex("Product 2") })
.GetByRole(AriaRole.Button, new () { Name = "Add to cart" }) .GetByRole(AriaRole.Button, new() { Name = "Add to cart" })
.ClickAsync(); .ClickAsync();
``` ```
@ -948,11 +948,11 @@ page.get_by_role("listitem").filter(
await page await page
.GetByRole(AriaRole.Listitem) .GetByRole(AriaRole.Listitem)
.Filter(new() { .Filter(new() {
Has = page.GetByRole(AriaRole.Heading, new () { Has = page.GetByRole(AriaRole.Heading, new() {
Name = "Product 2" Name = "Product 2"
}) })
}) })
.GetByRole(AriaRole.Button, new () { Name = "Add to cart" }) .GetByRole(AriaRole.Button, new() { Name = "Add to cart" })
.ClickAsync(); .ClickAsync();
``` ```
@ -992,7 +992,7 @@ expect(
await Expect(page await Expect(page
.GetByRole(AriaRole.Listitem) .GetByRole(AriaRole.Listitem)
.Filter(new() { .Filter(new() {
Has = page.GetByRole(AriaRole.Heading, new () { Name = "Product 2" }) Has = page.GetByRole(AriaRole.Heading, new() { Name = "Product 2" })
}) })
.toHaveCountAsync(1); .toHaveCountAsync(1);
``` ```

View file

@ -4,6 +4,63 @@ title: "Release notes"
toc_max_heading_level: 2 toc_max_heading_level: 2
--- ---
## Version 1.29
### New APIs
- New method [`method: Route.fetch`] and new option `Json` for [`method: Route.fulfill`]:
```csharp
await Page.RouteAsync("**/api/settings", async route => {
// Fetch original settings.
var response = await route.FetchAsync();
// Force settings theme to a predefined value.
var json = await response.JsonAsync<MyDataType>();
json.Theme = "Solarized";
// Fulfill with modified data.
await route.FulfillAsync(new() {
Json = json
});
});
```
- New method [`method: Locator.all`] to iterate over all matching elements:
```csharp
// Check all checkboxes!
var checkboxes = Page.GetByRole(AriaRole.Checkbox);
foreach (var checkbox in await checkboxes.AllAsync())
await checkbox.CheckAsync();
```
- [`method: Locator.selectOption`] matches now by value or label:
```html
<select multiple>
<option value="red">Red</div>
<option value="green">Green</div>
<option value="blue">Blue</div>
</select>
```
```csharp
await element.SelectOptionAsync("Red");
```
### Browser Versions
* Chromium 109.0.5414.46
* Mozilla Firefox 107.0
* WebKit 16.4
This version was also tested against the following stable channels:
* Google Chrome 108
* Microsoft Edge 108
## Version 1.28 ## Version 1.28
### Playwright Tools ### Playwright Tools

View file

@ -4,6 +4,44 @@ title: "Release notes"
toc_max_heading_level: 2 toc_max_heading_level: 2
--- ---
## Version 1.29
### New APIs
- New method [`method: Locator.all`] to iterate over all matching elements:
```java
// Check all checkboxes!
Locator checkboxes = page.getByRole(AriaRole.CHECKBOX);
for (Locator checkbox : checkboxes.all())
checkbox.check();
```
- [`method: Locator.selectOption`] matches now by value or label:
```html
<select multiple>
<option value="red">Red</div>
<option value="green">Green</div>
<option value="blue">Blue</div>
</select>
```
```java
element.selectOption('Red');
```
### Browser Versions
* Chromium 109.0.5414.46
* Mozilla Firefox 107.0
* WebKit 16.4
This version was also tested against the following stable channels:
* Google Chrome 108
* Microsoft Edge 108
## Version 1.28 ## Version 1.28
### Playwright Tools ### Playwright Tools

View file

@ -4,6 +4,94 @@ title: "Release notes"
toc_max_heading_level: 2 toc_max_heading_level: 2
--- ---
## Version 1.29
### New APIs
- New method [`method: Route.fetch`] and new option `json` for [`method: Route.fulfill`]:
```js
await page.route('**/api/settings', async route => {
// Fetch original settings.
const response = await route.fetch();
// Force settings theme to a predefined value.
const json = await response.json();
json.theme = 'Solorized';
// Fulfill with modified data.
await route.fulfill({ json });
});
```
- New method [`method: Locator.all`] to iterate over all matching elements:
```js
// Check all checkboxes!
const checkboxes = page.getByRole('checkbox');
for (const checkbox of await checkboxes.all())
await checkbox.check();
```
- [`method: Locator.selectOption`] matches now by value or label:
```html
<select multiple>
<option value="red">Red</div>
<option value="green">Green</div>
<option value="blue">Blue</div>
</select>
```
```js
await element.selectOption('Red');
```
- Retry blocks of code until all assertions pass:
```js
await expect(async () => {
const response = await page.request.get('https://api.example.com');
await expect(response).toBeOK();
}).toPass();
```
Read more in [our documentation](./test-assertions.md#retrying).
- Automatically capture **full page screenshot** on test failure:
```js
// playwright.config.ts
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
use: {
screenshot: {
mode: 'only-on-failure',
fullPage: true,
}
}
};
export default config;
```
### Miscellaneous
- Playwright Test now respects [`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig).
- New options `args` and `proxy` for [`method: AndroidDevice.launchBrowser`].
- Option `postData` in method [`method: Route.continue`] now supports [Serializable] values.
### Browser Versions
* Chromium 109.0.5414.46
* Mozilla Firefox 107.0
* WebKit 16.4
This version was also tested against the following stable channels:
* Google Chrome 108
* Microsoft Edge 108
## Version 1.28 ## Version 1.28
<div className="embed-youtube"> <div className="embed-youtube">
@ -218,7 +306,7 @@ This version was also tested against the following stable channels:
### Announcements ### Announcements
* 🎁 We now ship Ubuntu 22.04 Jammy Jellyfish docker image: `mcr.microsoft.com/playwright:v1.29.0-jammy`. * 🎁 We now ship Ubuntu 22.04 Jammy Jellyfish docker image: `mcr.microsoft.com/playwright:v1.29.2-jammy`.
* 🪦 This is the last release with macOS 10.15 support (deprecated as of 1.21). * 🪦 This is the last release with macOS 10.15 support (deprecated as of 1.21).
* 🪦 This is the last release with Node.js 12 support, we recommend upgrading to Node.js LTS (16). * 🪦 This is the last release with Node.js 12 support, we recommend upgrading to Node.js LTS (16).
* ⚠️ Ubuntu 18 is now deprecated and will not be supported as of Dec 2022. * ⚠️ Ubuntu 18 is now deprecated and will not be supported as of Dec 2022.
@ -468,7 +556,7 @@ Read more about [component testing with Playwright](./test-components).
} }
}); });
``` ```
* Playwright now runs on Ubuntu 22 amd64 and Ubuntu 22 arm64. We also publish new docker image `mcr.microsoft.com/playwright:v1.29.0-jammy`. * Playwright now runs on Ubuntu 22 amd64 and Ubuntu 22 arm64. We also publish new docker image `mcr.microsoft.com/playwright:v1.29.2-jammy`.
### ⚠️ Breaking Changes ⚠️ ### ⚠️ Breaking Changes ⚠️

View file

@ -4,6 +4,66 @@ title: "Release notes"
toc_max_heading_level: 2 toc_max_heading_level: 2
--- ---
## Version 1.29
### New APIs
- New method [`method: Route.fetch`] and new option `json` for [`method: Route.fulfill`]:
```python
def handle_route(route: Route):
# Fetch original settings.
response = route.fetch()
# Force settings theme to a predefined value.
json = response.json()
json["theme"] = "Solorized"
# Fulfill with modified data.
route.fulfill(json=json)
page.route("**/api/settings", handle_route)
```
- New method [`method: Locator.all`] to iterate over all matching elements:
```python
# Check all checkboxes!
checkboxes = page.get_by_role("checkbox")
for checkbox in checkboxes.all():
checkbox.check()
```
- [`method: Locator.selectOption`] matches now by value or label:
```html
<select multiple>
<option value="red">Red</div>
<option value="green">Green</div>
<option value="blue">Blue</div>
</select>
```
```python
element.select_option("Red")
```
### Miscellaneous
- Option `postData` in method [`method: Route.continue`] now supports [Serializable] values.
### Browser Versions
* Chromium 109.0.5414.46
* Mozilla Firefox 107.0
* WebKit 16.4
This version was also tested against the following stable channels:
* Google Chrome 108
* Microsoft Edge 108
## Version 1.28 ## Version 1.28
### Playwright Tools ### Playwright Tools
@ -122,7 +182,7 @@ This version was also tested against the following stable channels:
### Announcements ### Announcements
* 🎁 We now ship Ubuntu 22.04 Jammy Jellyfish docker image: `mcr.microsoft.com/playwright/python:v1.29.0-jammy`. * 🎁 We now ship Ubuntu 22.04 Jammy Jellyfish docker image: `mcr.microsoft.com/playwright/python:v1.29.2-jammy`.
* 🪦 This is the last release with macOS 10.15 support (deprecated as of 1.21). * 🪦 This is the last release with macOS 10.15 support (deprecated as of 1.21).
* ⚠️ Ubuntu 18 is now deprecated and will not be supported as of Dec 2022. * ⚠️ Ubuntu 18 is now deprecated and will not be supported as of Dec 2022.

View file

@ -56,7 +56,7 @@ The snapshot name `example-test-1-chromium-darwin.png` consists of a few parts:
If you are not on the same operating system as your CI system, you can use Docker to generate/update the screenshots: If you are not on the same operating system as your CI system, you can use Docker to generate/update the screenshots:
```bash ```bash
docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.29.0-focal /bin/bash docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.29.2-focal /bin/bash
npm install npm install
npx playwright test --update-snapshots npx playwright test --update-snapshots
``` ```

75
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "playwright-internal", "name": "playwright-internal",
"version": "1.29.0-next", "version": "1.29.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "playwright-internal", "name": "playwright-internal",
"version": "1.29.0-next", "version": "1.29.2",
"license": "Apache-2.0", "license": "Apache-2.0",
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
@ -3754,8 +3754,9 @@
"optional": true "optional": true
}, },
"node_modules/json5": { "node_modules/json5": {
"version": "2.2.1", "version": "2.2.2",
"license": "MIT", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
"integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==",
"bin": { "bin": {
"json5": "lib/cli.js" "json5": "lib/cli.js"
}, },
@ -5886,11 +5887,11 @@
"version": "0.0.0" "version": "0.0.0"
}, },
"packages/playwright": { "packages/playwright": {
"version": "1.29.0-next", "version": "1.29.2",
"hasInstallScript": true, "hasInstallScript": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -5900,11 +5901,11 @@
} }
}, },
"packages/playwright-chromium": { "packages/playwright-chromium": {
"version": "1.29.0-next", "version": "1.29.2",
"hasInstallScript": true, "hasInstallScript": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -5914,7 +5915,7 @@
} }
}, },
"packages/playwright-core": { "packages/playwright-core": {
"version": "1.29.0-next", "version": "1.29.2",
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -5925,10 +5926,10 @@
}, },
"packages/playwright-ct-react": { "packages/playwright-ct-react": {
"name": "@playwright/experimental-ct-react", "name": "@playwright/experimental-ct-react",
"version": "1.29.0-next", "version": "1.29.2",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"@vitejs/plugin-react": "^2.2.0", "@vitejs/plugin-react": "^2.2.0",
"vite": "^3.2.1" "vite": "^3.2.1"
}, },
@ -5965,10 +5966,10 @@
}, },
"packages/playwright-ct-solid": { "packages/playwright-ct-solid": {
"name": "@playwright/experimental-ct-solid", "name": "@playwright/experimental-ct-solid",
"version": "1.29.0-next", "version": "1.29.2",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"vite": "^3.2.1", "vite": "^3.2.1",
"vite-plugin-solid": "^2.3.10" "vite-plugin-solid": "^2.3.10"
}, },
@ -5981,10 +5982,10 @@
}, },
"packages/playwright-ct-svelte": { "packages/playwright-ct-svelte": {
"name": "@playwright/experimental-ct-svelte", "name": "@playwright/experimental-ct-svelte",
"version": "1.29.0-next", "version": "1.29.2",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"@sveltejs/vite-plugin-svelte": "^1.1.0", "@sveltejs/vite-plugin-svelte": "^1.1.0",
"vite": "^3.2.1" "vite": "^3.2.1"
}, },
@ -5997,10 +5998,10 @@
}, },
"packages/playwright-ct-vue": { "packages/playwright-ct-vue": {
"name": "@playwright/experimental-ct-vue", "name": "@playwright/experimental-ct-vue",
"version": "1.29.0-next", "version": "1.29.2",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"@vitejs/plugin-vue": "^3.2.0", "@vitejs/plugin-vue": "^3.2.0",
"vite": "^3.2.1" "vite": "^3.2.1"
}, },
@ -6046,10 +6047,10 @@
}, },
"packages/playwright-ct-vue2": { "packages/playwright-ct-vue2": {
"name": "@playwright/experimental-ct-vue2", "name": "@playwright/experimental-ct-vue2",
"version": "1.29.0-next", "version": "1.29.2",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"@vitejs/plugin-vue2": "^2.0.0", "@vitejs/plugin-vue2": "^2.0.0",
"vite": "^3.2.1" "vite": "^3.2.1"
}, },
@ -6061,11 +6062,11 @@
} }
}, },
"packages/playwright-firefox": { "packages/playwright-firefox": {
"version": "1.29.0-next", "version": "1.29.2",
"hasInstallScript": true, "hasInstallScript": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -6076,11 +6077,11 @@
}, },
"packages/playwright-test": { "packages/playwright-test": {
"name": "@playwright/test", "name": "@playwright/test",
"version": "1.29.0-next", "version": "1.29.2",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@types/node": "*", "@types/node": "*",
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -6090,11 +6091,11 @@
} }
}, },
"packages/playwright-webkit": { "packages/playwright-webkit": {
"version": "1.29.0-next", "version": "1.29.2",
"hasInstallScript": true, "hasInstallScript": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -6698,7 +6699,7 @@
"@playwright/experimental-ct-react": { "@playwright/experimental-ct-react": {
"version": "file:packages/playwright-ct-react", "version": "file:packages/playwright-ct-react",
"requires": { "requires": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"@vitejs/plugin-react": "^2.2.0", "@vitejs/plugin-react": "^2.2.0",
"vite": "^3.2.1" "vite": "^3.2.1"
}, },
@ -6725,7 +6726,7 @@
"@playwright/experimental-ct-solid": { "@playwright/experimental-ct-solid": {
"version": "file:packages/playwright-ct-solid", "version": "file:packages/playwright-ct-solid",
"requires": { "requires": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"solid-js": "^1.4.7", "solid-js": "^1.4.7",
"vite": "^3.2.1", "vite": "^3.2.1",
"vite-plugin-solid": "^2.3.10" "vite-plugin-solid": "^2.3.10"
@ -6734,7 +6735,7 @@
"@playwright/experimental-ct-svelte": { "@playwright/experimental-ct-svelte": {
"version": "file:packages/playwright-ct-svelte", "version": "file:packages/playwright-ct-svelte",
"requires": { "requires": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"@sveltejs/vite-plugin-svelte": "^1.1.0", "@sveltejs/vite-plugin-svelte": "^1.1.0",
"svelte": "^3.49.0", "svelte": "^3.49.0",
"vite": "^3.2.1" "vite": "^3.2.1"
@ -6743,7 +6744,7 @@
"@playwright/experimental-ct-vue": { "@playwright/experimental-ct-vue": {
"version": "file:packages/playwright-ct-vue", "version": "file:packages/playwright-ct-vue",
"requires": { "requires": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"@vitejs/plugin-vue": "^3.2.0", "@vitejs/plugin-vue": "^3.2.0",
"vite": "^3.2.1" "vite": "^3.2.1"
}, },
@ -6778,7 +6779,7 @@
"@playwright/experimental-ct-vue2": { "@playwright/experimental-ct-vue2": {
"version": "file:packages/playwright-ct-vue2", "version": "file:packages/playwright-ct-vue2",
"requires": { "requires": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"@vitejs/plugin-vue2": "^2.0.0", "@vitejs/plugin-vue2": "^2.0.0",
"vite": "^3.2.1", "vite": "^3.2.1",
"vue": "^2.7.13" "vue": "^2.7.13"
@ -6788,7 +6789,7 @@
"version": "file:packages/playwright-test", "version": "file:packages/playwright-test",
"requires": { "requires": {
"@types/node": "*", "@types/node": "*",
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
} }
}, },
"@rollup/pluginutils": { "@rollup/pluginutils": {
@ -8534,7 +8535,9 @@
"optional": true "optional": true
}, },
"json5": { "json5": {
"version": "2.2.1" "version": "2.2.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
"integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ=="
}, },
"jsonfile": { "jsonfile": {
"version": "4.0.0", "version": "4.0.0",
@ -8899,13 +8902,13 @@
"playwright": { "playwright": {
"version": "file:packages/playwright", "version": "file:packages/playwright",
"requires": { "requires": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
} }
}, },
"playwright-chromium": { "playwright-chromium": {
"version": "file:packages/playwright-chromium", "version": "file:packages/playwright-chromium",
"requires": { "requires": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
} }
}, },
"playwright-core": { "playwright-core": {
@ -8914,13 +8917,13 @@
"playwright-firefox": { "playwright-firefox": {
"version": "file:packages/playwright-firefox", "version": "file:packages/playwright-firefox",
"requires": { "requires": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
} }
}, },
"playwright-webkit": { "playwright-webkit": {
"version": "file:packages/playwright-webkit", "version": "file:packages/playwright-webkit",
"requires": { "requires": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
} }
}, },
"postcss": { "postcss": {

View file

@ -1,7 +1,7 @@
{ {
"name": "playwright-internal", "name": "playwright-internal",
"private": true, "private": true,
"version": "1.29.0-next", "version": "1.29.2",
"description": "A high-level API to automate web browsers", "description": "A high-level API to automate web browsers",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",

View file

@ -1,6 +1,6 @@
{ {
"name": "playwright-chromium", "name": "playwright-chromium",
"version": "1.29.0-next", "version": "1.29.2",
"description": "A high-level API to automate Chromium", "description": "A high-level API to automate Chromium",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",
@ -28,6 +28,6 @@
"install": "node install.js" "install": "node install.js"
}, },
"dependencies": { "dependencies": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
} }
} }

View file

@ -3,13 +3,13 @@
"browsers": [ "browsers": [
{ {
"name": "chromium", "name": "chromium",
"revision": "1040", "revision": "1041",
"installByDefault": true, "installByDefault": true,
"browserVersion": "109.0.5414.46" "browserVersion": "109.0.5414.46"
}, },
{ {
"name": "chromium-with-symbols", "name": "chromium-with-symbols",
"revision": "1040", "revision": "1041",
"installByDefault": false, "installByDefault": false,
"browserVersion": "109.0.5414.46" "browserVersion": "109.0.5414.46"
}, },

View file

@ -1,6 +1,6 @@
{ {
"name": "playwright-core", "name": "playwright-core",
"version": "1.29.0-next", "version": "1.29.2",
"description": "A high-level API to automate web browsers", "description": "A high-level API to automate web browsers",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",

View file

@ -37,8 +37,9 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher {
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> { async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> {
const playwright = createPlaywright('javascript'); const playwright = createPlaywright('javascript');
const socksProxy = new SocksProxy(); // TODO: enable socks proxy once ipv6 is supported.
playwright.options.socksProxyPort = await socksProxy.listen(0); const socksProxy = false ? new SocksProxy() : undefined;
playwright.options.socksProxyPort = await socksProxy?.listen(0);
// 1. Pre-launch the browser // 1. Pre-launch the browser
const metadata = serverSideCallMetadata(); const metadata = serverSideCallMetadata();
@ -68,7 +69,7 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher {
(browserServer as any)._disconnectForTest = () => server.close(); (browserServer as any)._disconnectForTest = () => server.close();
(browserServer as any)._userDataDirForTest = (browser as any)._userDataDirForTest; (browserServer as any)._userDataDirForTest = (browser as any)._userDataDirForTest;
browser.options.browserProcess.onclose = (exitCode, signal) => { browser.options.browserProcess.onclose = (exitCode, signal) => {
socksProxy.close().catch(() => {}); socksProxy?.close().catch(() => {});
server.close(); server.close();
browserServer.emit('close', exitCode, signal); browserServer.emit('close', exitCode, signal);
}; };

View file

@ -62,6 +62,7 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
readonly _context: BrowserContext; readonly _context: BrowserContext;
private _windows = new Set<Page>(); private _windows = new Set<Page>();
private _timeoutSettings = new TimeoutSettings(); private _timeoutSettings = new TimeoutSettings();
private _isClosed = false;
static from(electronApplication: channels.ElectronApplicationChannel): ElectronApplication { static from(electronApplication: channels.ElectronApplicationChannel): ElectronApplication {
return (electronApplication as any)._object; return (electronApplication as any)._object;
@ -73,7 +74,10 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
for (const page of this._context._pages) for (const page of this._context._pages)
this._onPage(page); this._onPage(page);
this._context.on(Events.BrowserContext.Page, page => this._onPage(page)); this._context.on(Events.BrowserContext.Page, page => this._onPage(page));
this._channel.on('close', () => this.emit(Events.ElectronApplication.Close)); this._channel.on('close', () => {
this._isClosed = true;
this.emit(Events.ElectronApplication.Close);
});
} }
process(): childProcess.ChildProcess { process(): childProcess.ChildProcess {
@ -102,6 +106,8 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
} }
async close() { async close() {
if (this._isClosed)
return;
await this._channel.close(); await this._channel.close();
} }

View file

@ -15,6 +15,7 @@
*/ */
const { app } = require('electron'); const { app } = require('electron');
const fs = require('fs');
const path = require('path'); const path = require('path');
const { chromiumSwitches } = require('../chromium/chromiumSwitches'); const { chromiumSwitches } = require('../chromium/chromiumSwitches');
@ -31,27 +32,36 @@ for (const arg of chromiumSwitches) {
app.commandLine.appendSwitch(match[1], match[2]); app.commandLine.appendSwitch(match[1], match[2]);
} }
app.getAppPath = () => path.dirname(appPath); // Defer ready event.
const originalWhenReady = app.whenReady();
const originalEmit = app.emit.bind(app);
let readyEventArgs: any[];
app.emit = (event: string | symbol, ...args: any[]): boolean => {
if (event === 'ready') {
readyEventArgs = args;
return app.listenerCount('ready') > 0;
}
return originalEmit(event, ...args);
};
let launchInfoEventPayload: any; app.getAppPath = () => {
app.on('ready', launchInfo => launchInfoEventPayload = launchInfo); if (fs.statSync(appPath).isFile())
return path.dirname(appPath);
return appPath;
};
let isReady = false;
let whenReadyCallback: (event: any) => any;
const whenReadyPromise = new Promise<void>(f => whenReadyCallback = f);
app.isReady = () => isReady;
app.whenReady = () => whenReadyPromise;
require(appPath);
(globalThis as any).__playwright_run = async () => { (globalThis as any).__playwright_run = async () => {
// Wait for app to be ready to avoid browser initialization races. // Wait for app to be ready to avoid browser initialization races.
await app.whenReady(); const event = await originalWhenReady;
// Override isReady pipeline.
let isReady = false;
let whenReadyCallback: () => void;
const whenReadyPromise = new Promise<void>(f => whenReadyCallback = f);
app.isReady = () => isReady;
app.whenReady = () => whenReadyPromise;
require(appPath);
// Trigger isReady.
isReady = true; isReady = true;
whenReadyCallback!(); whenReadyCallback(event);
app.emit('will-finish-launching'); originalEmit('ready', ...readyEventArgs);
app.emit('ready', launchInfoEventPayload);
}; };

View file

@ -78,8 +78,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined, '<unknown>': undefined,
'generic-linux': 'builds/chromium/%s/chromium-linux.zip', 'generic-linux': 'builds/chromium/%s/chromium-linux.zip',
'generic-linux-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip', 'generic-linux-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
'ubuntu18.04': 'builds/chromium/%s/chromium-linux.zip',
'ubuntu20.04': 'builds/chromium/%s/chromium-linux.zip', 'ubuntu20.04': 'builds/chromium/%s/chromium-linux.zip',
'ubuntu22.04': 'builds/chromium/%s/chromium-linux.zip', 'ubuntu22.04': 'builds/chromium/%s/chromium-linux.zip',
'ubuntu18.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip', 'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip', 'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
'debian11': 'builds/chromium/%s/chromium-linux.zip', 'debian11': 'builds/chromium/%s/chromium-linux.zip',
@ -96,8 +98,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined, '<unknown>': undefined,
'generic-linux': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip', 'generic-linux': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
'generic-linux-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip', 'generic-linux-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
'ubuntu18.04': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
'ubuntu20.04': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip', 'ubuntu20.04': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
'ubuntu22.04': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip', 'ubuntu22.04': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
'ubuntu18.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
'ubuntu20.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip', 'ubuntu20.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
'ubuntu22.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip', 'ubuntu22.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
'debian11': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip', 'debian11': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
@ -114,8 +118,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined, '<unknown>': undefined,
'generic-linux': 'builds/chromium/%s/chromium-with-symbols-linux.zip', 'generic-linux': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
'generic-linux-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip', 'generic-linux-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
'ubuntu18.04': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
'ubuntu20.04': 'builds/chromium/%s/chromium-with-symbols-linux.zip', 'ubuntu20.04': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
'ubuntu22.04': 'builds/chromium/%s/chromium-with-symbols-linux.zip', 'ubuntu22.04': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
'ubuntu18.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip', 'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip', 'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
'debian11': 'builds/chromium/%s/chromium-with-symbols-linux.zip', 'debian11': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
@ -132,8 +138,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined, '<unknown>': undefined,
'generic-linux': 'builds/firefox/%s/firefox-ubuntu-20.04.zip', 'generic-linux': 'builds/firefox/%s/firefox-ubuntu-20.04.zip',
'generic-linux-arm64': 'builds/firefox/%s/firefox-ubuntu-20.04-arm64.zip', 'generic-linux-arm64': 'builds/firefox/%s/firefox-ubuntu-20.04-arm64.zip',
'ubuntu18.04': 'builds/firefox/%s/firefox-ubuntu-18.04.zip',
'ubuntu20.04': 'builds/firefox/%s/firefox-ubuntu-20.04.zip', 'ubuntu20.04': 'builds/firefox/%s/firefox-ubuntu-20.04.zip',
'ubuntu22.04': 'builds/firefox/%s/firefox-ubuntu-22.04.zip', 'ubuntu22.04': 'builds/firefox/%s/firefox-ubuntu-22.04.zip',
'ubuntu18.04-arm64': undefined,
'ubuntu20.04-arm64': 'builds/firefox/%s/firefox-ubuntu-20.04-arm64.zip', 'ubuntu20.04-arm64': 'builds/firefox/%s/firefox-ubuntu-20.04-arm64.zip',
'ubuntu22.04-arm64': 'builds/firefox/%s/firefox-ubuntu-22.04-arm64.zip', 'ubuntu22.04-arm64': 'builds/firefox/%s/firefox-ubuntu-22.04-arm64.zip',
'debian11': 'builds/firefox/%s/firefox-debian-11.zip', 'debian11': 'builds/firefox/%s/firefox-debian-11.zip',
@ -150,8 +158,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined, '<unknown>': undefined,
'generic-linux': 'builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip', 'generic-linux': 'builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip',
'generic-linux-arm64': undefined, 'generic-linux-arm64': undefined,
'ubuntu18.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-18.04.zip',
'ubuntu20.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip', 'ubuntu20.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip',
'ubuntu22.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-22.04.zip', 'ubuntu22.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-22.04.zip',
'ubuntu18.04-arm64': undefined,
'ubuntu20.04-arm64': undefined, 'ubuntu20.04-arm64': undefined,
'ubuntu22.04-arm64': 'builds/firefox-beta/%s/firefox-beta-ubuntu-22.04-arm64.zip', 'ubuntu22.04-arm64': 'builds/firefox-beta/%s/firefox-beta-ubuntu-22.04-arm64.zip',
'debian11': 'builds/firefox-beta/%s/firefox-beta-debian-11.zip', 'debian11': 'builds/firefox-beta/%s/firefox-beta-debian-11.zip',
@ -168,8 +178,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined, '<unknown>': undefined,
'generic-linux': 'builds/webkit/%s/webkit-ubuntu-20.04.zip', 'generic-linux': 'builds/webkit/%s/webkit-ubuntu-20.04.zip',
'generic-linux-arm64': 'builds/webkit/%s/webkit-ubuntu-20.04-arm64.zip', 'generic-linux-arm64': 'builds/webkit/%s/webkit-ubuntu-20.04-arm64.zip',
'ubuntu18.04': 'builds/deprecated-webkit-ubuntu-18.04/%s/deprecated-webkit-ubuntu-18.04.zip',
'ubuntu20.04': 'builds/webkit/%s/webkit-ubuntu-20.04.zip', 'ubuntu20.04': 'builds/webkit/%s/webkit-ubuntu-20.04.zip',
'ubuntu22.04': 'builds/webkit/%s/webkit-ubuntu-22.04.zip', 'ubuntu22.04': 'builds/webkit/%s/webkit-ubuntu-22.04.zip',
'ubuntu18.04-arm64': undefined,
'ubuntu20.04-arm64': 'builds/webkit/%s/webkit-ubuntu-20.04-arm64.zip', 'ubuntu20.04-arm64': 'builds/webkit/%s/webkit-ubuntu-20.04-arm64.zip',
'ubuntu22.04-arm64': 'builds/webkit/%s/webkit-ubuntu-22.04-arm64.zip', 'ubuntu22.04-arm64': 'builds/webkit/%s/webkit-ubuntu-22.04-arm64.zip',
'debian11': 'builds/webkit/%s/webkit-debian-11.zip', 'debian11': 'builds/webkit/%s/webkit-debian-11.zip',
@ -186,8 +198,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined, '<unknown>': undefined,
'generic-linux': 'builds/ffmpeg/%s/ffmpeg-linux.zip', 'generic-linux': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
'generic-linux-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip', 'generic-linux-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
'ubuntu18.04': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
'ubuntu20.04': 'builds/ffmpeg/%s/ffmpeg-linux.zip', 'ubuntu20.04': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
'ubuntu22.04': 'builds/ffmpeg/%s/ffmpeg-linux.zip', 'ubuntu22.04': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
'ubuntu18.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
'ubuntu20.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip', 'ubuntu20.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
'ubuntu22.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip', 'ubuntu22.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
'debian11': 'builds/ffmpeg/%s/ffmpeg-linux.zip', 'debian11': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
@ -640,7 +654,7 @@ export class Registry {
private async _validateHostRequirements(sdkLanguage: string, browserName: BrowserName, browserDirectory: string, linuxLddDirectories: string[], dlOpenLibraries: string[], windowsExeAndDllDirectories: string[]) { private async _validateHostRequirements(sdkLanguage: string, browserName: BrowserName, browserDirectory: string, linuxLddDirectories: string[], dlOpenLibraries: string[], windowsExeAndDllDirectories: string[]) {
if (getAsBooleanFromENV('PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS')) { if (getAsBooleanFromENV('PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS')) {
process.stdout.write('Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n'); process.stderr.write('Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n');
return; return;
} }
const distributionInfo = await getLinuxDistributionInfo(); const distributionInfo = await getLinuxDistributionInfo();

View file

@ -19,6 +19,168 @@
// ./utils/linux-browser-dependencies/run.sh ubuntu:20.04 // ./utils/linux-browser-dependencies/run.sh ubuntu:20.04
export const deps: any = { export const deps: any = {
'ubuntu18.04': {
tools: [
'xvfb',
'fonts-noto-color-emoji',
'ttf-unifont',
'libfontconfig',
'libfreetype6',
'xfonts-cyrillic',
'xfonts-scalable',
'fonts-liberation',
'fonts-ipafont-gothic',
'fonts-wqy-zenhei',
'fonts-tlwg-loma-otf',
'ttf-ubuntu-font-family',
],
chromium: [
'fonts-liberation',
'libasound2',
'libatk-bridge2.0-0',
'libatk1.0-0',
'libatspi2.0-0',
'libcairo2',
'libcups2',
'libdbus-1-3',
'libdrm2',
'libegl1',
'libgbm1',
'libglib2.0-0',
'libgtk-3-0',
'libnspr4',
'libnss3',
'libpango-1.0-0',
'libx11-6',
'libx11-xcb1',
'libxcb1',
'libxcomposite1',
'libxdamage1',
'libxext6',
'libxfixes3',
'libxrandr2',
'libxshmfence1',
],
firefox: [
'ffmpeg',
'libatk1.0-0',
'libcairo-gobject2',
'libcairo2',
'libdbus-1-3',
'libdbus-glib-1-2',
'libfontconfig1',
'libfreetype6',
'libgdk-pixbuf2.0-0',
'libglib2.0-0',
'libgtk-3-0',
'libpango-1.0-0',
'libpangocairo-1.0-0',
'libpangoft2-1.0-0',
'libx11-6',
'libx11-xcb1',
'libxcb-shm0',
'libxcb1',
'libxcomposite1',
'libxcursor1',
'libxdamage1',
'libxext6',
'libxfixes3',
'libxi6',
'libxrender1',
'libxt6',
'libxtst6',
],
webkit: [],
lib2package: {
'libasound.so.2': 'libasound2',
'libatk-1.0.so.0': 'libatk1.0-0',
'libatk-bridge-2.0.so.0': 'libatk-bridge2.0-0',
'libatspi.so.0': 'libatspi2.0-0',
'libbrotlidec.so.1': 'libbrotli1',
'libcairo-gobject.so.2': 'libcairo-gobject2',
'libcairo.so.2': 'libcairo2',
'libcups.so.2': 'libcups2',
'libdbus-1.so.3': 'libdbus-1-3',
'libdbus-glib-1.so.2': 'libdbus-glib-1-2',
'libdrm.so.2': 'libdrm2',
'libEGL.so.1': 'libegl1',
'libenchant.so.1': 'libenchant1c2a',
'libepoxy.so.0': 'libepoxy0',
'libevent-2.1.so.6': 'libevent-2.1-6',
'libevdev.so.2': 'libevdev2',
'libfontconfig.so.1': 'libfontconfig1',
'libfreetype.so.6': 'libfreetype6',
'libgbm.so.1': 'libgbm1',
'libgdk_pixbuf-2.0.so.0': 'libgdk-pixbuf2.0-0',
'libgdk-3.so.0': 'libgtk-3-0',
'libgdk-x11-2.0.so.0': 'libgtk2.0-0',
'libgio-2.0.so.0': 'libglib2.0-0',
'libGL.so.1': 'libgl1',
'libGLESv2.so.2': 'libgles2',
'libglib-2.0.so.0': 'libglib2.0-0',
'libgmodule-2.0.so.0': 'libglib2.0-0',
'libgobject-2.0.so.0': 'libglib2.0-0',
'libgstapp-1.0.so.0': 'gstreamer1.0-plugins-base',
'libgstaudio-1.0.so.0': 'gstreamer1.0-plugins-base',
'libgstbase-1.0.so.0': 'libgstreamer1.0-0',
'libgstcodecparsers-1.0.so.0': 'gstreamer1.0-plugins-bad',
'libgstfft-1.0.so.0': 'gstreamer1.0-plugins-base',
'libgstgl-1.0.so.0': 'libgstreamer-gl1.0-0',
'libgstpbutils-1.0.so.0': 'gstreamer1.0-plugins-base',
'libgstreamer-1.0.so.0': 'libgstreamer1.0-0',
'libgsttag-1.0.so.0': 'gstreamer1.0-plugins-base',
'libgstvideo-1.0.so.0': 'gstreamer1.0-plugins-base',
'libgthread-2.0.so.0': 'libglib2.0-0',
'libgtk-3.so.0': 'libgtk-3-0',
'libgtk-x11-2.0.so.0': 'libgtk2.0-0',
'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',
'libharfbuzz.so.0': 'libharfbuzz0b',
'libhyphen.so.0': 'libhyphen0',
'libicudata.so.60': 'libicu60',
'libicui18n.so.60': 'libicu60',
'libicuuc.so.60': 'libicu60',
'libjpeg.so.8': 'libjpeg-turbo8',
'libnotify.so.4': 'libnotify4',
'libnspr4.so': 'libnspr4',
'libnss3.so': 'libnss3',
'libnssutil3.so': 'libnss3',
'libopenjp2.so.7': 'libopenjp2-7',
'libopus.so.0': 'libopus0',
'libpango-1.0.so.0': 'libpango-1.0-0',
'libpangocairo-1.0.so.0': 'libpangocairo-1.0-0',
'libpangoft2-1.0.so.0': 'libpangoft2-1.0-0',
'libpng16.so.16': 'libpng16-16',
'libsecret-1.so.0': 'libsecret-1-0',
'libsmime3.so': 'libnss3',
'libvpx.so.5': 'libvpx5',
'libwayland-client.so.0': 'libwayland-client0',
'libwayland-egl.so.1': 'libwayland-egl1',
'libwayland-server.so.0': 'libwayland-server0',
'libwebp.so.6': 'libwebp6',
'libwebpdemux.so.2': 'libwebpdemux2',
'libwoff2dec.so.1.0.2': 'libwoff1',
'libX11-xcb.so.1': 'libx11-xcb1',
'libX11.so.6': 'libx11-6',
'libxcb-dri3.so.0': 'libxcb-dri3-0',
'libxcb-shm.so.0': 'libxcb-shm0',
'libxcb.so.1': 'libxcb1',
'libXcomposite.so.1': 'libxcomposite1',
'libXcursor.so.1': 'libxcursor1',
'libXdamage.so.1': 'libxdamage1',
'libXext.so.6': 'libxext6',
'libXfixes.so.3': 'libxfixes3',
'libXi.so.6': 'libxi6',
'libxkbcommon.so.0': 'libxkbcommon0',
'libxml2.so.2': 'libxml2',
'libXrandr.so.2': 'libxrandr2',
'libXrender.so.1': 'libxrender1',
'libxslt.so.1': 'libxslt1.1',
'libXt.so.6': 'libxt6',
'libXtst.so.6': 'libxtst6',
'libevent-2.1-6': 'libevent-2.1-6',
},
},
'ubuntu20.04': { 'ubuntu20.04': {
tools: [ tools: [
'xvfb', 'xvfb',

View file

@ -23,6 +23,7 @@ export type HostPlatform = 'win64' |
'mac10.15' | 'mac10.15' |
'mac11' | 'mac11-arm64' | 'mac11' | 'mac11-arm64' |
'mac12' | 'mac12-arm64' | 'mac12' | 'mac12-arm64' |
'ubuntu18.04' | 'ubuntu18.04-arm64' |
'ubuntu20.04' | 'ubuntu20.04-arm64' | 'ubuntu20.04' | 'ubuntu20.04-arm64' |
'ubuntu22.04' | 'ubuntu22.04-arm64' | 'ubuntu22.04' | 'ubuntu22.04-arm64' |
'debian11' | 'debian11' |

View file

@ -286,7 +286,8 @@ export interface Page {
addInitScript<Arg>(script: PageFunction<Arg, any> | { path?: string, content?: string }, arg?: Arg): Promise<void>; addInitScript<Arg>(script: PageFunction<Arg, any> | { path?: string, content?: string }, arg?: Arg): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Page.locator`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [page.locator(selector[, options])](https://playwright.dev/docs/api/class-page#page-locator)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* The method finds an element matching the specified selector within the page. If no elements match the selector, the * The method finds an element matching the specified selector within the page. If no elements match the selector, the
* return value resolves to `null`. To wait for an element on the page, use * return value resolves to `null`. To wait for an element on the page, use
@ -296,7 +297,8 @@ export interface Page {
*/ */
$<K extends keyof HTMLElementTagNameMap>(selector: K, options?: { strict: boolean }): Promise<ElementHandleForTag<K> | null>; $<K extends keyof HTMLElementTagNameMap>(selector: K, options?: { strict: boolean }): Promise<ElementHandleForTag<K> | null>;
/** /**
* **NOTE** Use locator-based [`method: Page.locator`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [page.locator(selector[, options])](https://playwright.dev/docs/api/class-page#page-locator)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* The method finds an element matching the specified selector within the page. If no elements match the selector, the * The method finds an element matching the specified selector within the page. If no elements match the selector, the
* return value resolves to `null`. To wait for an element on the page, use * return value resolves to `null`. To wait for an element on the page, use
@ -307,7 +309,8 @@ export interface Page {
$(selector: string, options?: { strict: boolean }): Promise<ElementHandle<SVGElement | HTMLElement> | null>; $(selector: string, options?: { strict: boolean }): Promise<ElementHandle<SVGElement | HTMLElement> | null>;
/** /**
* **NOTE** Use locator-based [`method: Page.locator`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [page.locator(selector[, options])](https://playwright.dev/docs/api/class-page#page-locator)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* The method finds all elements matching the specified selector within the page. If no elements match the selector, * The method finds all elements matching the specified selector within the page. If no elements match the selector,
* the return value resolves to `[]`. * the return value resolves to `[]`.
@ -315,7 +318,8 @@ export interface Page {
*/ */
$$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K>[]>; $$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K>[]>;
/** /**
* **NOTE** Use locator-based [`method: Page.locator`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [page.locator(selector[, options])](https://playwright.dev/docs/api/class-page#page-locator)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* The method finds all elements matching the specified selector within the page. If no elements match the selector, * The method finds all elements matching the specified selector within the page. If no elements match the selector,
* the return value resolves to `[]`. * the return value resolves to `[]`.
@ -325,7 +329,9 @@ export interface Page {
/** /**
* **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests. * **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests.
* Use [`method: Locator.evaluate`], other [Locator] helper methods or web-first assertions instead. * Use
* [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate),
* other [Locator] helper methods or web-first assertions instead.
* *
* The method finds an element matching the specified selector within the page and passes it as a first argument to * The method finds an element matching the specified selector within the page and passes it as a first argument to
* `pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`. * `pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`.
@ -352,7 +358,9 @@ export interface Page {
$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], Arg, R>, arg: Arg): Promise<R>; $eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], Arg, R>, arg: Arg): Promise<R>;
/** /**
* **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests. * **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests.
* Use [`method: Locator.evaluate`], other [Locator] helper methods or web-first assertions instead. * Use
* [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate),
* other [Locator] helper methods or web-first assertions instead.
* *
* The method finds an element matching the specified selector within the page and passes it as a first argument to * The method finds an element matching the specified selector within the page and passes it as a first argument to
* `pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`. * `pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`.
@ -379,7 +387,9 @@ export interface Page {
$eval<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E, Arg, R>, arg: Arg): Promise<R>; $eval<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E, Arg, R>, arg: Arg): Promise<R>;
/** /**
* **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests. * **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests.
* Use [`method: Locator.evaluate`], other [Locator] helper methods or web-first assertions instead. * Use
* [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate),
* other [Locator] helper methods or web-first assertions instead.
* *
* The method finds an element matching the specified selector within the page and passes it as a first argument to * The method finds an element matching the specified selector within the page and passes it as a first argument to
* `pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`. * `pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`.
@ -406,7 +416,9 @@ export interface Page {
$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], void, R>, arg?: any): Promise<R>; $eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], void, R>, arg?: any): Promise<R>;
/** /**
* **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests. * **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests.
* Use [`method: Locator.evaluate`], other [Locator] helper methods or web-first assertions instead. * Use
* [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate),
* other [Locator] helper methods or web-first assertions instead.
* *
* The method finds an element matching the specified selector within the page and passes it as a first argument to * The method finds an element matching the specified selector within the page and passes it as a first argument to
* `pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`. * `pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`.
@ -433,8 +445,9 @@ export interface Page {
$eval<R, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E, void, R>, arg?: any): Promise<R>; $eval<R, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E, void, R>, arg?: any): Promise<R>;
/** /**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better * **NOTE** In most cases,
* job. * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all),
* other [Locator] helper methods and web-first assertions do a better job.
* *
* The method finds all elements matching the specified selector within the page and passes an array of matched * The method finds all elements matching the specified selector within the page and passes an array of matched
* elements as a first argument to `pageFunction`. Returns the result of `pageFunction` invocation. * elements as a first argument to `pageFunction`. Returns the result of `pageFunction` invocation.
@ -455,8 +468,9 @@ export interface Page {
*/ */
$$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], Arg, R>, arg: Arg): Promise<R>; $$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], Arg, R>, arg: Arg): Promise<R>;
/** /**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better * **NOTE** In most cases,
* job. * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all),
* other [Locator] helper methods and web-first assertions do a better job.
* *
* The method finds all elements matching the specified selector within the page and passes an array of matched * The method finds all elements matching the specified selector within the page and passes an array of matched
* elements as a first argument to `pageFunction`. Returns the result of `pageFunction` invocation. * elements as a first argument to `pageFunction`. Returns the result of `pageFunction` invocation.
@ -477,8 +491,9 @@ export interface Page {
*/ */
$$eval<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E[], Arg, R>, arg: Arg): Promise<R>; $$eval<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E[], Arg, R>, arg: Arg): Promise<R>;
/** /**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better * **NOTE** In most cases,
* job. * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all),
* other [Locator] helper methods and web-first assertions do a better job.
* *
* The method finds all elements matching the specified selector within the page and passes an array of matched * The method finds all elements matching the specified selector within the page and passes an array of matched
* elements as a first argument to `pageFunction`. Returns the result of `pageFunction` invocation. * elements as a first argument to `pageFunction`. Returns the result of `pageFunction` invocation.
@ -499,8 +514,9 @@ export interface Page {
*/ */
$$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], void, R>, arg?: any): Promise<R>; $$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], void, R>, arg?: any): Promise<R>;
/** /**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better * **NOTE** In most cases,
* job. * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all),
* other [Locator] helper methods and web-first assertions do a better job.
* *
* The method finds all elements matching the specified selector within the page and passes an array of matched * The method finds all elements matching the specified selector within the page and passes an array of matched
* elements as a first argument to `pageFunction`. Returns the result of `pageFunction` invocation. * elements as a first argument to `pageFunction`. Returns the result of `pageFunction` invocation.
@ -1797,7 +1813,8 @@ export interface Page {
bringToFront(): Promise<void>; bringToFront(): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.check`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.check([options])](https://playwright.dev/docs/api/class-locator#locator-check) instead.
* Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method checks an element matching `selector` by performing the following steps: * This method checks an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -1862,7 +1879,8 @@ export interface Page {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.click`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.click([options])](https://playwright.dev/docs/api/class-locator#locator-click) instead.
* Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method clicks an element matching `selector` by performing the following steps: * This method clicks an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -1980,7 +1998,8 @@ export interface Page {
coverage: Coverage; coverage: Coverage;
/** /**
* **NOTE** Use locator-based [`method: Locator.dblclick`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.dblclick([options])](https://playwright.dev/docs/api/class-locator#locator-dblclick)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method double clicks an element matching `selector` by performing the following steps: * This method double clicks an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -2061,7 +2080,9 @@ export interface Page {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.dispatchEvent`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.dispatchEvent(type[, eventInit, options])](https://playwright.dev/docs/api/class-locator#locator-dispatch-event)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the element, * The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the element,
* `click` is dispatched. This is equivalent to calling * `click` is dispatched. This is equivalent to calling
@ -2298,7 +2319,8 @@ export interface Page {
exposeFunction(name: string, callback: Function): Promise<void>; exposeFunction(name: string, callback: Function): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.fill`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.fill(value[, options])](https://playwright.dev/docs/api/class-locator#locator-fill)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method waits for an element matching `selector`, waits for [actionability](https://playwright.dev/docs/actionability) checks, * This method waits for an element matching `selector`, waits for [actionability](https://playwright.dev/docs/actionability) checks,
* focuses the element, fills it and triggers an `input` event after filling. Note that you can pass an empty string * focuses the element, fills it and triggers an `input` event after filling. Note that you can pass an empty string
@ -2345,7 +2367,8 @@ export interface Page {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.focus`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.focus([options])](https://playwright.dev/docs/api/class-locator#locator-focus) instead.
* Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method fetches an element with `selector` and focuses it. If there's no element matching `selector`, the * This method fetches an element with `selector` and focuses it. If there's no element matching `selector`, the
* method waits until a matching element appears in the DOM. * method waits until a matching element appears in the DOM.
@ -2420,7 +2443,9 @@ export interface Page {
frames(): Array<Frame>; frames(): Array<Frame>;
/** /**
* **NOTE** Use locator-based [`method: Locator.getAttribute`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.getAttribute(name[, options])](https://playwright.dev/docs/api/class-locator#locator-get-attribute)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns element attribute value. * Returns element attribute value.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -2779,7 +2804,8 @@ export interface Page {
}): Promise<null|Response>; }): Promise<null|Response>;
/** /**
* **NOTE** Use locator-based [`method: Locator.hover`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.hover([options])](https://playwright.dev/docs/api/class-locator#locator-hover) instead.
* Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method hovers over an element matching `selector` by performing the following steps: * This method hovers over an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -2847,7 +2873,8 @@ export interface Page {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.innerHTML`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.innerHTML([options])](https://playwright.dev/docs/api/class-locator#locator-inner-html)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns `element.innerHTML`. * Returns `element.innerHTML`.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -2871,7 +2898,8 @@ export interface Page {
}): Promise<string>; }): Promise<string>;
/** /**
* **NOTE** Use locator-based [`method: Locator.innerText`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.innerText([options])](https://playwright.dev/docs/api/class-locator#locator-inner-text)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns `element.innerText`. * Returns `element.innerText`.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -2895,7 +2923,9 @@ export interface Page {
}): Promise<string>; }): Promise<string>;
/** /**
* **NOTE** Use locator-based [`method: Locator.inputValue`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.inputValue([options])](https://playwright.dev/docs/api/class-locator#locator-input-value) instead. Read
* more about [locators](https://playwright.dev/docs/locators).
* *
* Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element. * Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element.
* *
@ -2923,7 +2953,8 @@ export interface Page {
}): Promise<string>; }): Promise<string>;
/** /**
* **NOTE** Use locator-based [`method: Locator.isChecked`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.isChecked([options])](https://playwright.dev/docs/api/class-locator#locator-is-checked)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is checked. Throws if the element is not a checkbox or radio input. * Returns whether the element is checked. Throws if the element is not a checkbox or radio input.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -2952,7 +2983,9 @@ export interface Page {
isClosed(): boolean; isClosed(): boolean;
/** /**
* **NOTE** Use locator-based [`method: Locator.isDisabled`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.isDisabled([options])](https://playwright.dev/docs/api/class-locator#locator-is-disabled) instead. Read
* more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is disabled, the opposite of [enabled](https://playwright.dev/docs/actionability#enabled). * Returns whether the element is disabled, the opposite of [enabled](https://playwright.dev/docs/actionability#enabled).
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -2976,7 +3009,9 @@ export interface Page {
}): Promise<boolean>; }): Promise<boolean>;
/** /**
* **NOTE** Use locator-based [`method: Locator.isEditable`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.isEditable([options])](https://playwright.dev/docs/api/class-locator#locator-is-editable) instead. Read
* more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is [editable](https://playwright.dev/docs/actionability#editable). * Returns whether the element is [editable](https://playwright.dev/docs/actionability#editable).
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -3000,7 +3035,8 @@ export interface Page {
}): Promise<boolean>; }): Promise<boolean>;
/** /**
* **NOTE** Use locator-based [`method: Locator.isEnabled`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.isEnabled([options])](https://playwright.dev/docs/api/class-locator#locator-is-enabled)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is [enabled](https://playwright.dev/docs/actionability#enabled). * Returns whether the element is [enabled](https://playwright.dev/docs/actionability#enabled).
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -3024,7 +3060,8 @@ export interface Page {
}): Promise<boolean>; }): Promise<boolean>;
/** /**
* **NOTE** Use locator-based [`method: Locator.isHidden`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.isHidden([options])](https://playwright.dev/docs/api/class-locator#locator-is-hidden)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is hidden, the opposite of [visible](https://playwright.dev/docs/actionability#visible). `selector` that * Returns whether the element is hidden, the opposite of [visible](https://playwright.dev/docs/actionability#visible). `selector` that
* does not match any elements is considered hidden. * does not match any elements is considered hidden.
@ -3040,14 +3077,16 @@ export interface Page {
strict?: boolean; strict?: boolean;
/** /**
* @deprecated This option is ignored. [`method: Page.isHidden`] does not wait for the element to become hidden and returns * @deprecated This option is ignored.
* immediately. * [page.isHidden(selector[, options])](https://playwright.dev/docs/api/class-page#page-is-hidden) does not wait for
* the element to become hidden and returns immediately.
*/ */
timeout?: number; timeout?: number;
}): Promise<boolean>; }): Promise<boolean>;
/** /**
* **NOTE** Use locator-based [`method: Locator.isVisible`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.isVisible([options])](https://playwright.dev/docs/api/class-locator#locator-is-visible)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is [visible](https://playwright.dev/docs/actionability#visible). `selector` that does not match any elements * Returns whether the element is [visible](https://playwright.dev/docs/actionability#visible). `selector` that does not match any elements
* is considered not visible. * is considered not visible.
@ -3063,8 +3102,9 @@ export interface Page {
strict?: boolean; strict?: boolean;
/** /**
* @deprecated This option is ignored. [`method: Page.isVisible`] does not wait for the element to become visible and returns * @deprecated This option is ignored.
* immediately. * [page.isVisible(selector[, options])](https://playwright.dev/docs/api/class-page#page-is-visible) does not wait for
* the element to become visible and returns immediately.
*/ */
timeout?: number; timeout?: number;
}): Promise<boolean>; }): Promise<boolean>;
@ -3269,7 +3309,8 @@ export interface Page {
}): Promise<Buffer>; }): Promise<Buffer>;
/** /**
* **NOTE** Use locator-based [`method: Locator.press`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.press(key[, options])](https://playwright.dev/docs/api/class-locator#locator-press)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Focuses the element, and then uses * Focuses the element, and then uses
* [keyboard.down(key)](https://playwright.dev/docs/api/class-keyboard#keyboard-down) and * [keyboard.down(key)](https://playwright.dev/docs/api/class-keyboard#keyboard-down) and
@ -3486,7 +3527,9 @@ export interface Page {
screenshot(options?: PageScreenshotOptions): Promise<Buffer>; screenshot(options?: PageScreenshotOptions): Promise<Buffer>;
/** /**
* **NOTE** Use locator-based [`method: Locator.selectOption`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.selectOption(values[, options])](https://playwright.dev/docs/api/class-locator#locator-select-option)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method waits for an element matching `selector`, waits for [actionability](https://playwright.dev/docs/actionability) checks, waits * This method waits for an element matching `selector`, waits for [actionability](https://playwright.dev/docs/actionability) checks, waits
* until all specified options are present in the `<select>` element and selects these options. * until all specified options are present in the `<select>` element and selects these options.
@ -3580,7 +3623,9 @@ export interface Page {
}): Promise<Array<string>>; }): Promise<Array<string>>;
/** /**
* **NOTE** Use locator-based [`method: Locator.setChecked`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.setChecked(checked[, options])](https://playwright.dev/docs/api/class-locator#locator-set-checked)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method checks or unchecks an element matching `selector` by performing the following steps: * This method checks or unchecks an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -3715,7 +3760,9 @@ export interface Page {
setExtraHTTPHeaders(headers: { [key: string]: string; }): Promise<void>; setExtraHTTPHeaders(headers: { [key: string]: string; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.setInputFiles`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.setInputFiles(files[, options])](https://playwright.dev/docs/api/class-locator#locator-set-input-files)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then * Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files. * they are resolved relative to the current working directory. For empty array, clears the selected files.
@ -3821,7 +3868,8 @@ export interface Page {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.tap`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.tap([options])](https://playwright.dev/docs/api/class-locator#locator-tap) instead. Read
* more about [locators](https://playwright.dev/docs/locators).
* *
* This method taps an element matching `selector` by performing the following steps: * This method taps an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -3892,7 +3940,9 @@ export interface Page {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.textContent`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.textContent([options])](https://playwright.dev/docs/api/class-locator#locator-text-content) instead. Read
* more about [locators](https://playwright.dev/docs/locators).
* *
* Returns `element.textContent`. * Returns `element.textContent`.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -3923,7 +3973,8 @@ export interface Page {
touchscreen: Touchscreen; touchscreen: Touchscreen;
/** /**
* **NOTE** Use locator-based [`method: Locator.type`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.type(text[, options])](https://playwright.dev/docs/api/class-locator#locator-type)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. `page.type` can be used to * Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. `page.type` can be used to
* send fine-grained keyboard events. To fill values in form fields, use * send fine-grained keyboard events. To fill values in form fields, use
@ -3973,7 +4024,8 @@ export interface Page {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.uncheck`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.uncheck([options])](https://playwright.dev/docs/api/class-locator#locator-uncheck)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method unchecks an element matching `selector` by performing the following steps: * This method unchecks an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -4692,7 +4744,8 @@ export interface Frame {
evaluateHandle<R>(pageFunction: PageFunction<void, R>, arg?: any): Promise<SmartHandle<R>>; evaluateHandle<R>(pageFunction: PageFunction<void, R>, arg?: any): Promise<SmartHandle<R>>;
/** /**
* **NOTE** Use locator-based [`method: Frame.locator`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [frame.locator(selector[, options])](https://playwright.dev/docs/api/class-frame#frame-locator)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns the ElementHandle pointing to the frame element. * Returns the ElementHandle pointing to the frame element.
* *
@ -4705,7 +4758,8 @@ export interface Frame {
*/ */
$<K extends keyof HTMLElementTagNameMap>(selector: K, options?: { strict: boolean }): Promise<ElementHandleForTag<K> | null>; $<K extends keyof HTMLElementTagNameMap>(selector: K, options?: { strict: boolean }): Promise<ElementHandleForTag<K> | null>;
/** /**
* **NOTE** Use locator-based [`method: Frame.locator`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [frame.locator(selector[, options])](https://playwright.dev/docs/api/class-frame#frame-locator)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns the ElementHandle pointing to the frame element. * Returns the ElementHandle pointing to the frame element.
* *
@ -4719,7 +4773,8 @@ export interface Frame {
$(selector: string, options?: { strict: boolean }): Promise<ElementHandle<SVGElement | HTMLElement> | null>; $(selector: string, options?: { strict: boolean }): Promise<ElementHandle<SVGElement | HTMLElement> | null>;
/** /**
* **NOTE** Use locator-based [`method: Frame.locator`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [frame.locator(selector[, options])](https://playwright.dev/docs/api/class-frame#frame-locator)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns the ElementHandles pointing to the frame elements. * Returns the ElementHandles pointing to the frame elements.
* *
@ -4731,7 +4786,8 @@ export interface Frame {
*/ */
$$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K>[]>; $$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K>[]>;
/** /**
* **NOTE** Use locator-based [`method: Frame.locator`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [frame.locator(selector[, options])](https://playwright.dev/docs/api/class-frame#frame-locator)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns the ElementHandles pointing to the frame elements. * Returns the ElementHandles pointing to the frame elements.
* *
@ -4745,7 +4801,9 @@ export interface Frame {
/** /**
* **NOTE** This method does not wait for the element to pass the actionability checks and therefore can lead to the flaky * **NOTE** This method does not wait for the element to pass the actionability checks and therefore can lead to the flaky
* tests. Use [`method: Locator.evaluate`], other [Locator] helper methods or web-first assertions instead. * tests. Use
* [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate),
* other [Locator] helper methods or web-first assertions instead.
* *
* Returns the return value of `pageFunction`. * Returns the return value of `pageFunction`.
* *
@ -4772,7 +4830,9 @@ export interface Frame {
$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], Arg, R>, arg: Arg): Promise<R>; $eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], Arg, R>, arg: Arg): Promise<R>;
/** /**
* **NOTE** This method does not wait for the element to pass the actionability checks and therefore can lead to the flaky * **NOTE** This method does not wait for the element to pass the actionability checks and therefore can lead to the flaky
* tests. Use [`method: Locator.evaluate`], other [Locator] helper methods or web-first assertions instead. * tests. Use
* [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate),
* other [Locator] helper methods or web-first assertions instead.
* *
* Returns the return value of `pageFunction`. * Returns the return value of `pageFunction`.
* *
@ -4799,7 +4859,9 @@ export interface Frame {
$eval<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E, Arg, R>, arg: Arg): Promise<R>; $eval<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E, Arg, R>, arg: Arg): Promise<R>;
/** /**
* **NOTE** This method does not wait for the element to pass the actionability checks and therefore can lead to the flaky * **NOTE** This method does not wait for the element to pass the actionability checks and therefore can lead to the flaky
* tests. Use [`method: Locator.evaluate`], other [Locator] helper methods or web-first assertions instead. * tests. Use
* [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate),
* other [Locator] helper methods or web-first assertions instead.
* *
* Returns the return value of `pageFunction`. * Returns the return value of `pageFunction`.
* *
@ -4826,7 +4888,9 @@ export interface Frame {
$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], void, R>, arg?: any): Promise<R>; $eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], void, R>, arg?: any): Promise<R>;
/** /**
* **NOTE** This method does not wait for the element to pass the actionability checks and therefore can lead to the flaky * **NOTE** This method does not wait for the element to pass the actionability checks and therefore can lead to the flaky
* tests. Use [`method: Locator.evaluate`], other [Locator] helper methods or web-first assertions instead. * tests. Use
* [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate),
* other [Locator] helper methods or web-first assertions instead.
* *
* Returns the return value of `pageFunction`. * Returns the return value of `pageFunction`.
* *
@ -4853,8 +4917,9 @@ export interface Frame {
$eval<R, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E, void, R>, arg?: any): Promise<R>; $eval<R, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E, void, R>, arg?: any): Promise<R>;
/** /**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better * **NOTE** In most cases,
* job. * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all),
* other [Locator] helper methods and web-first assertions do a better job.
* *
* Returns the return value of `pageFunction`. * Returns the return value of `pageFunction`.
* *
@ -4877,8 +4942,9 @@ export interface Frame {
*/ */
$$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], Arg, R>, arg: Arg): Promise<R>; $$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], Arg, R>, arg: Arg): Promise<R>;
/** /**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better * **NOTE** In most cases,
* job. * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all),
* other [Locator] helper methods and web-first assertions do a better job.
* *
* Returns the return value of `pageFunction`. * Returns the return value of `pageFunction`.
* *
@ -4901,8 +4967,9 @@ export interface Frame {
*/ */
$$eval<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E[], Arg, R>, arg: Arg): Promise<R>; $$eval<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(selector: string, pageFunction: PageFunctionOn<E[], Arg, R>, arg: Arg): Promise<R>;
/** /**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better * **NOTE** In most cases,
* job. * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all),
* other [Locator] helper methods and web-first assertions do a better job.
* *
* Returns the return value of `pageFunction`. * Returns the return value of `pageFunction`.
* *
@ -4925,8 +4992,9 @@ export interface Frame {
*/ */
$$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], void, R>, arg?: any): Promise<R>; $$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], void, R>, arg?: any): Promise<R>;
/** /**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better * **NOTE** In most cases,
* job. * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all),
* other [Locator] helper methods and web-first assertions do a better job.
* *
* Returns the return value of `pageFunction`. * Returns the return value of `pageFunction`.
* *
@ -5210,7 +5278,8 @@ export interface Frame {
}): Promise<ElementHandle>; }): Promise<ElementHandle>;
/** /**
* **NOTE** Use locator-based [`method: Locator.check`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.check([options])](https://playwright.dev/docs/api/class-locator#locator-check) instead.
* Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method checks an element matching `selector` by performing the following steps: * This method checks an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -5277,7 +5346,8 @@ export interface Frame {
childFrames(): Array<Frame>; childFrames(): Array<Frame>;
/** /**
* **NOTE** Use locator-based [`method: Locator.click`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.click([options])](https://playwright.dev/docs/api/class-locator#locator-click) instead.
* Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method clicks an element matching `selector` by performing the following steps: * This method clicks an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -5365,7 +5435,8 @@ export interface Frame {
content(): Promise<string>; content(): Promise<string>;
/** /**
* **NOTE** Use locator-based [`method: Locator.dblclick`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.dblclick([options])](https://playwright.dev/docs/api/class-locator#locator-dblclick)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method double clicks an element matching `selector` by performing the following steps: * This method double clicks an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -5446,7 +5517,9 @@ export interface Frame {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.dispatchEvent`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.dispatchEvent(type[, eventInit, options])](https://playwright.dev/docs/api/class-locator#locator-dispatch-event)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the element, * The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the element,
* `click` is dispatched. This is equivalent to calling * `click` is dispatched. This is equivalent to calling
@ -5562,7 +5635,8 @@ export interface Frame {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.fill`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.fill(value[, options])](https://playwright.dev/docs/api/class-locator#locator-fill)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method waits for an element matching `selector`, waits for [actionability](https://playwright.dev/docs/actionability) checks, * This method waits for an element matching `selector`, waits for [actionability](https://playwright.dev/docs/actionability) checks,
* focuses the element, fills it and triggers an `input` event after filling. Note that you can pass an empty string * focuses the element, fills it and triggers an `input` event after filling. Note that you can pass an empty string
@ -5609,7 +5683,8 @@ export interface Frame {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.focus`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.focus([options])](https://playwright.dev/docs/api/class-locator#locator-focus) instead.
* Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method fetches an element with `selector` and focuses it. If there's no element matching `selector`, the * This method fetches an element with `selector` and focuses it. If there's no element matching `selector`, the
* method waits until a matching element appears in the DOM. * method waits until a matching element appears in the DOM.
@ -5672,7 +5747,9 @@ export interface Frame {
frameLocator(selector: string): FrameLocator; frameLocator(selector: string): FrameLocator;
/** /**
* **NOTE** Use locator-based [`method: Locator.getAttribute`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.getAttribute(name[, options])](https://playwright.dev/docs/api/class-locator#locator-get-attribute)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns element attribute value. * Returns element attribute value.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -5969,7 +6046,8 @@ export interface Frame {
}): Promise<null|Response>; }): Promise<null|Response>;
/** /**
* **NOTE** Use locator-based [`method: Locator.hover`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.hover([options])](https://playwright.dev/docs/api/class-locator#locator-hover) instead.
* Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method hovers over an element matching `selector` by performing the following steps: * This method hovers over an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -6037,7 +6115,8 @@ export interface Frame {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.innerHTML`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.innerHTML([options])](https://playwright.dev/docs/api/class-locator#locator-inner-html)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns `element.innerHTML`. * Returns `element.innerHTML`.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -6061,7 +6140,8 @@ export interface Frame {
}): Promise<string>; }): Promise<string>;
/** /**
* **NOTE** Use locator-based [`method: Locator.innerText`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.innerText([options])](https://playwright.dev/docs/api/class-locator#locator-inner-text)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns `element.innerText`. * Returns `element.innerText`.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -6085,7 +6165,9 @@ export interface Frame {
}): Promise<string>; }): Promise<string>;
/** /**
* **NOTE** Use locator-based [`method: Locator.inputValue`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.inputValue([options])](https://playwright.dev/docs/api/class-locator#locator-input-value) instead. Read
* more about [locators](https://playwright.dev/docs/locators).
* *
* Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element. * Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element.
* *
@ -6113,7 +6195,8 @@ export interface Frame {
}): Promise<string>; }): Promise<string>;
/** /**
* **NOTE** Use locator-based [`method: Locator.isChecked`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.isChecked([options])](https://playwright.dev/docs/api/class-locator#locator-is-checked)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is checked. Throws if the element is not a checkbox or radio input. * Returns whether the element is checked. Throws if the element is not a checkbox or radio input.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -6142,7 +6225,9 @@ export interface Frame {
isDetached(): boolean; isDetached(): boolean;
/** /**
* **NOTE** Use locator-based [`method: Locator.isDisabled`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.isDisabled([options])](https://playwright.dev/docs/api/class-locator#locator-is-disabled) instead. Read
* more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is disabled, the opposite of [enabled](https://playwright.dev/docs/actionability#enabled). * Returns whether the element is disabled, the opposite of [enabled](https://playwright.dev/docs/actionability#enabled).
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -6166,7 +6251,9 @@ export interface Frame {
}): Promise<boolean>; }): Promise<boolean>;
/** /**
* **NOTE** Use locator-based [`method: Locator.isEditable`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.isEditable([options])](https://playwright.dev/docs/api/class-locator#locator-is-editable) instead. Read
* more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is [editable](https://playwright.dev/docs/actionability#editable). * Returns whether the element is [editable](https://playwright.dev/docs/actionability#editable).
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -6212,7 +6299,8 @@ export interface Frame {
}): Promise<boolean>; }): Promise<boolean>;
/** /**
* **NOTE** Use locator-based [`method: Locator.isHidden`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.isHidden([options])](https://playwright.dev/docs/api/class-locator#locator-is-hidden)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is hidden, the opposite of [visible](https://playwright.dev/docs/actionability#visible). `selector` that * Returns whether the element is hidden, the opposite of [visible](https://playwright.dev/docs/actionability#visible). `selector` that
* does not match any elements is considered hidden. * does not match any elements is considered hidden.
@ -6228,14 +6316,16 @@ export interface Frame {
strict?: boolean; strict?: boolean;
/** /**
* @deprecated This option is ignored. [`method: Frame.isHidden`] does not wait for the element to become hidden and returns * @deprecated This option is ignored.
* immediately. * [frame.isHidden(selector[, options])](https://playwright.dev/docs/api/class-frame#frame-is-hidden) does not wait
* for the element to become hidden and returns immediately.
*/ */
timeout?: number; timeout?: number;
}): Promise<boolean>; }): Promise<boolean>;
/** /**
* **NOTE** Use locator-based [`method: Locator.isVisible`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.isVisible([options])](https://playwright.dev/docs/api/class-locator#locator-is-visible)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Returns whether the element is [visible](https://playwright.dev/docs/actionability#visible). `selector` that does not match any elements * Returns whether the element is [visible](https://playwright.dev/docs/actionability#visible). `selector` that does not match any elements
* is considered not visible. * is considered not visible.
@ -6251,8 +6341,9 @@ export interface Frame {
strict?: boolean; strict?: boolean;
/** /**
* @deprecated This option is ignored. [`method: Frame.isVisible`] does not wait for the element to become visible and returns * @deprecated This option is ignored.
* immediately. * [frame.isVisible(selector[, options])](https://playwright.dev/docs/api/class-frame#frame-is-visible) does not wait
* for the element to become visible and returns immediately.
*/ */
timeout?: number; timeout?: number;
}): Promise<boolean>; }): Promise<boolean>;
@ -6306,7 +6397,8 @@ export interface Frame {
parentFrame(): null|Frame; parentFrame(): null|Frame;
/** /**
* **NOTE** Use locator-based [`method: Locator.press`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.press(key[, options])](https://playwright.dev/docs/api/class-locator#locator-press)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* `key` can specify the intended * `key` can specify the intended
* [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character * [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character
@ -6360,7 +6452,9 @@ export interface Frame {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.selectOption`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.selectOption(values[, options])](https://playwright.dev/docs/api/class-locator#locator-select-option)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method waits for an element matching `selector`, waits for [actionability](https://playwright.dev/docs/actionability) checks, waits * This method waits for an element matching `selector`, waits for [actionability](https://playwright.dev/docs/actionability) checks, waits
* until all specified options are present in the `<select>` element and selects these options. * until all specified options are present in the `<select>` element and selects these options.
@ -6452,7 +6546,9 @@ export interface Frame {
}): Promise<Array<string>>; }): Promise<Array<string>>;
/** /**
* **NOTE** Use locator-based [`method: Locator.setChecked`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.setChecked(checked[, options])](https://playwright.dev/docs/api/class-locator#locator-set-checked)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method checks or unchecks an element matching `selector` by performing the following steps: * This method checks or unchecks an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -6545,7 +6641,9 @@ export interface Frame {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.setInputFiles`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.setInputFiles(files[, options])](https://playwright.dev/docs/api/class-locator#locator-set-input-files)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then * Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files. * they are resolved relative to the current working directory. For empty array, clears the selected files.
@ -6613,7 +6711,8 @@ export interface Frame {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.tap`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.tap([options])](https://playwright.dev/docs/api/class-locator#locator-tap) instead. Read
* more about [locators](https://playwright.dev/docs/locators).
* *
* This method taps an element matching `selector` by performing the following steps: * This method taps an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -6683,7 +6782,9 @@ export interface Frame {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.textContent`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based
* [locator.textContent([options])](https://playwright.dev/docs/api/class-locator#locator-text-content) instead. Read
* more about [locators](https://playwright.dev/docs/locators).
* *
* Returns `element.textContent`. * Returns `element.textContent`.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be * @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
@ -6712,7 +6813,8 @@ export interface Frame {
title(): Promise<string>; title(): Promise<string>;
/** /**
* **NOTE** Use locator-based [`method: Locator.type`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.type(text[, options])](https://playwright.dev/docs/api/class-locator#locator-type)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. `frame.type` can be used * Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. `frame.type` can be used
* to send fine-grained keyboard events. To fill values in form fields, use * to send fine-grained keyboard events. To fill values in form fields, use
@ -6762,7 +6864,8 @@ export interface Frame {
}): Promise<void>; }): Promise<void>;
/** /**
* **NOTE** Use locator-based [`method: Locator.uncheck`] instead. Read more about [locators](https://playwright.dev/docs/locators). * **NOTE** Use locator-based [locator.uncheck([options])](https://playwright.dev/docs/api/class-locator#locator-uncheck)
* instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* This method checks an element matching `selector` by performing the following steps: * This method checks an element matching `selector` by performing the following steps:
* 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM. * 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
@ -10798,8 +10901,9 @@ export interface Locator {
*/ */
isHidden(options?: { isHidden(options?: {
/** /**
* @deprecated This option is ignored. [`method: Locator.isHidden`] does not wait for the element to become hidden and returns * @deprecated This option is ignored.
* immediately. * [locator.isHidden([options])](https://playwright.dev/docs/api/class-locator#locator-is-hidden) does not wait for
* the element to become hidden and returns immediately.
*/ */
timeout?: number; timeout?: number;
}): Promise<boolean>; }): Promise<boolean>;
@ -10810,8 +10914,9 @@ export interface Locator {
*/ */
isVisible(options?: { isVisible(options?: {
/** /**
* @deprecated This option is ignored. [`method: Locator.isVisible`] does not wait for the element to become visible and returns * @deprecated This option is ignored.
* immediately. * [locator.isVisible([options])](https://playwright.dev/docs/api/class-locator#locator-is-visible) does not wait for
* the element to become visible and returns immediately.
*/ */
timeout?: number; timeout?: number;
}): Promise<boolean>; }): Promise<boolean>;
@ -11874,7 +11979,7 @@ export interface BrowserType<Unused = {}> {
userAgent?: string; userAgent?: string;
/** /**
* @deprecated Use [`option: recordVideo`] instead. * @deprecated Use `recordVideo` instead.
*/ */
videoSize?: { videoSize?: {
/** /**
@ -11889,7 +11994,7 @@ export interface BrowserType<Unused = {}> {
}; };
/** /**
* @deprecated Use [`option: recordVideo`] instead. * @deprecated Use `recordVideo` instead.
*/ */
videosPath?: string; videosPath?: string;
@ -12133,8 +12238,9 @@ export namespace errors {
/** /**
* - extends: [Error] * - extends: [Error]
* *
* TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g. [`method: Locator.waitFor`] * TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g.
* or [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browser-type-launch). * [locator.waitFor([options])](https://playwright.dev/docs/api/class-locator#locator-wait-for) or
* [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browser-type-launch).
* *
* ```js * ```js
* const playwright = require('playwright'); * const playwright = require('playwright');
@ -13236,7 +13342,7 @@ export interface AndroidDevice {
userAgent?: string; userAgent?: string;
/** /**
* @deprecated Use [`option: recordVideo`] instead. * @deprecated Use `recordVideo` instead.
*/ */
videoSize?: { videoSize?: {
/** /**
@ -13251,7 +13357,7 @@ export interface AndroidDevice {
}; };
/** /**
* @deprecated Use [`option: recordVideo`] instead. * @deprecated Use `recordVideo` instead.
*/ */
videosPath?: string; videosPath?: string;
@ -15138,7 +15244,7 @@ export interface Browser extends EventEmitter {
userAgent?: string; userAgent?: string;
/** /**
* @deprecated Use [`option: recordVideo`] instead. * @deprecated Use `recordVideo` instead.
*/ */
videoSize?: { videoSize?: {
/** /**
@ -15153,7 +15259,7 @@ export interface Browser extends EventEmitter {
}; };
/** /**
* @deprecated Use [`option: recordVideo`] instead. * @deprecated Use `recordVideo` instead.
*/ */
videosPath?: string; videosPath?: string;
@ -18087,7 +18193,7 @@ export interface BrowserContextOptions {
userAgent?: string; userAgent?: string;
/** /**
* @deprecated Use [`option: recordVideo`] instead. * @deprecated Use `recordVideo` instead.
*/ */
videoSize?: { videoSize?: {
/** /**
@ -18102,7 +18208,7 @@ export interface BrowserContextOptions {
}; };
/** /**
* @deprecated Use [`option: recordVideo`] instead. * @deprecated Use `recordVideo` instead.
*/ */
videosPath?: string; videosPath?: string;

View file

@ -1,6 +1,6 @@
{ {
"name": "@playwright/experimental-ct-react", "name": "@playwright/experimental-ct-react",
"version": "1.29.0-next", "version": "1.29.2",
"description": "Playwright Component Testing for React", "description": "Playwright Component Testing for React",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",
@ -27,7 +27,7 @@
}, },
"dependencies": { "dependencies": {
"@vitejs/plugin-react": "^2.2.0", "@vitejs/plugin-react": "^2.2.0",
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"vite": "^3.2.1" "vite": "^3.2.1"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "@playwright/experimental-ct-solid", "name": "@playwright/experimental-ct-solid",
"version": "1.29.0-next", "version": "1.29.2",
"description": "Playwright Component Testing for Solid", "description": "Playwright Component Testing for Solid",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",
@ -28,7 +28,7 @@
"dependencies": { "dependencies": {
"vite": "^3.2.1", "vite": "^3.2.1",
"vite-plugin-solid": "^2.3.10", "vite-plugin-solid": "^2.3.10",
"@playwright/test": "1.29.0-next" "@playwright/test": "1.29.2"
}, },
"devDependencies": { "devDependencies": {
"solid-js": "^1.4.7" "solid-js": "^1.4.7"

View file

@ -1,6 +1,6 @@
{ {
"name": "@playwright/experimental-ct-svelte", "name": "@playwright/experimental-ct-svelte",
"version": "1.29.0-next", "version": "1.29.2",
"description": "Playwright Component Testing for Svelte", "description": "Playwright Component Testing for Svelte",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",
@ -26,7 +26,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"@sveltejs/vite-plugin-svelte": "^1.1.0", "@sveltejs/vite-plugin-svelte": "^1.1.0",
"vite": "^3.2.1" "vite": "^3.2.1"
}, },

View file

@ -1,6 +1,6 @@
{ {
"name": "@playwright/experimental-ct-vue", "name": "@playwright/experimental-ct-vue",
"version": "1.29.0-next", "version": "1.29.2",
"description": "Playwright Component Testing for Vue", "description": "Playwright Component Testing for Vue",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",
@ -27,7 +27,7 @@
}, },
"dependencies": { "dependencies": {
"@vitejs/plugin-vue": "^3.2.0", "@vitejs/plugin-vue": "^3.2.0",
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"vite": "^3.2.1" "vite": "^3.2.1"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "@playwright/experimental-ct-vue2", "name": "@playwright/experimental-ct-vue2",
"version": "1.29.0-next", "version": "1.29.2",
"description": "Playwright Component Testing for Vue2", "description": "Playwright Component Testing for Vue2",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",
@ -26,7 +26,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@playwright/test": "1.29.0-next", "@playwright/test": "1.29.2",
"@vitejs/plugin-vue2": "^2.0.0", "@vitejs/plugin-vue2": "^2.0.0",
"vite": "^3.2.1" "vite": "^3.2.1"
}, },

View file

@ -1,6 +1,6 @@
{ {
"name": "playwright-firefox", "name": "playwright-firefox",
"version": "1.29.0-next", "version": "1.29.2",
"description": "A high-level API to automate Firefox", "description": "A high-level API to automate Firefox",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",
@ -28,6 +28,6 @@
"install": "node install.js" "install": "node install.js"
}, },
"dependencies": { "dependencies": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "@playwright/test", "name": "@playwright/test",
"version": "1.29.0-next", "version": "1.29.2",
"description": "A high-level API to automate web browsers", "description": "A high-level API to automate web browsers",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",
@ -34,6 +34,6 @@
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@types/node": "*", "@types/node": "*",
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
} }
} }

View file

@ -20,7 +20,7 @@ import type { APIRequestContext, BrowserContext, BrowserContextOptions, LaunchOp
import * as playwrightLibrary from 'playwright-core'; import * as playwrightLibrary from 'playwright-core';
import { createGuid, debugMode } from 'playwright-core/lib/utils'; import { createGuid, debugMode } from 'playwright-core/lib/utils';
import { removeFolders } from 'playwright-core/lib/utils/fileUtils'; import { removeFolders } from 'playwright-core/lib/utils/fileUtils';
import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo, TestType, TraceMode, VideoMode } from '../types/test'; import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, ScreenshotMode, TestInfo, TestType, TraceMode, VideoMode } from '../types/test';
import { store as _baseStore } from './store'; import { store as _baseStore } from './store';
import type { TestInfoImpl } from './testInfo'; import type { TestInfoImpl } from './testInfo';
import { rootTestType, _setProjectSetup } from './testType'; import { rootTestType, _setProjectSetup } from './testType';
@ -246,8 +246,8 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
if (debugMode()) if (debugMode())
testInfo.setTimeout(0); testInfo.setTimeout(0);
const screenshotOptions = typeof screenshot !== 'string' ? { fullPage: screenshot.fullPage, omitBackground: screenshot.omitBackground } : undefined; const screenshotMode = normalizeScreenshotMode(screenshot);
const screenshotMode = typeof screenshot === 'string' ? screenshot : screenshot.mode; const screenshotOptions = typeof screenshot === 'string' ? undefined : screenshot;
const traceMode = normalizeTraceMode(trace); const traceMode = normalizeTraceMode(trace);
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true }; const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true };
const traceOptions = typeof trace === 'string' ? defaultTraceOptions : { ...defaultTraceOptions, ...trace, mode: undefined }; const traceOptions = typeof trace === 'string' ? defaultTraceOptions : { ...defaultTraceOptions, ...trace, mode: undefined };
@ -620,6 +620,12 @@ export function shouldCaptureTrace(traceMode: TraceMode, testInfo: TestInfo) {
return traceMode === 'on' || traceMode === 'retain-on-failure' || (traceMode === 'on-first-retry' && testInfo.retry === 1); return traceMode === 'on' || traceMode === 'retain-on-failure' || (traceMode === 'on-first-retry' && testInfo.retry === 1);
} }
function normalizeScreenshotMode(screenshot: PlaywrightWorkerOptions['screenshot'] | undefined): ScreenshotMode {
if (!screenshot)
return 'off';
return typeof screenshot === 'string' ? screenshot : screenshot.mode;
}
const kTracingStarted = Symbol('kTracingStarted'); const kTracingStarted = Symbol('kTracingStarted');
export const test = _baseTest.extend<TestFixtures, WorkerFixtures>(playwrightFixtures); export const test = _baseTest.extend<TestFixtures, WorkerFixtures>(playwrightFixtures);

View file

@ -358,5 +358,5 @@ export async function toPass(
`- ${timeoutMessage}`, `- ${timeoutMessage}`,
].join('\n') : timeoutMessage; ].join('\n') : timeoutMessage;
return { message, pass: false }; return { message, pass: isNot ? true : false };
} }

View file

@ -472,7 +472,7 @@ export class Runner {
return { status: 'passed' }; return { status: 'passed' };
// Remove output directores. // Remove output directores.
if (!this._removeOutputDirs(options)) if (!await this._removeOutputDirs(options))
return { status: 'failed' }; return { status: 'failed' };
// Run Global setup. // Run Global setup.

View file

@ -1,6 +1,6 @@
{ {
"name": "playwright-webkit", "name": "playwright-webkit",
"version": "1.29.0-next", "version": "1.29.2",
"description": "A high-level API to automate WebKit", "description": "A high-level API to automate WebKit",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",
@ -28,6 +28,6 @@
"install": "node install.js" "install": "node install.js"
}, },
"dependencies": { "dependencies": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "playwright", "name": "playwright",
"version": "1.29.0-next", "version": "1.29.2",
"description": "A high-level API to automate web browsers", "description": "A high-level API to automate web browsers",
"repository": "github:Microsoft/playwright", "repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev", "homepage": "https://playwright.dev",
@ -28,6 +28,6 @@
"install": "node install.js" "install": "node install.js"
}, },
"dependencies": { "dependencies": {
"playwright-core": "1.29.0-next" "playwright-core": "1.29.2"
} }
} }

View file

@ -0,0 +1,2 @@
const { protocol } = require('electron');
protocol.registerSchemesAsPrivileged([]);

View file

@ -19,10 +19,8 @@ import path from 'path';
import fs from 'fs'; import fs from 'fs';
import { electronTest as test, expect } from './electronTest'; import { electronTest as test, expect } from './electronTest';
test('should fire close event', async ({ playwright }) => { test('should fire close event', async ({ launchElectronApp }) => {
const electronApp = await playwright._electron.launch({ const electronApp = await launchElectronApp('electron-app.js');
args: [path.join(__dirname, 'electron-app.js')],
});
const events = []; const events = [];
electronApp.on('close', () => events.push('application')); electronApp.on('close', () => events.push('application'));
electronApp.context().on('close', () => events.push('context')); electronApp.context().on('close', () => events.push('context'));
@ -33,22 +31,16 @@ test('should fire close event', async ({ playwright }) => {
expect(events.join('|')).toBe('context|application'); expect(events.join('|')).toBe('context|application');
}); });
test('should dispatch ready event', async ({ playwright }) => { test('should dispatch ready event', async ({ launchElectronApp }) => {
const electronApp = await playwright._electron.launch({ const electronApp = await launchElectronApp('electron-app-ready-event.js');
args: [path.join(__dirname, 'electron-app-ready-event.js')], const events = await electronApp.evaluate(() => globalThis.__playwrightLog);
}); expect(events).toEqual([
try { 'isReady == false',
const events = await electronApp.evaluate(() => globalThis.__playwrightLog); 'will-finish-launching fired',
expect(events).toEqual([ 'ready fired',
'isReady == false', 'whenReady resolved',
'will-finish-launching fired', 'isReady == true',
'ready fired', ]);
'whenReady resolved',
'isReady == true',
]);
} finally {
await electronApp.close();
}
}); });
test('should script application', async ({ electronApp }) => { test('should script application', async ({ electronApp }) => {
@ -114,28 +106,19 @@ test('should have a clipboard instance', async ({ electronApp }) => {
expect(clipboardContentRead).toEqual(clipboardContentToWrite); expect(clipboardContentRead).toEqual(clipboardContentToWrite);
}); });
test('should test app that opens window fast', async ({ playwright }) => { test('should test app that opens window fast', async ({ launchElectronApp }) => {
const electronApp = await playwright._electron.launch({ await launchElectronApp('electron-window-app.js');
args: [path.join(__dirname, 'electron-window-app.js')],
});
await electronApp.close();
}); });
test('should return browser window', async ({ playwright }) => { test('should return browser window', async ({ launchElectronApp }) => {
const electronApp = await playwright._electron.launch({ const electronApp = await launchElectronApp('electron-window-app.js');
args: [path.join(__dirname, 'electron-window-app.js')],
});
const page = await electronApp.firstWindow(); const page = await electronApp.firstWindow();
const bwHandle = await electronApp.browserWindow(page); const bwHandle = await electronApp.browserWindow(page);
expect(await bwHandle.evaluate((bw: BrowserWindow) => bw.title)).toBe('Electron'); expect(await bwHandle.evaluate((bw: BrowserWindow) => bw.title)).toBe('Electron');
await electronApp.close();
}); });
test('should bypass csp', async ({ playwright, server }) => { test('should bypass csp', async ({ launchElectronApp, server }) => {
const app = await playwright._electron.launch({ const app = await launchElectronApp('electron-app.js', { bypassCSP: true });
args: [require('path').join(__dirname, 'electron-app.js')],
bypassCSP: true,
});
await app.evaluate(electron => { await app.evaluate(electron => {
const window = new electron.BrowserWindow({ const window = new electron.BrowserWindow({
width: 800, width: 800,
@ -147,13 +130,10 @@ test('should bypass csp', async ({ playwright, server }) => {
await page.goto(server.PREFIX + '/csp.html'); await page.goto(server.PREFIX + '/csp.html');
await page.addScriptTag({ content: 'window["__injected"] = 42;' }); await page.addScriptTag({ content: 'window["__injected"] = 42;' });
expect(await page.evaluate('window["__injected"]')).toBe(42); expect(await page.evaluate('window["__injected"]')).toBe(42);
await app.close();
}); });
test('should create page for browser view', async ({ playwright }) => { test('should create page for browser view', async ({ launchElectronApp }) => {
const app = await playwright._electron.launch({ const app = await launchElectronApp('electron-window-app.js');
args: [path.join(__dirname, 'electron-window-app.js')],
});
await app.firstWindow(); await app.firstWindow();
await app.evaluate(async electron => { await app.evaluate(async electron => {
const window = electron.BrowserWindow.getAllWindows()[0]; const window = electron.BrowserWindow.getAllWindows()[0];
@ -163,13 +143,10 @@ test('should create page for browser view', async ({ playwright }) => {
view.setBounds({ x: 0, y: 0, width: 256, height: 256 }); view.setBounds({ x: 0, y: 0, width: 256, height: 256 });
}); });
await expect.poll(() => app.windows().length).toBe(2); await expect.poll(() => app.windows().length).toBe(2);
await app.close();
}); });
test('should return same browser window for browser view pages', async ({ playwright }) => { test('should return same browser window for browser view pages', async ({ launchElectronApp }) => {
const app = await playwright._electron.launch({ const app = await launchElectronApp('electron-window-app.js');
args: [path.join(__dirname, 'electron-window-app.js')],
});
await app.firstWindow(); await app.firstWindow();
await app.evaluate(async electron => { await app.evaluate(async electron => {
const window = electron.BrowserWindow.getAllWindows()[0]; const window = electron.BrowserWindow.getAllWindows()[0];
@ -187,12 +164,10 @@ test('should return same browser window for browser view pages', async ({ playwr
}) })
); );
expect(firstWindowId).toEqual(secondWindowId); expect(firstWindowId).toEqual(secondWindowId);
await app.close();
}); });
test('should record video', async ({ playwright }, testInfo) => { test('should record video', async ({ launchElectronApp }, testInfo) => {
const app = await playwright._electron.launch({ const app = await launchElectronApp('electron-window-app.js', {
args: [path.join(__dirname, 'electron-window-app.js')],
recordVideo: { dir: testInfo.outputPath('video') } recordVideo: { dir: testInfo.outputPath('video') }
}); });
const page = await app.firstWindow(); const page = await app.firstWindow();
@ -203,25 +178,31 @@ test('should record video', async ({ playwright }, testInfo) => {
expect(fs.statSync(videoPath).size).toBeGreaterThan(0); expect(fs.statSync(videoPath).size).toBeGreaterThan(0);
}); });
test('should be able to get the first window when with a delayed navigation', async ({ playwright }) => { test('should be able to get the first window when with a delayed navigation', async ({ launchElectronApp }) => {
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/17765' }); test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/17765' });
const app = await playwright._electron.launch({ const app = await launchElectronApp('electron-window-app-delayed-loadURL.js');
args: [path.join(__dirname, 'electron-window-app-delayed-loadURL.js')],
});
const page = await app.firstWindow(); const page = await app.firstWindow();
await expect(page).toHaveURL('data:text/html,<h1>Foobar</h1>'); await expect(page).toHaveURL('data:text/html,<h1>Foobar</h1>');
await expect(page.locator('h1')).toHaveText('Foobar'); await expect(page.locator('h1')).toHaveText('Foobar');
await app.close();
}); });
test('should detach debugger on app-initiated exit', async ({ playwright }) => { test('should detach debugger on app-initiated exit', async ({ launchElectronApp }) => {
const electronApp = await playwright._electron.launch({ const electronApp = await launchElectronApp('electron-app.js');
args: [path.join(__dirname, 'electron-app.js')],
});
const closePromise = new Promise(f => electronApp.process().on('close', f)); const closePromise = new Promise(f => electronApp.process().on('close', f));
await electronApp.evaluate(({ app }) => { await electronApp.evaluate(({ app }) => {
app.quit(); app.quit();
}); });
await closePromise; await closePromise;
}); });
test('should run pre-ready apis', async ({ launchElectronApp }) => {
await launchElectronApp('electron-pre-ready-app.js');
});
test('should resolve app path for folder apps', async ({ launchElectronApp }) => {
const electronApp = await launchElectronApp('.');
const appPath = await electronApp.evaluate(async ({ app }) => app.getAppPath());
expect(appPath).toBe(path.resolve(__dirname));
await electronApp.close();
});

View file

@ -26,6 +26,7 @@ import { assert } from 'playwright-core/lib/utils';
type ElectronTestFixtures = PageTestFixtures & { type ElectronTestFixtures = PageTestFixtures & {
electronApp: ElectronApplication; electronApp: ElectronApplication;
launchElectronApp: (appFile: string, options?: any) => Promise<ElectronApplication>;
newWindow: () => Promise<Page>; newWindow: () => Promise<Page>;
}; };
@ -40,14 +41,21 @@ export const electronTest = baseTest.extend<TraceViewerFixtures>(traceViewerFixt
isElectron: [true, { scope: 'worker' }], isElectron: [true, { scope: 'worker' }],
isWebView2: [false, { scope: 'worker' }], isWebView2: [false, { scope: 'worker' }],
electronApp: async ({ playwright }, run) => { launchElectronApp: async ({ playwright }, use) => {
// This env prevents 'Electron Security Policy' console message. // This env prevents 'Electron Security Policy' console message.
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'; process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
const electronApp = await playwright._electron.launch({ const apps: ElectronApplication[] = [];
args: [path.join(__dirname, 'electron-app.js')], await use(async (appFile: string, options?: any[]) => {
const app = await playwright._electron.launch({ ...options, args: [path.join(__dirname, appFile)] });
apps.push(app);
return app;
}); });
await run(electronApp); for (const app of apps)
await electronApp.close(); await app.close();
},
electronApp: async ({ launchElectronApp }, use) => {
await use(await launchElectronApp('electron-app.js'));
}, },
newWindow: async ({ electronApp }, run) => { newWindow: async ({ electronApp }, run) => {

1
tests/electron/index.js Normal file
View file

@ -0,0 +1 @@
require('electron');

View file

@ -30,6 +30,7 @@ import type { Browser, ConnectOptions } from 'playwright-core';
type ExtraFixtures = { type ExtraFixtures = {
connect: (wsEndpoint: string, options?: ConnectOptions, redirectPortForTest?: number) => Promise<Browser>, connect: (wsEndpoint: string, options?: ConnectOptions, redirectPortForTest?: number) => Promise<Browser>,
dummyServerPort: number, dummyServerPort: number,
ipV6ServerUrl: string,
}; };
const test = playwrightTest.extend<ExtraFixtures>({ const test = playwrightTest.extend<ExtraFixtures>({
connect: async ({ browserType }, use) => { connect: async ({ browserType }, use) => {
@ -54,6 +55,16 @@ const test = playwrightTest.extend<ExtraFixtures>({
await use((server.address() as net.AddressInfo).port); await use((server.address() as net.AddressInfo).port);
await new Promise<Error>(resolve => server.close(resolve)); await new Promise<Error>(resolve => server.close(resolve));
}, },
ipV6ServerUrl: async ({}, use) => {
const server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => {
res.end('<html><body>from-ipv6-server</body></html>');
});
await new Promise<void>(resolve => server.listen(0, '::1', resolve));
const address = server.address() as net.AddressInfo;
await use('http://[::1]:' + address.port);
await new Promise<Error>(resolve => server.close(resolve));
},
}); });
test.slow(true, 'All connect tests are slow'); test.slow(true, 'All connect tests are slow');
@ -126,6 +137,16 @@ for (const kind of ['launchServer', 'run-server'] as const) {
} }
}); });
test('should be able to visit ipv6', async ({ connect, startRemoteServer, ipV6ServerUrl }) => {
test.fixme(kind === 'run-server', 'socks proxy does not support ipv6 yet');
const remoteServer = await startRemoteServer(kind);
const browser = await connect(remoteServer.wsEndpoint());
const page = await browser.newPage();
await page.goto(ipV6ServerUrl);
expect(await page.content()).toContain('from-ipv6-server');
await browser.close();
});
test('should be able to connect two browsers at the same time', async ({ connect, startRemoteServer }) => { test('should be able to connect two browsers at the same time', async ({ connect, startRemoteServer }) => {
const remoteServer = await startRemoteServer(kind); const remoteServer = await startRemoteServer(kind);
@ -679,6 +700,7 @@ for (const kind of ['launchServer', 'run-server'] as const) {
test.describe('socks proxy', () => { test.describe('socks proxy', () => {
test.fixme(({ platform, browserName }) => browserName === 'webkit' && platform === 'win32'); test.fixme(({ platform, browserName }) => browserName === 'webkit' && platform === 'win32');
test.skip(({ mode }) => mode !== 'default'); test.skip(({ mode }) => mode !== 'default');
test.skip(kind === 'launchServer', 'not supported yet');
test('should forward non-forwarded requests', async ({ server, startRemoteServer, connect }) => { test('should forward non-forwarded requests', async ({ server, startRemoteServer, connect }) => {
let reachedOriginalTarget = false; let reachedOriginalTarget = false;

View file

@ -167,3 +167,16 @@ test('should work with soft', async ({ runInlineTest }) => {
expect(result.exitCode).toBe(1); expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1); expect(result.failed).toBe(1);
}); });
test('should not accept TimeoutError', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.spec.ts': `
const { test } = pwt;
test('should fail', async () => {
await test.expect(() => {}).not.toPass({ timeout: 1 });
});
`
});
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
});

View file

@ -600,3 +600,86 @@ test('should pass fixture defaults to tests', async ({ runInlineTest }) => {
expect(result.exitCode).toBe(0); expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1); expect(result.passed).toBe(1);
}); });
test('should not throw with many fixtures set to undefined', async ({ runInlineTest }, testInfo) => {
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = { use: {
headless: undefined,
channel: undefined,
launchOptions: undefined,
connectOptions: undefined,
screenshot: undefined,
video: undefined,
trace: undefined,
acceptDownloads: undefined,
bypassCSP: undefined,
colorScheme: undefined,
deviceScaleFactor: undefined,
extraHTTPHeaders: undefined,
geolocation: undefined,
hasTouch: undefined,
httpCredentials: undefined,
ignoreHTTPSErrors: undefined,
isMobile: undefined,
javaScriptEnabled: undefined,
locale: undefined,
offline: undefined,
permissions: undefined,
proxy: undefined,
storageState: undefined,
timezoneId: undefined,
userAgent: undefined,
viewport: undefined,
actionTimeout: undefined,
testIdAttribute: undefined,
navigationTimeout: undefined,
baseURL: undefined,
serviceWorkers: undefined,
contextOptions: undefined,
} };
`,
'a.spec.ts': `
const { test } = pwt;
test.use({
headless: undefined,
channel: undefined,
launchOptions: undefined,
connectOptions: undefined,
screenshot: undefined,
video: undefined,
trace: undefined,
acceptDownloads: undefined,
bypassCSP: undefined,
colorScheme: undefined,
deviceScaleFactor: undefined,
extraHTTPHeaders: undefined,
geolocation: undefined,
hasTouch: undefined,
httpCredentials: undefined,
ignoreHTTPSErrors: undefined,
isMobile: undefined,
javaScriptEnabled: undefined,
locale: undefined,
offline: undefined,
permissions: undefined,
proxy: undefined,
storageState: undefined,
timezoneId: undefined,
userAgent: undefined,
viewport: undefined,
actionTimeout: undefined,
testIdAttribute: undefined,
navigationTimeout: undefined,
baseURL: undefined,
serviceWorkers: undefined,
contextOptions: undefined,
});
test('passes', async ({ page }) => {
});
`,
}, { workers: 1 });
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1);
});

View file

@ -178,6 +178,10 @@ class Documentation {
* @param {Class|Member=} classOrMember * @param {Class|Member=} classOrMember
*/ */
renderLinksInNodes(nodes, classOrMember) { renderLinksInNodes(nodes, classOrMember) {
if (classOrMember instanceof Member) {
classOrMember.discouraged = classOrMember.discouraged ? this.renderLinksInText(classOrMember.discouraged, classOrMember) : undefined;
classOrMember.deprecated = classOrMember.deprecated ? this.renderLinksInText(classOrMember.deprecated, classOrMember) : undefined
}
md.visitAll(nodes, node => { md.visitAll(nodes, node => {
if (!node.text) if (!node.text)
return; return;

View file

@ -117,7 +117,7 @@ function _wrapAndEscape(node, maxColumns = 0) {
}; };
let text = node.text; let text = (node.text || '').replace(/↵/g, ' ');
text = text.replace(/\[([^\]]*)\]\((.*?)\)/g, (match, linkName, linkUrl) => { text = text.replace(/\[([^\]]*)\]\((.*?)\)/g, (match, linkName, linkUrl) => {
const isInternal = !linkUrl.startsWith('http://') && !linkUrl.startsWith('https://'); const isInternal = !linkUrl.startsWith('http://') && !linkUrl.startsWith('https://');
if (isInternal) if (isInternal)

View file

@ -25,7 +25,6 @@ const fs = require('fs');
const { parseApi } = require('./api_parser'); const { parseApi } = require('./api_parser');
const { Type } = require('./documentation'); const { Type } = require('./documentation');
const { EOL } = require('os'); const { EOL } = require('os');
const { execSync } = require('child_process');
const maxDocumentationColumnWidth = 80; const maxDocumentationColumnWidth = 80;
Error.stackTraceLimit = 100; Error.stackTraceLimit = 100;
@ -91,10 +90,10 @@ classNameMap.set('Readable', 'Stream');
* *
* @param {string} kind * @param {string} kind
* @param {string} name * @param {string} name
* @param {Documentation.MarkdownNode[]} spec * @param {Documentation.MarkdownNode[]|null} spec
* @param {string[]} body * @param {string[]} body
* @param {string} folder * @param {string} folder
* @param {string} extendsName * @param {string|null} extendsName
*/ */
function writeFile(kind, name, spec, body, folder, extendsName = null) { function writeFile(kind, name, spec, body, folder, extendsName = null) {
const out = []; const out = [];
@ -144,10 +143,19 @@ function renderClass(clazz) {
renderMember(member, clazz, {}, body); renderMember(member, clazz, {}, body);
} }
/** @type {Documentation.MarkdownNode[]} */
const spec = [];
if (clazz.deprecated)
spec.push({ type: 'text', text: '**DEPRECATED** ' + clazz.deprecated });
if (clazz.discouraged)
spec.push({ type: 'text', text: clazz.discouraged });
if (clazz.spec)
spec.push(...clazz.spec);
writeFile( writeFile(
'public partial interface', 'public partial interface',
name, name,
clazz.spec, spec,
body, body,
apiDir, apiDir,
clazz.extends ? `I${toTitleCase(clazz.extends)}` : null); clazz.extends ? `I${toTitleCase(clazz.extends)}` : null);
@ -278,7 +286,22 @@ function renderConstructors(name, type, out) {
} }
/** /**
* * @param {Documentation.Member} member
* @param {string[]} out
*/
function renderMemberDoc(member, out) {
/** @type {Documentation.MarkdownNode[]} */
const nodes = [];
if (member.deprecated)
nodes.push({ type: 'text', text: '**DEPRECATED** ' + member.deprecated });
if (member.discouraged)
nodes.push({ type: 'text', text: member.discouraged });
if (member.spec)
nodes.push(...member.spec);
out.push(...XmlDoc.renderXmlDoc(nodes, maxDocumentationColumnWidth));
}
/**
* @param {Documentation.Member} member * @param {Documentation.Member} member
* @param {Documentation.Class|Documentation.Type} parent * @param {Documentation.Class|Documentation.Type} parent
* @param {{nojson?: boolean, trimRunAndPrefix?: boolean}} options * @param {{nojson?: boolean, trimRunAndPrefix?: boolean}} options
@ -296,8 +319,7 @@ function renderMember(member, parent, options, out) {
if (!member.type) if (!member.type)
throw new Error(`No Event Type for ${name} in ${parent.name}`); throw new Error(`No Event Type for ${name} in ${parent.name}`);
out.push(''); out.push('');
if (member.spec) renderMemberDoc(member, out);
out.push(...XmlDoc.renderXmlDoc(member.spec, maxDocumentationColumnWidth));
if (member.deprecated) if (member.deprecated)
out.push(`[System.Obsolete]`); out.push(`[System.Obsolete]`);
out.push(`event EventHandler<${type}> ${name};`); out.push(`event EventHandler<${type}> ${name};`);
@ -314,8 +336,7 @@ function renderMember(member, parent, options, out) {
const { name, jsonName } = overload; const { name, jsonName } = overload;
let { type } = overload; let { type } = overload;
out.push(''); out.push('');
if (member.spec) renderMemberDoc(member, out);
out.push(...XmlDoc.renderXmlDoc(member.spec, maxDocumentationColumnWidth));
if (!member.clazz) if (!member.clazz)
out.push(`${member.required ? '[Required]\n' : ''}[JsonPropertyName("${jsonName}")]`); out.push(`${member.required ? '[Required]\n' : ''}[JsonPropertyName("${jsonName}")]`);
if (member.deprecated) if (member.deprecated)
@ -623,7 +644,7 @@ function renderMethod(member, parent, name, options, out) {
if (!explodedArgs.length) { if (!explodedArgs.length) {
if (!options.nodocs) { if (!options.nodocs) {
out.push(...XmlDoc.renderXmlDoc(member.spec, maxDocumentationColumnWidth)); renderMemberDoc(member, out);
paramDocs.forEach((value, i) => printArgDoc(i, value, out)); paramDocs.forEach((value, i) => printArgDoc(i, value, out));
} }
if (member.deprecated) if (member.deprecated)
@ -633,7 +654,7 @@ function renderMethod(member, parent, name, options, out) {
let containsOptionalExplodedArgs = false; let containsOptionalExplodedArgs = false;
explodedArgs.forEach((explodedArg, argIndex) => { explodedArgs.forEach((explodedArg, argIndex) => {
if (!options.nodocs) if (!options.nodocs)
out.push(...XmlDoc.renderXmlDoc(member.spec, maxDocumentationColumnWidth)); renderMemberDoc(member, out);
const overloadedArgs = []; const overloadedArgs = [];
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
const arg = args[i]; const arg = args[i];
@ -662,7 +683,7 @@ function renderMethod(member, parent, name, options, out) {
if (containsOptionalExplodedArgs) { if (containsOptionalExplodedArgs) {
const filteredArgs = args.filter(x => x !== 'OPTIONAL_EXPLODED_ARG'); const filteredArgs = args.filter(x => x !== 'OPTIONAL_EXPLODED_ARG');
if (!options.nodocs) if (!options.nodocs)
out.push(...XmlDoc.renderXmlDoc(member.spec, maxDocumentationColumnWidth)); renderMemberDoc(member, out);
filteredArgs.forEach(arg => { filteredArgs.forEach(arg => {
if (arg === 'EXPLODED_ARG') if (arg === 'EXPLODED_ARG')
throw new Error(`Unsupported required union arg combined an optional union inside ${member.name}`); throw new Error(`Unsupported required union arg combined an optional union inside ${member.name}`);