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).
## async method: Locator.all
* since: v1.14
* since: v1.29
- returns: <[Array]<[Locator]>>
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
* since: v1.8
* langs: js, python, java
* langs: js, python
- `postData` <[string]|[Buffer]|[Serializable]>
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
* since: v1.8
* langs: csharp
@ -390,11 +397,18 @@ If set changes the request method (e.g. GET or POST).
### option: Route.fallback.postData
* since: v1.23
* langs: js, python, java
* langs: js, python
- `postData` <[string]|[Buffer]|[Serializable]>
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
* since: v1.23
* 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).
### option: Route.fetch.postData = %%-js-python-csharp-fetch-option-post-data-%%
### option: Route.fetch.postData
* langs: js, python
* 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
* since: v1.29
@ -611,28 +638,11 @@ Optional response body as raw bytes.
### option: Route.fulfill.json
* since: v1.29
* langs: js, python
* langs: js, python, csharp
- `json` <[Serializable]>
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
* since: v1.8
- `path` <[path]>

View file

@ -2,8 +2,7 @@
* since: v1.8
* extends: [Error]
TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g. [`method:
Locator.waitFor`] or [`method: BrowserType.launch`].
TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g. [`method: Locator.waitFor`] or [`method: BrowserType.launch`].
```js
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
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
* langs: js, python, csharp
- `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.
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
// 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
```js
// fixtures.ts
import { test as baseTest } from '@playwright/test';
export { expect } from '@playwright/test';
@ -371,15 +334,15 @@ const users = [
export const test = baseTest.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);
// 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.parallelIndex);
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');
// Create a unique username for each worker.
await page.getByLabel('User Name').fill(users[testInfo.workerIndex].username);
await page.getByLabel('Password').fill(users[testInfo.workerIndex].password);
await page.getByLabel('User Name').fill(users[testInfo.parallelIndex].username);
await page.getByLabel('Password').fill(users[testInfo.parallelIndex].password);
await page.getByText('Sign in').click();
await page.context().storageState({ path: fileName });
await page.close();

View file

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

View file

@ -14,19 +14,19 @@ This image is published on [Docker Hub].
### Pull the image
```bash js
docker pull mcr.microsoft.com/playwright:v1.29.0-focal
docker pull mcr.microsoft.com/playwright:v1.29.2-focal
```
```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
docker pull mcr.microsoft.com/playwright/dotnet:v1.29.0-focal
docker pull mcr.microsoft.com/playwright/dotnet:v1.29.2-focal
```
```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
@ -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.
```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
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
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
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
@ -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.
```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
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
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
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:

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>
<button>Add to cart</button>
</li>
<ul>
</ul>
```
### Filter by text

View file

@ -4,6 +4,63 @@ title: "Release notes"
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
### Playwright Tools

View file

@ -4,6 +4,44 @@ title: "Release notes"
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
### Playwright Tools

View file

@ -4,6 +4,94 @@ title: "Release notes"
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
<div className="embed-youtube">
@ -218,7 +306,7 @@ This version was also tested against the following stable channels:
### 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 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.
@ -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 ⚠️

View file

@ -4,6 +4,66 @@ title: "Release notes"
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
### Playwright Tools
@ -122,7 +182,7 @@ This version was also tested against the following stable channels:
### 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).
* ⚠️ 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:
```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
npx playwright test --update-snapshots
```

75
package-lock.json generated
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -78,8 +78,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined,
'generic-linux': 'builds/chromium/%s/chromium-linux.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',
'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',
'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
'debian11': 'builds/chromium/%s/chromium-linux.zip',
@ -96,8 +98,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined,
'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',
'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',
'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',
'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',
@ -114,8 +118,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined,
'generic-linux': 'builds/chromium/%s/chromium-with-symbols-linux.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',
'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',
'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
'debian11': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
@ -132,8 +138,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined,
'generic-linux': 'builds/firefox/%s/firefox-ubuntu-20.04.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',
'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',
'ubuntu22.04-arm64': 'builds/firefox/%s/firefox-ubuntu-22.04-arm64.zip',
'debian11': 'builds/firefox/%s/firefox-debian-11.zip',
@ -150,8 +158,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined,
'generic-linux': 'builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip',
'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',
'ubuntu22.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-22.04.zip',
'ubuntu18.04-arm64': undefined,
'ubuntu20.04-arm64': undefined,
'ubuntu22.04-arm64': 'builds/firefox-beta/%s/firefox-beta-ubuntu-22.04-arm64.zip',
'debian11': 'builds/firefox-beta/%s/firefox-beta-debian-11.zip',
@ -168,8 +178,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined,
'generic-linux': 'builds/webkit/%s/webkit-ubuntu-20.04.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',
'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',
'ubuntu22.04-arm64': 'builds/webkit/%s/webkit-ubuntu-22.04-arm64.zip',
'debian11': 'builds/webkit/%s/webkit-debian-11.zip',
@ -186,8 +198,10 @@ const DOWNLOAD_PATHS = {
'<unknown>': undefined,
'generic-linux': 'builds/ffmpeg/%s/ffmpeg-linux.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',
'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',
'ubuntu22.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.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[]) {
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;
}
const distributionInfo = await getLinuxDistributionInfo();

View file

@ -19,6 +19,168 @@
// ./utils/linux-browser-dependencies/run.sh ubuntu:20.04
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': {
tools: [
'xvfb',

View file

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

View file

@ -286,7 +286,8 @@ export interface Page {
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
* 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>;
/**
* **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
* 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>;
/**
* **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 return value resolves to `[]`.
@ -315,7 +318,8 @@ export interface Page {
*/
$$<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 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.
* 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
* `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>;
/**
* **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
* `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>;
/**
* **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
* `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>;
/**
* **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
* `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>;
/**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better
* job.
* **NOTE** In most cases,
* [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
* 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>;
/**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better
* job.
* **NOTE** In most cases,
* [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
* 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>;
/**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better
* job.
* **NOTE** In most cases,
* [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
* 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>;
/**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better
* job.
* **NOTE** In most cases,
* [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
* elements as a first argument to `pageFunction`. Returns the result of `pageFunction` invocation.
@ -1797,7 +1813,8 @@ export interface Page {
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:
* 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>;
/**
* **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:
* 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;
/**
* **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:
* 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>;
/**
* **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,
* `click` is dispatched. This is equivalent to calling
@ -2298,7 +2319,8 @@ export interface Page {
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,
* 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>;
/**
* **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
* method waits until a matching element appears in the DOM.
@ -2420,7 +2443,9 @@ export interface Page {
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.
* @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>;
/**
* **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:
* 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>;
/**
* **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`.
* @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>;
/**
* **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`.
* @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>;
/**
* **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.
*
@ -2923,7 +2953,8 @@ export interface Page {
}): 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.
* @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;
/**
* **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).
* @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>;
/**
* **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).
* @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>;
/**
* **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).
* @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>;
/**
* **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
* does not match any elements is considered hidden.
@ -3040,14 +3077,16 @@ export interface Page {
strict?: boolean;
/**
* @deprecated This option is ignored. [`method: Page.isHidden`] does not wait for the element to become hidden and returns
* immediately.
* @deprecated This option is ignored.
* [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;
}): 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
* is considered not visible.
@ -3063,8 +3102,9 @@ export interface Page {
strict?: boolean;
/**
* @deprecated This option is ignored. [`method: Page.isVisible`] does not wait for the element to become visible and returns
* immediately.
* @deprecated This option is ignored.
* [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;
}): Promise<boolean>;
@ -3269,7 +3309,8 @@ export interface Page {
}): 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
* [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>;
/**
* **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
* until all specified options are present in the `<select>` element and selects these options.
@ -3580,7 +3623,9 @@ export interface Page {
}): 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:
* 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>;
/**
* **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
* 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>;
/**
* **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:
* 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>;
/**
* **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`.
* @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;
/**
* **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
* send fine-grained keyboard events. To fill values in form fields, use
@ -3973,7 +4024,8 @@ export interface Page {
}): 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:
* 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>>;
/**
* **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.
*
@ -4705,7 +4758,8 @@ export interface Frame {
*/
$<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.
*
@ -4719,7 +4773,8 @@ export interface Frame {
$(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.
*
@ -4731,7 +4786,8 @@ export interface Frame {
*/
$$<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.
*
@ -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
* 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`.
*
@ -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>;
/**
* **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`.
*
@ -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>;
/**
* **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`.
*
@ -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>;
/**
* **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`.
*
@ -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>;
/**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better
* job.
* **NOTE** In most cases,
* [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`.
*
@ -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>;
/**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better
* job.
* **NOTE** In most cases,
* [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`.
*
@ -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>;
/**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better
* job.
* **NOTE** In most cases,
* [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`.
*
@ -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>;
/**
* **NOTE** In most cases, [`method: Locator.evaluateAll`], other [Locator] helper methods and web-first assertions do a better
* job.
* **NOTE** In most cases,
* [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`.
*
@ -5210,7 +5278,8 @@ export interface Frame {
}): 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:
* 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>;
/**
* **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:
* 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>;
/**
* **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:
* 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>;
/**
* **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,
* `click` is dispatched. This is equivalent to calling
@ -5562,7 +5635,8 @@ export interface Frame {
}): 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,
* 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>;
/**
* **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
* method waits until a matching element appears in the DOM.
@ -5672,7 +5747,9 @@ export interface Frame {
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.
* @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>;
/**
* **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:
* 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>;
/**
* **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`.
* @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>;
/**
* **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`.
* @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>;
/**
* **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.
*
@ -6113,7 +6195,8 @@ export interface Frame {
}): 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.
* @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;
/**
* **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).
* @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>;
/**
* **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).
* @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>;
/**
* **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
* does not match any elements is considered hidden.
@ -6228,14 +6316,16 @@ export interface Frame {
strict?: boolean;
/**
* @deprecated This option is ignored. [`method: Frame.isHidden`] does not wait for the element to become hidden and returns
* immediately.
* @deprecated This option is ignored.
* [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;
}): 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
* is considered not visible.
@ -6251,8 +6341,9 @@ export interface Frame {
strict?: boolean;
/**
* @deprecated This option is ignored. [`method: Frame.isVisible`] does not wait for the element to become visible and returns
* immediately.
* @deprecated This option is ignored.
* [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;
}): Promise<boolean>;
@ -6306,7 +6397,8 @@ export interface 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
* [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>;
/**
* **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
* until all specified options are present in the `<select>` element and selects these options.
@ -6452,7 +6546,9 @@ export interface Frame {
}): 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:
* 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>;
/**
* **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
* 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>;
/**
* **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:
* 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>;
/**
* **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`.
* @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>;
/**
* **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
* to send fine-grained keyboard events. To fill values in form fields, use
@ -6762,7 +6864,8 @@ export interface Frame {
}): 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:
* 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?: {
/**
* @deprecated This option is ignored. [`method: Locator.isHidden`] does not wait for the element to become hidden and returns
* immediately.
* @deprecated This option is ignored.
* [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;
}): Promise<boolean>;
@ -10810,8 +10914,9 @@ export interface Locator {
*/
isVisible(options?: {
/**
* @deprecated This option is ignored. [`method: Locator.isVisible`] does not wait for the element to become visible and returns
* immediately.
* @deprecated This option is ignored.
* [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;
}): Promise<boolean>;
@ -11874,7 +11979,7 @@ export interface BrowserType<Unused = {}> {
userAgent?: string;
/**
* @deprecated Use [`option: recordVideo`] instead.
* @deprecated Use `recordVideo` instead.
*/
videoSize?: {
/**
@ -11889,7 +11994,7 @@ export interface BrowserType<Unused = {}> {
};
/**
* @deprecated Use [`option: recordVideo`] instead.
* @deprecated Use `recordVideo` instead.
*/
videosPath?: string;
@ -12133,8 +12238,9 @@ export namespace errors {
/**
* - extends: [Error]
*
* TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g. [`method: Locator.waitFor`]
* or [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browser-type-launch).
* TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g.
* [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
* const playwright = require('playwright');
@ -13236,7 +13342,7 @@ export interface AndroidDevice {
userAgent?: string;
/**
* @deprecated Use [`option: recordVideo`] instead.
* @deprecated Use `recordVideo` instead.
*/
videoSize?: {
/**
@ -13251,7 +13357,7 @@ export interface AndroidDevice {
};
/**
* @deprecated Use [`option: recordVideo`] instead.
* @deprecated Use `recordVideo` instead.
*/
videosPath?: string;
@ -15138,7 +15244,7 @@ export interface Browser extends EventEmitter {
userAgent?: string;
/**
* @deprecated Use [`option: recordVideo`] instead.
* @deprecated Use `recordVideo` instead.
*/
videoSize?: {
/**
@ -15153,7 +15259,7 @@ export interface Browser extends EventEmitter {
};
/**
* @deprecated Use [`option: recordVideo`] instead.
* @deprecated Use `recordVideo` instead.
*/
videosPath?: string;
@ -18087,7 +18193,7 @@ export interface BrowserContextOptions {
userAgent?: string;
/**
* @deprecated Use [`option: recordVideo`] instead.
* @deprecated Use `recordVideo` instead.
*/
videoSize?: {
/**
@ -18102,7 +18208,7 @@ export interface BrowserContextOptions {
};
/**
* @deprecated Use [`option: recordVideo`] instead.
* @deprecated Use `recordVideo` instead.
*/
videosPath?: string;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/test",
"version": "1.29.0-next",
"version": "1.29.2",
"description": "A high-level API to automate web browsers",
"repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev",
@ -34,6 +34,6 @@
"license": "Apache-2.0",
"dependencies": {
"@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 { createGuid, debugMode } from 'playwright-core/lib/utils';
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 type { TestInfoImpl } from './testInfo';
import { rootTestType, _setProjectSetup } from './testType';
@ -246,8 +246,8 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
if (debugMode())
testInfo.setTimeout(0);
const screenshotOptions = typeof screenshot !== 'string' ? { fullPage: screenshot.fullPage, omitBackground: screenshot.omitBackground } : undefined;
const screenshotMode = typeof screenshot === 'string' ? screenshot : screenshot.mode;
const screenshotMode = normalizeScreenshotMode(screenshot);
const screenshotOptions = typeof screenshot === 'string' ? undefined : screenshot;
const traceMode = normalizeTraceMode(trace);
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true };
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);
}
function normalizeScreenshotMode(screenshot: PlaywrightWorkerOptions['screenshot'] | undefined): ScreenshotMode {
if (!screenshot)
return 'off';
return typeof screenshot === 'string' ? screenshot : screenshot.mode;
}
const kTracingStarted = Symbol('kTracingStarted');
export const test = _baseTest.extend<TestFixtures, WorkerFixtures>(playwrightFixtures);

View file

@ -358,5 +358,5 @@ export async function toPass(
`- ${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' };
// Remove output directores.
if (!this._removeOutputDirs(options))
if (!await this._removeOutputDirs(options))
return { status: 'failed' };
// Run Global setup.

View file

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

View file

@ -1,6 +1,6 @@
{
"name": "playwright",
"version": "1.29.0-next",
"version": "1.29.2",
"description": "A high-level API to automate web browsers",
"repository": "github:Microsoft/playwright",
"homepage": "https://playwright.dev",
@ -28,6 +28,6 @@
"install": "node install.js"
},
"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 { electronTest as test, expect } from './electronTest';
test('should fire close event', async ({ playwright }) => {
const electronApp = await playwright._electron.launch({
args: [path.join(__dirname, 'electron-app.js')],
});
test('should fire close event', async ({ launchElectronApp }) => {
const electronApp = await launchElectronApp('electron-app.js');
const events = [];
electronApp.on('close', () => events.push('application'));
electronApp.context().on('close', () => events.push('context'));
@ -33,11 +31,8 @@ test('should fire close event', async ({ playwright }) => {
expect(events.join('|')).toBe('context|application');
});
test('should dispatch ready event', async ({ playwright }) => {
const electronApp = await playwright._electron.launch({
args: [path.join(__dirname, 'electron-app-ready-event.js')],
});
try {
test('should dispatch ready event', async ({ launchElectronApp }) => {
const electronApp = await launchElectronApp('electron-app-ready-event.js');
const events = await electronApp.evaluate(() => globalThis.__playwrightLog);
expect(events).toEqual([
'isReady == false',
@ -46,9 +41,6 @@ test('should dispatch ready event', async ({ playwright }) => {
'whenReady resolved',
'isReady == true',
]);
} finally {
await electronApp.close();
}
});
test('should script application', async ({ electronApp }) => {
@ -114,28 +106,19 @@ test('should have a clipboard instance', async ({ electronApp }) => {
expect(clipboardContentRead).toEqual(clipboardContentToWrite);
});
test('should test app that opens window fast', async ({ playwright }) => {
const electronApp = await playwright._electron.launch({
args: [path.join(__dirname, 'electron-window-app.js')],
});
await electronApp.close();
test('should test app that opens window fast', async ({ launchElectronApp }) => {
await launchElectronApp('electron-window-app.js');
});
test('should return browser window', async ({ playwright }) => {
const electronApp = await playwright._electron.launch({
args: [path.join(__dirname, 'electron-window-app.js')],
});
test('should return browser window', async ({ launchElectronApp }) => {
const electronApp = await launchElectronApp('electron-window-app.js');
const page = await electronApp.firstWindow();
const bwHandle = await electronApp.browserWindow(page);
expect(await bwHandle.evaluate((bw: BrowserWindow) => bw.title)).toBe('Electron');
await electronApp.close();
});
test('should bypass csp', async ({ playwright, server }) => {
const app = await playwright._electron.launch({
args: [require('path').join(__dirname, 'electron-app.js')],
bypassCSP: true,
});
test('should bypass csp', async ({ launchElectronApp, server }) => {
const app = await launchElectronApp('electron-app.js', { bypassCSP: true });
await app.evaluate(electron => {
const window = new electron.BrowserWindow({
width: 800,
@ -147,13 +130,10 @@ test('should bypass csp', async ({ playwright, server }) => {
await page.goto(server.PREFIX + '/csp.html');
await page.addScriptTag({ content: 'window["__injected"] = 42;' });
expect(await page.evaluate('window["__injected"]')).toBe(42);
await app.close();
});
test('should create page for browser view', async ({ playwright }) => {
const app = await playwright._electron.launch({
args: [path.join(__dirname, 'electron-window-app.js')],
});
test('should create page for browser view', async ({ launchElectronApp }) => {
const app = await launchElectronApp('electron-window-app.js');
await app.firstWindow();
await app.evaluate(async electron => {
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 });
});
await expect.poll(() => app.windows().length).toBe(2);
await app.close();
});
test('should return same browser window for browser view pages', async ({ playwright }) => {
const app = await playwright._electron.launch({
args: [path.join(__dirname, 'electron-window-app.js')],
});
test('should return same browser window for browser view pages', async ({ launchElectronApp }) => {
const app = await launchElectronApp('electron-window-app.js');
await app.firstWindow();
await app.evaluate(async electron => {
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);
await app.close();
});
test('should record video', async ({ playwright }, testInfo) => {
const app = await playwright._electron.launch({
args: [path.join(__dirname, 'electron-window-app.js')],
test('should record video', async ({ launchElectronApp }, testInfo) => {
const app = await launchElectronApp('electron-window-app.js', {
recordVideo: { dir: testInfo.outputPath('video') }
});
const page = await app.firstWindow();
@ -203,25 +178,31 @@ test('should record video', async ({ playwright }, testInfo) => {
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' });
const app = await playwright._electron.launch({
args: [path.join(__dirname, 'electron-window-app-delayed-loadURL.js')],
});
const app = await launchElectronApp('electron-window-app-delayed-loadURL.js');
const page = await app.firstWindow();
await expect(page).toHaveURL('data:text/html,<h1>Foobar</h1>');
await expect(page.locator('h1')).toHaveText('Foobar');
await app.close();
});
test('should detach debugger on app-initiated exit', async ({ playwright }) => {
const electronApp = await playwright._electron.launch({
args: [path.join(__dirname, 'electron-app.js')],
});
test('should detach debugger on app-initiated exit', async ({ launchElectronApp }) => {
const electronApp = await launchElectronApp('electron-app.js');
const closePromise = new Promise(f => electronApp.process().on('close', f));
await electronApp.evaluate(({ app }) => {
app.quit();
});
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 & {
electronApp: ElectronApplication;
launchElectronApp: (appFile: string, options?: any) => Promise<ElectronApplication>;
newWindow: () => Promise<Page>;
};
@ -40,14 +41,21 @@ export const electronTest = baseTest.extend<TraceViewerFixtures>(traceViewerFixt
isElectron: [true, { scope: 'worker' }],
isWebView2: [false, { scope: 'worker' }],
electronApp: async ({ playwright }, run) => {
launchElectronApp: async ({ playwright }, use) => {
// This env prevents 'Electron Security Policy' console message.
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
const electronApp = await playwright._electron.launch({
args: [path.join(__dirname, 'electron-app.js')],
const apps: ElectronApplication[] = [];
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);
await electronApp.close();
for (const app of apps)
await app.close();
},
electronApp: async ({ launchElectronApp }, use) => {
await use(await launchElectronApp('electron-app.js'));
},
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 = {
connect: (wsEndpoint: string, options?: ConnectOptions, redirectPortForTest?: number) => Promise<Browser>,
dummyServerPort: number,
ipV6ServerUrl: string,
};
const test = playwrightTest.extend<ExtraFixtures>({
connect: async ({ browserType }, use) => {
@ -54,6 +55,16 @@ const test = playwrightTest.extend<ExtraFixtures>({
await use((server.address() as net.AddressInfo).port);
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');
@ -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 }) => {
const remoteServer = await startRemoteServer(kind);
@ -679,6 +700,7 @@ for (const kind of ['launchServer', 'run-server'] as const) {
test.describe('socks proxy', () => {
test.fixme(({ platform, browserName }) => browserName === 'webkit' && platform === 'win32');
test.skip(({ mode }) => mode !== 'default');
test.skip(kind === 'launchServer', 'not supported yet');
test('should forward non-forwarded requests', async ({ server, startRemoteServer, connect }) => {
let reachedOriginalTarget = false;

View file

@ -167,3 +167,16 @@ test('should work with soft', async ({ runInlineTest }) => {
expect(result.exitCode).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.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
*/
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 => {
if (!node.text)
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) => {
const isInternal = !linkUrl.startsWith('http://') && !linkUrl.startsWith('https://');
if (isInternal)

View file

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