Compare commits
21 commits
main
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a51d4a39b8 | ||
|
|
f11873a895 | ||
|
|
b5ff463779 | ||
|
|
4417a97482 | ||
|
|
2f3d88f3d5 | ||
|
|
ba85623f40 | ||
|
|
fe024dd5e3 | ||
|
|
ac4127d6cf | ||
|
|
b8761ef8de | ||
|
|
55eebadfa2 | ||
|
|
bc9f9b79c8 | ||
|
|
4aee014caf | ||
|
|
bf25a93617 | ||
|
|
7effaf4f22 | ||
|
|
ef18287266 | ||
|
|
552cba8c05 | ||
|
|
cd94a3f01d | ||
|
|
3543a741fd | ||
|
|
7196f82e52 | ||
|
|
32c247b815 | ||
|
|
c551cce74e |
|
|
@ -1,6 +1,6 @@
|
||||||
# 🎭 Playwright
|
# 🎭 Playwright
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[](https://webkit.org/)<!-- GEN:stop -->
|
[](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[](https://webkit.org/)<!-- GEN:stop -->
|
||||||
|
|
||||||
## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright)
|
## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright)
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ Playwright is a framework for Web Testing and Automation. It allows testing [Chr
|
||||||
|
|
||||||
| | Linux | macOS | Windows |
|
| | Linux | macOS | Windows |
|
||||||
| :--- | :---: | :---: | :---: |
|
| :--- | :---: | :---: | :---: |
|
||||||
| Chromium <!-- GEN:chromium-version -->114.0.5735.26<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
| Chromium <!-- GEN:chromium-version -->114.0.5735.35<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||||
| WebKit <!-- GEN:webkit-version -->16.4<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
| WebKit <!-- GEN:webkit-version -->16.4<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||||
| Firefox <!-- GEN:firefox-version -->113.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
| Firefox <!-- GEN:firefox-version -->113.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ Emitted when Browser context gets closed. This might happen because of one of th
|
||||||
* The [`method: Browser.close`] method was called.
|
* The [`method: Browser.close`] method was called.
|
||||||
|
|
||||||
## event: BrowserContext.console
|
## event: BrowserContext.console
|
||||||
* since: v1.33
|
* since: v1.34
|
||||||
* langs:
|
* langs:
|
||||||
- alias-java: consoleMessage
|
- alias-java: consoleMessage
|
||||||
- argument: <[ConsoleMessage]>
|
- argument: <[ConsoleMessage]>
|
||||||
|
|
@ -156,7 +156,7 @@ await page.EvaluateAsync("console.log('hello', 5, { foo: 'bar' })");
|
||||||
|
|
||||||
|
|
||||||
## event: BrowserContext.dialog
|
## event: BrowserContext.dialog
|
||||||
* since: v1.33
|
* since: v1.34
|
||||||
- argument: <[Dialog]>
|
- argument: <[Dialog]>
|
||||||
|
|
||||||
Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` or `beforeunload`. Listener **must** either [`method: Dialog.accept`] or [`method: Dialog.dismiss`] the dialog - otherwise the page will [freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking) waiting for the dialog, and actions like click will never finish.
|
Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` or `beforeunload`. Listener **must** either [`method: Dialog.accept`] or [`method: Dialog.dismiss`] the dialog - otherwise the page will [freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking) waiting for the dialog, and actions like click will never finish.
|
||||||
|
|
@ -180,10 +180,7 @@ context.on("dialog", lambda dialog: dialog.accept())
|
||||||
```
|
```
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
context.RequestFailed += (_, request) =>
|
context.Dialog += (_, dialog) => dialog.AcceptAsync();
|
||||||
{
|
|
||||||
Console.WriteLine(request.Url + " " + request.Failure);
|
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
@ -1456,6 +1453,37 @@ Condition to wait for.
|
||||||
### option: BrowserContext.waitForCondition.timeout = %%-wait-for-function-timeout-%%
|
### option: BrowserContext.waitForCondition.timeout = %%-wait-for-function-timeout-%%
|
||||||
* since: v1.32
|
* since: v1.32
|
||||||
|
|
||||||
|
## async method: BrowserContext.waitForConsoleMessage
|
||||||
|
* since: v1.34
|
||||||
|
* langs: java, python, csharp
|
||||||
|
- alias-python: expect_console_message
|
||||||
|
- alias-csharp: RunAndWaitForConsoleMessage
|
||||||
|
- returns: <[ConsoleMessage]>
|
||||||
|
|
||||||
|
Performs action and waits for a [ConsoleMessage] to be logged by in the pages in the context. If predicate is provided, it passes
|
||||||
|
[ConsoleMessage] value into the `predicate` function and waits for `predicate(message)` to return a truthy value.
|
||||||
|
Will throw an error if the page is closed before the [`event: BrowserContext.console`] event is fired.
|
||||||
|
|
||||||
|
## async method: BrowserContext.waitForConsoleMessage
|
||||||
|
* since: v1.34
|
||||||
|
* langs: python
|
||||||
|
- returns: <[EventContextManager]<[ConsoleMessage]>>
|
||||||
|
|
||||||
|
### param: BrowserContext.waitForConsoleMessage.action = %%-csharp-wait-for-event-action-%%
|
||||||
|
* since: v1.34
|
||||||
|
|
||||||
|
### option: BrowserContext.waitForConsoleMessage.predicate
|
||||||
|
* since: v1.34
|
||||||
|
- `predicate` <[function]\([ConsoleMessage]\):[boolean]>
|
||||||
|
|
||||||
|
Receives the [ConsoleMessage] object and resolves to truthy value when the waiting should resolve.
|
||||||
|
|
||||||
|
### option: BrowserContext.waitForConsoleMessage.timeout = %%-wait-for-event-timeout-%%
|
||||||
|
* since: v1.34
|
||||||
|
|
||||||
|
### param: BrowserContext.waitForConsoleMessage.callback = %%-java-wait-for-event-callback-%%
|
||||||
|
* since: v1.34
|
||||||
|
|
||||||
## async method: BrowserContext.waitForEvent
|
## async method: BrowserContext.waitForEvent
|
||||||
* since: v1.8
|
* since: v1.8
|
||||||
* langs: js, python
|
* langs: js, python
|
||||||
|
|
|
||||||
|
|
@ -126,8 +126,8 @@ List of arguments passed to a `console` function call. See also [`event: Page.co
|
||||||
URL of the resource followed by 0-based line and column numbers in the resource formatted as `URL:line:column`.
|
URL of the resource followed by 0-based line and column numbers in the resource formatted as `URL:line:column`.
|
||||||
|
|
||||||
## method: ConsoleMessage.page
|
## method: ConsoleMessage.page
|
||||||
* since: v1.33
|
* since: v1.34
|
||||||
- returns: <[Page]|[null]>
|
- returns: <[null]|[Page]>
|
||||||
|
|
||||||
The page that produced this console message, if any.
|
The page that produced this console message, if any.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,8 +138,8 @@ Returns when the dialog has been dismissed.
|
||||||
A message displayed in the dialog.
|
A message displayed in the dialog.
|
||||||
|
|
||||||
## method: Dialog.page
|
## method: Dialog.page
|
||||||
* since: v1.33
|
* since: v1.34
|
||||||
- returns: <[Page]|[null]>
|
- returns: <[null]|[Page]>
|
||||||
|
|
||||||
The page that initiated this dialog, if available.
|
The page that initiated this dialog, if available.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ jobs:
|
||||||
name: 'Playwright Tests'
|
name: 'Playwright Tests'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: mcr.microsoft.com/playwright:v1.34.0-jammy
|
image: mcr.microsoft.com/playwright:v1.34.3-jammy
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
|
|
@ -256,7 +256,7 @@ jobs:
|
||||||
name: 'Playwright Tests'
|
name: 'Playwright Tests'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: mcr.microsoft.com/playwright/python:v1.34.0-jammy
|
image: mcr.microsoft.com/playwright/python:v1.34.3-jammy
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
|
|
@ -284,7 +284,7 @@ jobs:
|
||||||
name: 'Playwright Tests'
|
name: 'Playwright Tests'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: mcr.microsoft.com/playwright/java:v1.34.0-jammy
|
image: mcr.microsoft.com/playwright/java:v1.34.3-jammy
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v3
|
||||||
|
|
@ -309,7 +309,7 @@ jobs:
|
||||||
name: 'Playwright Tests'
|
name: 'Playwright Tests'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: mcr.microsoft.com/playwright/dotnet:v1.34.0-jammy
|
image: mcr.microsoft.com/playwright/dotnet:v1.34.3-jammy
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
|
|
@ -338,7 +338,7 @@ jobs:
|
||||||
name: 'Playwright Tests - ${{ matrix.project }} - Shard ${{ matrix.shardIndex }} of ${{ matrix.shardTotal }}'
|
name: 'Playwright Tests - ${{ matrix.project }} - Shard ${{ matrix.shardIndex }} of ${{ matrix.shardTotal }}'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: mcr.microsoft.com/playwright:v1.34.0-jammy
|
image: mcr.microsoft.com/playwright:v1.34.3-jammy
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
|
@ -413,7 +413,7 @@ jobs:
|
||||||
- deployment: Run_E2E_Tests
|
- deployment: Run_E2E_Tests
|
||||||
pool:
|
pool:
|
||||||
vmImage: ubuntu-22.04
|
vmImage: ubuntu-22.04
|
||||||
container: mcr.microsoft.com/playwright:v1.34.0-jammy
|
container: mcr.microsoft.com/playwright:v1.34.3-jammy
|
||||||
environment: testing
|
environment: testing
|
||||||
strategy:
|
strategy:
|
||||||
runOnce:
|
runOnce:
|
||||||
|
|
@ -439,7 +439,7 @@ jobs:
|
||||||
- deployment: Run_E2E_Tests
|
- deployment: Run_E2E_Tests
|
||||||
pool:
|
pool:
|
||||||
vmImage: ubuntu-22.04
|
vmImage: ubuntu-22.04
|
||||||
container: mcr.microsoft.com/playwright:v1.34.0-jammy
|
container: mcr.microsoft.com/playwright:v1.34.3-jammy
|
||||||
environment: testing
|
environment: testing
|
||||||
strategy:
|
strategy:
|
||||||
runOnce:
|
runOnce:
|
||||||
|
|
@ -483,7 +483,7 @@ Running Playwright on CircleCI is very similar to running on GitHub Actions. In
|
||||||
executors:
|
executors:
|
||||||
pw-jammy-development:
|
pw-jammy-development:
|
||||||
docker:
|
docker:
|
||||||
- image: mcr.microsoft.com/playwright:v1.34.0-jammy
|
- image: mcr.microsoft.com/playwright:v1.34.3-jammy
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: When using the docker agent definition, you are specifying the resource class of where playwright runs to the 'medium' tier [here](https://circleci.com/docs/configuration-reference?#docker-execution-environment). The default behavior of Playwright is to set the number of workers to the detected core count (2 in the case of the medium tier). Overriding the number of workers to greater than this number will cause unnecessary timeouts and failures.
|
Note: When using the docker agent definition, you are specifying the resource class of where playwright runs to the 'medium' tier [here](https://circleci.com/docs/configuration-reference?#docker-execution-environment). The default behavior of Playwright is to set the number of workers to the detected core count (2 in the case of the medium tier). Overriding the number of workers to greater than this number will cause unnecessary timeouts and failures.
|
||||||
|
|
@ -507,7 +507,7 @@ to run tests on Jenkins.
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
pipeline {
|
pipeline {
|
||||||
agent { docker { image 'mcr.microsoft.com/playwright:v1.34.0-jammy' } }
|
agent { docker { image 'mcr.microsoft.com/playwright:v1.34.3-jammy' } }
|
||||||
stages {
|
stages {
|
||||||
stage('e2e-tests') {
|
stage('e2e-tests') {
|
||||||
steps {
|
steps {
|
||||||
|
|
@ -525,7 +525,7 @@ pipeline {
|
||||||
Bitbucket Pipelines can use public [Docker images as build environments](https://confluence.atlassian.com/bitbucket/use-docker-images-as-build-environments-792298897.html). To run Playwright tests on Bitbucket, use our public Docker image ([see Dockerfile](./docker.md)).
|
Bitbucket Pipelines can use public [Docker images as build environments](https://confluence.atlassian.com/bitbucket/use-docker-images-as-build-environments-792298897.html). To run Playwright tests on Bitbucket, use our public Docker image ([see Dockerfile](./docker.md)).
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
image: mcr.microsoft.com/playwright:v1.34.0-jammy
|
image: mcr.microsoft.com/playwright:v1.34.3-jammy
|
||||||
```
|
```
|
||||||
|
|
||||||
### GitLab CI
|
### GitLab CI
|
||||||
|
|
@ -538,7 +538,7 @@ stages:
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
stage: test
|
stage: test
|
||||||
image: mcr.microsoft.com/playwright:v1.34.0-jammy
|
image: mcr.microsoft.com/playwright:v1.34.3-jammy
|
||||||
script:
|
script:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
@ -554,7 +554,7 @@ stages:
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
stage: test
|
stage: test
|
||||||
image: mcr.microsoft.com/playwright:v1.34.0-jammy
|
image: mcr.microsoft.com/playwright:v1.34.3-jammy
|
||||||
parallel: 7
|
parallel: 7
|
||||||
script:
|
script:
|
||||||
- npm ci
|
- npm ci
|
||||||
|
|
@ -569,7 +569,7 @@ stages:
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
stage: test
|
stage: test
|
||||||
image: mcr.microsoft.com/playwright:v1.34.0-jammy
|
image: mcr.microsoft.com/playwright:v1.34.3-jammy
|
||||||
parallel:
|
parallel:
|
||||||
matrix:
|
matrix:
|
||||||
- PROJECT: ['chromium', 'webkit']
|
- PROJECT: ['chromium', 'webkit']
|
||||||
|
|
|
||||||
|
|
@ -18,19 +18,19 @@ This Docker image is intended to be used for testing and development purposes on
|
||||||
### Pull the image
|
### Pull the image
|
||||||
|
|
||||||
```bash js
|
```bash js
|
||||||
docker pull mcr.microsoft.com/playwright:v1.34.0-jammy
|
docker pull mcr.microsoft.com/playwright:v1.34.3-jammy
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash python
|
```bash python
|
||||||
docker pull mcr.microsoft.com/playwright/python:v1.34.0-jammy
|
docker pull mcr.microsoft.com/playwright/python:v1.34.3-jammy
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash csharp
|
```bash csharp
|
||||||
docker pull mcr.microsoft.com/playwright/dotnet:v1.34.0-jammy
|
docker pull mcr.microsoft.com/playwright/dotnet:v1.34.3-jammy
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash java
|
```bash java
|
||||||
docker pull mcr.microsoft.com/playwright/java:v1.34.0-jammy
|
docker pull mcr.microsoft.com/playwright/java:v1.34.3-jammy
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run the image
|
### Run the image
|
||||||
|
|
@ -42,19 +42,19 @@ By default, the Docker image will use the `root` user to run the browsers. This
|
||||||
On trusted websites, you can avoid creating a separate user and use root for it since you trust the code which will run on the browsers.
|
On trusted websites, you can avoid creating a separate user and use root for it since you trust the code which will run on the browsers.
|
||||||
|
|
||||||
```bash js
|
```bash js
|
||||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright:v1.34.0-jammy /bin/bash
|
docker run -it --rm --ipc=host mcr.microsoft.com/playwright:v1.34.3-jammy /bin/bash
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash python
|
```bash python
|
||||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/python:v1.34.0-jammy /bin/bash
|
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/python:v1.34.3-jammy /bin/bash
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash csharp
|
```bash csharp
|
||||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/dotnet:v1.34.0-jammy /bin/bash
|
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/dotnet:v1.34.3-jammy /bin/bash
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash java
|
```bash java
|
||||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/java:v1.34.0-jammy /bin/bash
|
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/java:v1.34.3-jammy /bin/bash
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Crawling and scraping
|
#### Crawling and scraping
|
||||||
|
|
@ -62,19 +62,19 @@ docker run -it --rm --ipc=host mcr.microsoft.com/playwright/java:v1.34.0-jammy /
|
||||||
On untrusted websites, it's recommended to use a separate user for launching the browsers in combination with the seccomp profile. Inside the container or if you are using the Docker image as a base image you have to use `adduser` for it.
|
On untrusted websites, it's recommended to use a separate user for launching the browsers in combination with the seccomp profile. Inside the container or if you are using the Docker image as a base image you have to use `adduser` for it.
|
||||||
|
|
||||||
```bash js
|
```bash js
|
||||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright:v1.34.0-jammy /bin/bash
|
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright:v1.34.3-jammy /bin/bash
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash python
|
```bash python
|
||||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/python:v1.34.0-jammy /bin/bash
|
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/python:v1.34.3-jammy /bin/bash
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash csharp
|
```bash csharp
|
||||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/dotnet:v1.34.0-jammy /bin/bash
|
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/dotnet:v1.34.3-jammy /bin/bash
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash java
|
```bash java
|
||||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/java:v1.34.0-jammy /bin/bash
|
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/java:v1.34.3-jammy /bin/bash
|
||||||
```
|
```
|
||||||
|
|
||||||
[`seccomp_profile.json`](https://github.com/microsoft/playwright/blob/main/utils/docker/seccomp_profile.json) is needed to run Chromium with sandbox. This is a [default Docker seccomp profile](https://github.com/docker/engine/blob/d0d99b04cf6e00ed3fc27e81fc3d94e7eda70af3/profiles/seccomp/default.json) with extra user namespace cloning permissions:
|
[`seccomp_profile.json`](https://github.com/microsoft/playwright/blob/main/utils/docker/seccomp_profile.json) is needed to run Chromium with sandbox. This is a [default Docker seccomp profile](https://github.com/docker/engine/blob/d0d99b04cf6e00ed3fc27e81fc3d94e7eda70af3/profiles/seccomp/default.json) with extra user namespace cloning permissions:
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@ import LiteYouTube from '@site/src/components/LiteYouTube';
|
||||||
|
|
||||||
## Version 1.34
|
## Version 1.34
|
||||||
|
|
||||||
### New APIs
|
### Highlights
|
||||||
|
|
||||||
|
* UI Mode now shows steps, fixtures and attachments:
|
||||||
|

|
||||||
* New property [`property: TestProject.teardown`] to specify a project that needs to run after this
|
* New property [`property: TestProject.teardown`] to specify a project that needs to run after this
|
||||||
and all dependent projects have finished. Teardown is useful to cleanup any resources acquired by this project.
|
and all dependent projects have finished. Teardown is useful to cleanup any resources acquired by this project.
|
||||||
|
|
||||||
|
|
@ -46,6 +48,18 @@ import LiteYouTube from '@site/src/components/LiteYouTube';
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
* New method [`expect.configure`](./test-assertions.md#expectconfigure) to
|
||||||
|
create pre-configured expect instance with its own defaults such as `timeout`
|
||||||
|
and `soft`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const slowExpect = expect.configure({ timeout: 10000 });
|
||||||
|
await slowExpect(locator).toHaveText('Submit');
|
||||||
|
|
||||||
|
// Always do soft assertions.
|
||||||
|
const softExpect = expect.configure({ soft: true });
|
||||||
|
```
|
||||||
|
|
||||||
* New options `stderr` and `stdout` in [`property: TestConfig.webServer`] to configure output handling:
|
* New options `stderr` and `stdout` in [`property: TestConfig.webServer`] to configure output handling:
|
||||||
|
|
||||||
```js title="playwright.config.ts"
|
```js title="playwright.config.ts"
|
||||||
|
|
|
||||||
|
|
@ -526,6 +526,7 @@ export default defineConfig({
|
||||||
* since: v1.10
|
* since: v1.10
|
||||||
- type: <[Object]|[TraceMode]<"off"|"on"|"retain-on-failure"|"on-first-retry">>
|
- type: <[Object]|[TraceMode]<"off"|"on"|"retain-on-failure"|"on-first-retry">>
|
||||||
- `mode` <[TraceMode]<"off"|"on"|"retain-on-failure"|"on-first-retry"|"on-all-retries">> Trace recording mode.
|
- `mode` <[TraceMode]<"off"|"on"|"retain-on-failure"|"on-first-retry"|"on-all-retries">> Trace recording mode.
|
||||||
|
- `attachments` ?<[boolean]> Whether to include test attachments. Defaults to true. Optional.
|
||||||
- `screenshots` ?<[boolean]> Whether to capture screenshots during tracing. Screenshots are used to build a timeline preview. Defaults to true. Optional.
|
- `screenshots` ?<[boolean]> Whether to capture screenshots during tracing. Screenshots are used to build a timeline preview. Defaults to true. Optional.
|
||||||
- `snapshots` ?<[boolean]> Whether to capture DOM snapshot on every action. Defaults to true. Optional.
|
- `snapshots` ?<[boolean]> Whether to capture DOM snapshot on every action. Defaults to true. Optional.
|
||||||
- `sources` ?<[boolean]> Whether to include source files for trace actions. Defaults to true. Optional.
|
- `sources` ?<[boolean]> Whether to include source files for trace actions. Defaults to true. Optional.
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,10 @@ defaults such as `timeout` and `soft`.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const slowExpect = expect.configure({ timeout: 10000 });
|
const slowExpect = expect.configure({ timeout: 10000 });
|
||||||
await slowExpect(locator).toHaveText('Submit);
|
await slowExpect(locator).toHaveText('Submit');
|
||||||
|
|
||||||
|
// Always do soft assertions.
|
||||||
|
const softExpect = expect.configure({ soft: true });
|
||||||
```
|
```
|
||||||
|
|
||||||
## expect.poll
|
## expect.poll
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ The snapshot name `example-test-1-chromium-darwin.png` consists of a few parts:
|
||||||
If you are not on the same operating system as your CI system, you can use Docker to generate/update the screenshots:
|
If you are not on the same operating system as your CI system, you can use Docker to generate/update the screenshots:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.34.0-jammy /bin/bash
|
docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.34.3-jammy /bin/bash
|
||||||
npm install
|
npm install
|
||||||
npx playwright test --update-snapshots
|
npx playwright test --update-snapshots
|
||||||
```
|
```
|
||||||
|
|
|
||||||
78
package-lock.json
generated
78
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "playwright-internal",
|
"name": "playwright-internal",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "playwright-internal",
|
"name": "playwright-internal",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
@ -6197,11 +6197,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/playwright": {
|
"packages/playwright": {
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
|
|
@ -6211,11 +6211,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/playwright-chromium": {
|
"packages/playwright-chromium": {
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
|
|
@ -6225,7 +6225,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/playwright-core": {
|
"packages/playwright-core": {
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
|
|
@ -6233,10 +6233,10 @@
|
||||||
},
|
},
|
||||||
"packages/playwright-ct-core": {
|
"packages/playwright-ct-core": {
|
||||||
"name": "@playwright/experimental-ct-core",
|
"name": "@playwright/experimental-ct-core",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/test": "1.34.0-next",
|
"@playwright/test": "1.34.3",
|
||||||
"vite": "^4.3.3"
|
"vite": "^4.3.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -6248,10 +6248,10 @@
|
||||||
},
|
},
|
||||||
"packages/playwright-ct-react": {
|
"packages/playwright-ct-react": {
|
||||||
"name": "@playwright/experimental-ct-react",
|
"name": "@playwright/experimental-ct-react",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-react": "^4.0.0"
|
"@vitejs/plugin-react": "^4.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -6280,10 +6280,10 @@
|
||||||
},
|
},
|
||||||
"packages/playwright-ct-react17": {
|
"packages/playwright-ct-react17": {
|
||||||
"name": "@playwright/experimental-ct-react17",
|
"name": "@playwright/experimental-ct-react17",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-react": "^4.0.0"
|
"@vitejs/plugin-react": "^4.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -6312,10 +6312,10 @@
|
||||||
},
|
},
|
||||||
"packages/playwright-ct-solid": {
|
"packages/playwright-ct-solid": {
|
||||||
"name": "@playwright/experimental-ct-solid",
|
"name": "@playwright/experimental-ct-solid",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"vite-plugin-solid": "^2.7.0"
|
"vite-plugin-solid": "^2.7.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -6330,10 +6330,10 @@
|
||||||
},
|
},
|
||||||
"packages/playwright-ct-svelte": {
|
"packages/playwright-ct-svelte": {
|
||||||
"name": "@playwright/experimental-ct-svelte",
|
"name": "@playwright/experimental-ct-svelte",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.1.1"
|
"@sveltejs/vite-plugin-svelte": "^2.1.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -6348,10 +6348,10 @@
|
||||||
},
|
},
|
||||||
"packages/playwright-ct-vue": {
|
"packages/playwright-ct-vue": {
|
||||||
"name": "@playwright/experimental-ct-vue",
|
"name": "@playwright/experimental-ct-vue",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-vue": "^4.2.1"
|
"@vitejs/plugin-vue": "^4.2.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -6399,10 +6399,10 @@
|
||||||
},
|
},
|
||||||
"packages/playwright-ct-vue2": {
|
"packages/playwright-ct-vue2": {
|
||||||
"name": "@playwright/experimental-ct-vue2",
|
"name": "@playwright/experimental-ct-vue2",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-vue2": "^2.2.0"
|
"@vitejs/plugin-vue2": "^2.2.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -6416,11 +6416,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/playwright-firefox": {
|
"packages/playwright-firefox": {
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
|
|
@ -6431,11 +6431,11 @@
|
||||||
},
|
},
|
||||||
"packages/playwright-test": {
|
"packages/playwright-test": {
|
||||||
"name": "@playwright/test",
|
"name": "@playwright/test",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
|
|
@ -6448,11 +6448,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/playwright-webkit": {
|
"packages/playwright-webkit": {
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
|
|
@ -7262,14 +7262,14 @@
|
||||||
"@playwright/experimental-ct-core": {
|
"@playwright/experimental-ct-core": {
|
||||||
"version": "file:packages/playwright-ct-core",
|
"version": "file:packages/playwright-ct-core",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@playwright/test": "1.34.0-next",
|
"@playwright/test": "1.34.3",
|
||||||
"vite": "^4.3.3"
|
"vite": "^4.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@playwright/experimental-ct-react": {
|
"@playwright/experimental-ct-react": {
|
||||||
"version": "file:packages/playwright-ct-react",
|
"version": "file:packages/playwright-ct-react",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-react": "^4.0.0"
|
"@vitejs/plugin-react": "^4.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -7289,7 +7289,7 @@
|
||||||
"@playwright/experimental-ct-react17": {
|
"@playwright/experimental-ct-react17": {
|
||||||
"version": "file:packages/playwright-ct-react17",
|
"version": "file:packages/playwright-ct-react17",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-react": "^4.0.0"
|
"@vitejs/plugin-react": "^4.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -7309,7 +7309,7 @@
|
||||||
"@playwright/experimental-ct-solid": {
|
"@playwright/experimental-ct-solid": {
|
||||||
"version": "file:packages/playwright-ct-solid",
|
"version": "file:packages/playwright-ct-solid",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"solid-js": "^1.7.0",
|
"solid-js": "^1.7.0",
|
||||||
"vite-plugin-solid": "^2.7.0"
|
"vite-plugin-solid": "^2.7.0"
|
||||||
}
|
}
|
||||||
|
|
@ -7317,7 +7317,7 @@
|
||||||
"@playwright/experimental-ct-svelte": {
|
"@playwright/experimental-ct-svelte": {
|
||||||
"version": "file:packages/playwright-ct-svelte",
|
"version": "file:packages/playwright-ct-svelte",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.1.1",
|
"@sveltejs/vite-plugin-svelte": "^2.1.1",
|
||||||
"svelte": "^3.55.1"
|
"svelte": "^3.55.1"
|
||||||
}
|
}
|
||||||
|
|
@ -7325,7 +7325,7 @@
|
||||||
"@playwright/experimental-ct-vue": {
|
"@playwright/experimental-ct-vue": {
|
||||||
"version": "file:packages/playwright-ct-vue",
|
"version": "file:packages/playwright-ct-vue",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-vue": "^4.2.1"
|
"@vitejs/plugin-vue": "^4.2.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -7359,7 +7359,7 @@
|
||||||
"@playwright/experimental-ct-vue2": {
|
"@playwright/experimental-ct-vue2": {
|
||||||
"version": "file:packages/playwright-ct-vue2",
|
"version": "file:packages/playwright-ct-vue2",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-vue2": "^2.2.0",
|
"@vitejs/plugin-vue2": "^2.2.0",
|
||||||
"vue": "^2.7.14"
|
"vue": "^2.7.14"
|
||||||
}
|
}
|
||||||
|
|
@ -7369,7 +7369,7 @@
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"fsevents": "2.3.2",
|
"fsevents": "2.3.2",
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sindresorhus/is": {
|
"@sindresorhus/is": {
|
||||||
|
|
@ -9663,13 +9663,13 @@
|
||||||
"playwright": {
|
"playwright": {
|
||||||
"version": "file:packages/playwright",
|
"version": "file:packages/playwright",
|
||||||
"requires": {
|
"requires": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"playwright-chromium": {
|
"playwright-chromium": {
|
||||||
"version": "file:packages/playwright-chromium",
|
"version": "file:packages/playwright-chromium",
|
||||||
"requires": {
|
"requires": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"playwright-core": {
|
"playwright-core": {
|
||||||
|
|
@ -9678,13 +9678,13 @@
|
||||||
"playwright-firefox": {
|
"playwright-firefox": {
|
||||||
"version": "file:packages/playwright-firefox",
|
"version": "file:packages/playwright-firefox",
|
||||||
"requires": {
|
"requires": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"playwright-webkit": {
|
"playwright-webkit": {
|
||||||
"version": "file:packages/playwright-webkit",
|
"version": "file:packages/playwright-webkit",
|
||||||
"requires": {
|
"requires": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss": {
|
"postcss": {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "playwright-internal",
|
"name": "playwright-internal",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "A high-level API to automate web browsers",
|
"description": "A high-level API to automate web browsers",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
background-color: var(--color-canvas-subtle);
|
background-color: var(--color-canvas-subtle);
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
|
margin-top: 24px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 38px;
|
line-height: 38px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
|
||||||
|
|
@ -108,9 +108,11 @@ export class Filter {
|
||||||
if (test.outcome === 'skipped')
|
if (test.outcome === 'skipped')
|
||||||
status = 'skipped';
|
status = 'skipped';
|
||||||
const searchValues: SearchValues = {
|
const searchValues: SearchValues = {
|
||||||
text: (status + ' ' + test.projectName + ' ' + test.path.join(' ') + ' ' + test.title).toLowerCase(),
|
text: (status + ' ' + test.projectName + ' ' + test.location.file + ' ' + test.path.join(' ') + ' ' + test.title).toLowerCase(),
|
||||||
project: test.projectName.toLowerCase(),
|
project: test.projectName.toLowerCase(),
|
||||||
status: status as any,
|
status: status as any,
|
||||||
|
file: test.location.file,
|
||||||
|
line: String(test.location.line),
|
||||||
};
|
};
|
||||||
(test as any).searchValues = searchValues;
|
(test as any).searchValues = searchValues;
|
||||||
}
|
}
|
||||||
|
|
@ -127,10 +129,15 @@ export class Filter {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.text.length) {
|
if (this.text.length) {
|
||||||
const matches = this.text.filter(t => searchValues.text.includes(t)).length === this.text.length;
|
for (const text of this.text) {
|
||||||
if (!matches)
|
if (searchValues.text.includes(text))
|
||||||
|
continue;
|
||||||
|
const location = text.split(':');
|
||||||
|
if (location.length === 2 && searchValues.file.includes(location[0]) && searchValues.line.includes(location[1]))
|
||||||
|
continue;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (this.labels.length) {
|
if (this.labels.length) {
|
||||||
const matches = this.labels.every(l => searchValues.text?.match(new RegExp(`(\\s|^)${escapeRegExp(l)}(\\s|$)`, 'g')));
|
const matches = this.labels.every(l => searchValues.text?.match(new RegExp(`(\\s|^)${escapeRegExp(l)}(\\s|$)`, 'g')));
|
||||||
if (!matches)
|
if (!matches)
|
||||||
|
|
@ -145,5 +152,7 @@ type SearchValues = {
|
||||||
text: string;
|
text: string;
|
||||||
project: string;
|
project: string;
|
||||||
status: 'passed' | 'failed' | 'flaky' | 'skipped';
|
status: 'passed' | 'failed' | 'flaky' | 'skipped';
|
||||||
|
file: string;
|
||||||
|
line: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ test('should switch to actual', async ({ mount }) => {
|
||||||
for (let i = 0; i < imageCount; ++i) {
|
for (let i = 0; i < imageCount; ++i) {
|
||||||
const image = images.nth(i);
|
const image = images.nth(i);
|
||||||
const box = await image.boundingBox();
|
const box = await image.boundingBox();
|
||||||
expect(box).toEqual({ x: 400, y: 124, width: 200, height: 200 });
|
expect(box).toEqual({ x: 400, y: 108, width: 200, height: 200 });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ test('should switch to expected', async ({ mount }) => {
|
||||||
for (let i = 0; i < imageCount; ++i) {
|
for (let i = 0; i < imageCount; ++i) {
|
||||||
const image = images.nth(i);
|
const image = images.nth(i);
|
||||||
const box = await image.boundingBox();
|
const box = await image.boundingBox();
|
||||||
expect(box).toEqual({ x: 400, y: 124, width: 200, height: 200 });
|
expect(box).toEqual({ x: 400, y: 108, width: 200, height: 200 });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -79,5 +79,5 @@ test('should show diff by default', async ({ mount }) => {
|
||||||
|
|
||||||
const image = component.locator('img');
|
const image = component.locator('img');
|
||||||
const box = await image.boundingBox();
|
const box = await image.boundingBox();
|
||||||
expect(box).toEqual({ x: 400, y: 124, width: 200, height: 200 });
|
expect(box).toEqual({ x: 400, y: 108, width: 200, height: 200 });
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
height: 48px;
|
height: 48px;
|
||||||
min-width: 70px;
|
min-width: 70px;
|
||||||
box-shadow: inset 0 -1px 0 var(--color-border-muted) !important;
|
box-shadow: inset 0 -1px 0 var(--color-border-muted) !important;
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabbed-pane-tab-strip:focus {
|
.tabbed-pane-tab-strip:focus {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
.test-case-duration {
|
.test-case-duration {
|
||||||
flex: none;
|
flex: none;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 8px 24px;
|
padding: 0 8px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.test-case-path {
|
.test-case-path {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "playwright-chromium",
|
"name": "playwright-chromium",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "A high-level API to automate Chromium",
|
"description": "A high-level API to automate Chromium",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -27,6 +27,6 @@
|
||||||
"install": "node install.js"
|
"install": "node install.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,15 @@
|
||||||
"browsers": [
|
"browsers": [
|
||||||
{
|
{
|
||||||
"name": "chromium",
|
"name": "chromium",
|
||||||
"revision": "1063",
|
"revision": "1064",
|
||||||
"installByDefault": true,
|
"installByDefault": true,
|
||||||
"browserVersion": "114.0.5735.26"
|
"browserVersion": "114.0.5735.35"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "chromium-with-symbols",
|
"name": "chromium-with-symbols",
|
||||||
"revision": "1063",
|
"revision": "1064",
|
||||||
"installByDefault": false,
|
"installByDefault": false,
|
||||||
"browserVersion": "114.0.5735.26"
|
"browserVersion": "114.0.5735.35"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "chromium-tip-of-tree",
|
"name": "chromium-tip-of-tree",
|
||||||
|
|
|
||||||
17
packages/playwright-core/cli.js
Executable file
17
packages/playwright-core/cli.js
Executable file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
module.exports = require('playwright-core/lib/cli/cli');
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "playwright-core",
|
"name": "playwright-core",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "A high-level API to automate web browsers",
|
"description": "A high-level API to automate web browsers",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -35,5 +35,8 @@
|
||||||
"./types/protocol": "./types/protocol.d.ts",
|
"./types/protocol": "./types/protocol.d.ts",
|
||||||
"./types/structs": "./types/structs.d.ts"
|
"./types/structs": "./types/structs.d.ts"
|
||||||
},
|
},
|
||||||
|
"bin": {
|
||||||
|
"playwright-core": "./cli.js"
|
||||||
|
},
|
||||||
"types": "types/types.d.ts"
|
"types": "types/types.d.ts"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,13 @@ const debugLoggerColorMap = {
|
||||||
'install': 34, // green
|
'install': 34, // green
|
||||||
'download': 34, // green
|
'download': 34, // green
|
||||||
'browser': 0, // reset
|
'browser': 0, // reset
|
||||||
'proxy': 92, // purple
|
'socks': 92, // purple
|
||||||
'error': 160, // red,
|
'error': 160, // red,
|
||||||
'channel:command': 33, // blue
|
'channel:command': 33, // blue
|
||||||
'channel:response': 202, // orange
|
'channel:response': 202, // orange
|
||||||
'channel:event': 207, // magenta
|
'channel:event': 207, // magenta
|
||||||
|
'server': 45, // cyan
|
||||||
|
'server:channel': 34, // green
|
||||||
};
|
};
|
||||||
export type LogName = keyof typeof debugLoggerColorMap;
|
export type LogName = keyof typeof debugLoggerColorMap;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,6 @@ export class SocksProxy extends EventEmitter implements SocksConnectionClient {
|
||||||
this._server.listen(port, () => {
|
this._server.listen(port, () => {
|
||||||
const port = (this._server.address() as AddressInfo).port;
|
const port = (this._server.address() as AddressInfo).port;
|
||||||
this._port = port;
|
this._port = port;
|
||||||
debugLogger.log('proxy', `Starting socks proxy server on port ${port}`);
|
|
||||||
f(port);
|
f(port);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -525,8 +524,10 @@ export class SocksProxyHandler extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
async socketRequested({ uid, host, port }: SocksSocketRequestedPayload): Promise<void> {
|
async socketRequested({ uid, host, port }: SocksSocketRequestedPayload): Promise<void> {
|
||||||
|
debugLogger.log('socks', `[${uid}] => request ${host}:${port}`);
|
||||||
if (!this._patternMatcher(host, port)) {
|
if (!this._patternMatcher(host, port)) {
|
||||||
const payload: SocksSocketFailedPayload = { uid, errorCode: 'ERULESET' };
|
const payload: SocksSocketFailedPayload = { uid, errorCode: 'ERULESET' };
|
||||||
|
debugLogger.log('socks', `[${uid}] <= pattern error ${payload.errorCode}`);
|
||||||
this.emit(SocksProxyHandler.Events.SocksFailed, payload);
|
this.emit(SocksProxyHandler.Events.SocksFailed, payload);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -543,11 +544,13 @@ export class SocksProxyHandler extends EventEmitter {
|
||||||
});
|
});
|
||||||
socket.on('error', error => {
|
socket.on('error', error => {
|
||||||
const payload: SocksSocketErrorPayload = { uid, error: error.message };
|
const payload: SocksSocketErrorPayload = { uid, error: error.message };
|
||||||
|
debugLogger.log('socks', `[${uid}] <= network socket error ${payload.error}`);
|
||||||
this.emit(SocksProxyHandler.Events.SocksError, payload);
|
this.emit(SocksProxyHandler.Events.SocksError, payload);
|
||||||
this._sockets.delete(uid);
|
this._sockets.delete(uid);
|
||||||
});
|
});
|
||||||
socket.on('end', () => {
|
socket.on('end', () => {
|
||||||
const payload: SocksSocketEndPayload = { uid };
|
const payload: SocksSocketEndPayload = { uid };
|
||||||
|
debugLogger.log('socks', `[${uid}] <= network socket closed`);
|
||||||
this.emit(SocksProxyHandler.Events.SocksEnd, payload);
|
this.emit(SocksProxyHandler.Events.SocksEnd, payload);
|
||||||
this._sockets.delete(uid);
|
this._sockets.delete(uid);
|
||||||
});
|
});
|
||||||
|
|
@ -555,9 +558,11 @@ export class SocksProxyHandler extends EventEmitter {
|
||||||
const localPort = socket.localPort;
|
const localPort = socket.localPort;
|
||||||
this._sockets.set(uid, socket);
|
this._sockets.set(uid, socket);
|
||||||
const payload: SocksSocketConnectedPayload = { uid, host: localAddress, port: localPort };
|
const payload: SocksSocketConnectedPayload = { uid, host: localAddress, port: localPort };
|
||||||
|
debugLogger.log('socks', `[${uid}] <= connected to network ${payload.host}:${payload.port}`);
|
||||||
this.emit(SocksProxyHandler.Events.SocksConnected, payload);
|
this.emit(SocksProxyHandler.Events.SocksConnected, payload);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const payload: SocksSocketFailedPayload = { uid, errorCode: error.code };
|
const payload: SocksSocketFailedPayload = { uid, errorCode: error.code };
|
||||||
|
debugLogger.log('socks', `[${uid}] <= connect error ${payload.errorCode}`);
|
||||||
this.emit(SocksProxyHandler.Events.SocksFailed, payload);
|
this.emit(SocksProxyHandler.Events.SocksFailed, payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -567,6 +572,7 @@ export class SocksProxyHandler extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
socketClosed({ uid }: SocksSocketClosedPayload): void {
|
socketClosed({ uid }: SocksSocketClosedPayload): void {
|
||||||
|
debugLogger.log('socks', `[${uid}] <= browser socket closed`);
|
||||||
this._sockets.get(uid)?.destroy();
|
this._sockets.get(uid)?.destroy();
|
||||||
this._sockets.delete(uid);
|
this._sockets.delete(uid);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ import type { LaunchOptions } from '../server/types';
|
||||||
import { AndroidDevice } from '../server/android/android';
|
import { AndroidDevice } from '../server/android/android';
|
||||||
import { DebugControllerDispatcher } from '../server/dispatchers/debugControllerDispatcher';
|
import { DebugControllerDispatcher } from '../server/dispatchers/debugControllerDispatcher';
|
||||||
import { startProfiling, stopProfiling } from '../utils';
|
import { startProfiling, stopProfiling } from '../utils';
|
||||||
|
import { monotonicTime } from '../utils';
|
||||||
|
import { debugLogger } from '../common/debugLogger';
|
||||||
|
|
||||||
export type ClientType = 'controller' | 'playwright' | 'launch-browser' | 'reuse-browser' | 'pre-launched-browser-or-android';
|
export type ClientType = 'controller' | 'playwright' | 'launch-browser' | 'reuse-browser' | 'pre-launched-browser-or-android';
|
||||||
|
|
||||||
|
|
@ -46,14 +48,14 @@ export class PlaywrightConnection {
|
||||||
private _onClose: () => void;
|
private _onClose: () => void;
|
||||||
private _dispatcherConnection: DispatcherConnection;
|
private _dispatcherConnection: DispatcherConnection;
|
||||||
private _cleanups: (() => Promise<void>)[] = [];
|
private _cleanups: (() => Promise<void>)[] = [];
|
||||||
private _debugLog: (m: string) => void;
|
private _id: string;
|
||||||
private _disconnected = false;
|
private _disconnected = false;
|
||||||
private _preLaunched: PreLaunched;
|
private _preLaunched: PreLaunched;
|
||||||
private _options: Options;
|
private _options: Options;
|
||||||
private _root: DispatcherScope;
|
private _root: DispatcherScope;
|
||||||
private _profileName: string;
|
private _profileName: string;
|
||||||
|
|
||||||
constructor(lock: Promise<void>, clientType: ClientType, ws: WebSocket, options: Options, preLaunched: PreLaunched, log: (m: string) => void, onClose: () => void) {
|
constructor(lock: Promise<void>, clientType: ClientType, ws: WebSocket, options: Options, preLaunched: PreLaunched, id: string, onClose: () => void) {
|
||||||
this._ws = ws;
|
this._ws = ws;
|
||||||
this._preLaunched = preLaunched;
|
this._preLaunched = preLaunched;
|
||||||
this._options = options;
|
this._options = options;
|
||||||
|
|
@ -63,18 +65,25 @@ export class PlaywrightConnection {
|
||||||
if (clientType === 'pre-launched-browser-or-android')
|
if (clientType === 'pre-launched-browser-or-android')
|
||||||
assert(preLaunched.browser || preLaunched.androidDevice);
|
assert(preLaunched.browser || preLaunched.androidDevice);
|
||||||
this._onClose = onClose;
|
this._onClose = onClose;
|
||||||
this._debugLog = log;
|
this._id = id;
|
||||||
this._profileName = `${new Date().toISOString()}-${clientType}`;
|
this._profileName = `${new Date().toISOString()}-${clientType}`;
|
||||||
|
|
||||||
this._dispatcherConnection = new DispatcherConnection();
|
this._dispatcherConnection = new DispatcherConnection();
|
||||||
this._dispatcherConnection.onmessage = async message => {
|
this._dispatcherConnection.onmessage = async message => {
|
||||||
await lock;
|
await lock;
|
||||||
if (ws.readyState !== ws.CLOSING)
|
if (ws.readyState !== ws.CLOSING) {
|
||||||
ws.send(JSON.stringify(message));
|
const messageString = JSON.stringify(message);
|
||||||
|
if (debugLogger.isEnabled('server:channel'))
|
||||||
|
debugLogger.log('server:channel', `[${this._id}] ${monotonicTime() * 1000} SEND ► ${messageString}`);
|
||||||
|
ws.send(messageString);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
ws.on('message', async (message: string) => {
|
ws.on('message', async (message: string) => {
|
||||||
await lock;
|
await lock;
|
||||||
this._dispatcherConnection.dispatch(JSON.parse(Buffer.from(message).toString()));
|
const messageString = Buffer.from(message).toString();
|
||||||
|
if (debugLogger.isEnabled('server:channel'))
|
||||||
|
debugLogger.log('server:channel', `[${this._id}] ${monotonicTime() * 1000} ◀ RECV ${messageString}`);
|
||||||
|
this._dispatcherConnection.dispatch(JSON.parse(messageString));
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on('close', () => this._onDisconnect());
|
ws.on('close', () => this._onDisconnect());
|
||||||
|
|
@ -100,7 +109,7 @@ export class PlaywrightConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _initPlaywrightConnectMode(scope: RootDispatcher) {
|
private async _initPlaywrightConnectMode(scope: RootDispatcher) {
|
||||||
this._debugLog(`engaged playwright.connect mode`);
|
debugLogger.log('server', `[${this._id}] engaged playwright.connect mode`);
|
||||||
const playwright = createPlaywright('javascript');
|
const playwright = createPlaywright('javascript');
|
||||||
// Close all launched browsers on disconnect.
|
// Close all launched browsers on disconnect.
|
||||||
this._cleanups.push(async () => {
|
this._cleanups.push(async () => {
|
||||||
|
|
@ -112,7 +121,7 @@ export class PlaywrightConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _initLaunchBrowserMode(scope: RootDispatcher) {
|
private async _initLaunchBrowserMode(scope: RootDispatcher) {
|
||||||
this._debugLog(`engaged launch mode for "${this._options.browserName}"`);
|
debugLogger.log('server', `[${this._id}] engaged launch mode for "${this._options.browserName}"`);
|
||||||
const playwright = createPlaywright('javascript');
|
const playwright = createPlaywright('javascript');
|
||||||
|
|
||||||
const ownedSocksProxy = await this._createOwnedSocksProxy(playwright);
|
const ownedSocksProxy = await this._createOwnedSocksProxy(playwright);
|
||||||
|
|
@ -131,7 +140,7 @@ export class PlaywrightConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _initPreLaunchedBrowserMode(scope: RootDispatcher) {
|
private async _initPreLaunchedBrowserMode(scope: RootDispatcher) {
|
||||||
this._debugLog(`engaged pre-launched (browser) mode`);
|
debugLogger.log('server', `[${this._id}] engaged pre-launched (browser) mode`);
|
||||||
const playwright = this._preLaunched.playwright!;
|
const playwright = this._preLaunched.playwright!;
|
||||||
|
|
||||||
// Note: connected client owns the socks proxy and configures the pattern.
|
// Note: connected client owns the socks proxy and configures the pattern.
|
||||||
|
|
@ -154,7 +163,7 @@ export class PlaywrightConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _initPreLaunchedAndroidMode(scope: RootDispatcher) {
|
private async _initPreLaunchedAndroidMode(scope: RootDispatcher) {
|
||||||
this._debugLog(`engaged pre-launched (Android) mode`);
|
debugLogger.log('server', `[${this._id}] engaged pre-launched (Android) mode`);
|
||||||
const playwright = this._preLaunched.playwright!;
|
const playwright = this._preLaunched.playwright!;
|
||||||
const androidDevice = this._preLaunched.androidDevice!;
|
const androidDevice = this._preLaunched.androidDevice!;
|
||||||
androidDevice.on(AndroidDevice.Events.Close, () => {
|
androidDevice.on(AndroidDevice.Events.Close, () => {
|
||||||
|
|
@ -167,7 +176,7 @@ export class PlaywrightConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _initDebugControllerMode(): DebugControllerDispatcher {
|
private _initDebugControllerMode(): DebugControllerDispatcher {
|
||||||
this._debugLog(`engaged reuse controller mode`);
|
debugLogger.log('server', `[${this._id}] engaged reuse controller mode`);
|
||||||
const playwright = this._preLaunched.playwright!;
|
const playwright = this._preLaunched.playwright!;
|
||||||
// Always create new instance based on the reused Playwright instance.
|
// Always create new instance based on the reused Playwright instance.
|
||||||
return new DebugControllerDispatcher(this._dispatcherConnection, playwright.debugController);
|
return new DebugControllerDispatcher(this._dispatcherConnection, playwright.debugController);
|
||||||
|
|
@ -177,7 +186,7 @@ export class PlaywrightConnection {
|
||||||
// Note: reuse browser mode does not support socks proxy, because
|
// Note: reuse browser mode does not support socks proxy, because
|
||||||
// clients come and go, while the browser stays the same.
|
// clients come and go, while the browser stays the same.
|
||||||
|
|
||||||
this._debugLog(`engaged reuse browsers mode for ${this._options.browserName}`);
|
debugLogger.log('server', `[${this._id}] engaged reuse browsers mode for ${this._options.browserName}`);
|
||||||
const playwright = this._preLaunched.playwright!;
|
const playwright = this._preLaunched.playwright!;
|
||||||
|
|
||||||
const requestedOptions = launchOptionsHash(this._options.launchOptions);
|
const requestedOptions = launchOptionsHash(this._options.launchOptions);
|
||||||
|
|
@ -232,27 +241,27 @@ export class PlaywrightConnection {
|
||||||
const socksProxy = new SocksProxy();
|
const socksProxy = new SocksProxy();
|
||||||
socksProxy.setPattern(this._options.socksProxyPattern);
|
socksProxy.setPattern(this._options.socksProxyPattern);
|
||||||
playwright.options.socksProxyPort = await socksProxy.listen(0);
|
playwright.options.socksProxyPort = await socksProxy.listen(0);
|
||||||
this._debugLog(`started socks proxy on port ${playwright.options.socksProxyPort}`);
|
debugLogger.log('server', `[${this._id}] started socks proxy on port ${playwright.options.socksProxyPort}`);
|
||||||
this._cleanups.push(() => socksProxy.close());
|
this._cleanups.push(() => socksProxy.close());
|
||||||
return socksProxy;
|
return socksProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _onDisconnect(error?: Error) {
|
private async _onDisconnect(error?: Error) {
|
||||||
this._disconnected = true;
|
this._disconnected = true;
|
||||||
this._debugLog(`disconnected. error: ${error}`);
|
debugLogger.log('server', `[${this._id}] disconnected. error: ${error}`);
|
||||||
this._root._dispose();
|
this._root._dispose();
|
||||||
this._debugLog(`starting cleanup`);
|
debugLogger.log('server', `[${this._id}] starting cleanup`);
|
||||||
for (const cleanup of this._cleanups)
|
for (const cleanup of this._cleanups)
|
||||||
await cleanup().catch(() => {});
|
await cleanup().catch(() => {});
|
||||||
await stopProfiling(this._profileName);
|
await stopProfiling(this._profileName);
|
||||||
this._onClose();
|
this._onClose();
|
||||||
this._debugLog(`finished cleanup`);
|
debugLogger.log('server', `[${this._id}] finished cleanup`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async close(reason?: { code: number, reason: string }) {
|
async close(reason?: { code: number, reason: string }) {
|
||||||
if (this._disconnected)
|
if (this._disconnected)
|
||||||
return;
|
return;
|
||||||
this._debugLog(`force closing connection: ${reason?.reason || ''} (${reason?.code || 0})`);
|
debugLogger.log('server', `[${this._id}] force closing connection: ${reason?.reason || ''} (${reason?.code || 0})`);
|
||||||
try {
|
try {
|
||||||
this._ws.close(reason?.code, reason?.reason);
|
this._ws.close(reason?.code, reason?.reason);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { debug, wsServer } from '../utilsBundle';
|
import { wsServer } from '../utilsBundle';
|
||||||
import type { WebSocketServer } from '../utilsBundle';
|
import type { WebSocketServer } from '../utilsBundle';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import type { Browser } from '../server/browser';
|
import type { Browser } from '../server/browser';
|
||||||
|
|
@ -26,17 +26,11 @@ import type { LaunchOptions } from '../server/types';
|
||||||
import { ManualPromise } from '../utils/manualPromise';
|
import { ManualPromise } from '../utils/manualPromise';
|
||||||
import type { AndroidDevice } from '../server/android/android';
|
import type { AndroidDevice } from '../server/android/android';
|
||||||
import { type SocksProxy } from '../common/socksProxy';
|
import { type SocksProxy } from '../common/socksProxy';
|
||||||
|
import { debugLogger } from '../common/debugLogger';
|
||||||
const debugLog = debug('pw:server');
|
|
||||||
|
|
||||||
let lastConnectionId = 0;
|
let lastConnectionId = 0;
|
||||||
const kConnectionSymbol = Symbol('kConnection');
|
const kConnectionSymbol = Symbol('kConnection');
|
||||||
|
|
||||||
function newLogger() {
|
|
||||||
const id = ++lastConnectionId;
|
|
||||||
return (message: string) => debugLog(`[id=${id}] ${message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
type ServerOptions = {
|
type ServerOptions = {
|
||||||
path: string;
|
path: string;
|
||||||
maxConnections: number;
|
maxConnections: number;
|
||||||
|
|
@ -59,6 +53,8 @@ export class PlaywrightServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
async listen(port: number = 0): Promise<string> {
|
async listen(port: number = 0): Promise<string> {
|
||||||
|
debugLogger.log('server', `Server started at ${new Date()}`);
|
||||||
|
|
||||||
const server = http.createServer((request: http.IncomingMessage, response: http.ServerResponse) => {
|
const server = http.createServer((request: http.IncomingMessage, response: http.ServerResponse) => {
|
||||||
if (request.method === 'GET' && request.url === '/json') {
|
if (request.method === 'GET' && request.url === '/json') {
|
||||||
response.setHeader('Content-Type', 'application/json');
|
response.setHeader('Content-Type', 'application/json');
|
||||||
|
|
@ -69,7 +65,7 @@ export class PlaywrightServer {
|
||||||
}
|
}
|
||||||
response.end('Running');
|
response.end('Running');
|
||||||
});
|
});
|
||||||
server.on('error', error => debugLog(error));
|
server.on('error', error => debugLogger.log('server', String(error)));
|
||||||
|
|
||||||
const wsEndpoint = await new Promise<string>((resolve, reject) => {
|
const wsEndpoint = await new Promise<string>((resolve, reject) => {
|
||||||
server.listen(port, () => {
|
server.listen(port, () => {
|
||||||
|
|
@ -83,7 +79,7 @@ export class PlaywrightServer {
|
||||||
}).on('error', reject);
|
}).on('error', reject);
|
||||||
});
|
});
|
||||||
|
|
||||||
debugLog('Listening at ' + wsEndpoint);
|
debugLogger.log('server', 'Listening at ' + wsEndpoint);
|
||||||
this._wsServer = new wsServer({ server, path: this._options.path });
|
this._wsServer = new wsServer({ server, path: this._options.path });
|
||||||
const browserSemaphore = new Semaphore(this._options.maxConnections);
|
const browserSemaphore = new Semaphore(this._options.maxConnections);
|
||||||
const controllerSemaphore = new Semaphore(1);
|
const controllerSemaphore = new Semaphore(1);
|
||||||
|
|
@ -107,8 +103,8 @@ export class PlaywrightServer {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const log = newLogger();
|
const id = String(++lastConnectionId);
|
||||||
log(`serving connection: ${request.url}`);
|
debugLogger.log('server', `[${id}] serving connection: ${request.url}`);
|
||||||
const isDebugControllerClient = !!request.headers['x-playwright-debug-controller'];
|
const isDebugControllerClient = !!request.headers['x-playwright-debug-controller'];
|
||||||
const shouldReuseBrowser = !!request.headers['x-playwright-reuse-context'];
|
const shouldReuseBrowser = !!request.headers['x-playwright-reuse-context'];
|
||||||
|
|
||||||
|
|
@ -145,7 +141,7 @@ export class PlaywrightServer {
|
||||||
androidDevice: this._options.preLaunchedAndroidDevice,
|
androidDevice: this._options.preLaunchedAndroidDevice,
|
||||||
socksProxy: this._options.preLaunchedSocksProxy,
|
socksProxy: this._options.preLaunchedSocksProxy,
|
||||||
},
|
},
|
||||||
log, () => semaphore.release());
|
id, () => semaphore.release());
|
||||||
(ws as any)[kConnectionSymbol] = connection;
|
(ws as any)[kConnectionSymbol] = connection;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -156,7 +152,7 @@ export class PlaywrightServer {
|
||||||
const server = this._wsServer;
|
const server = this._wsServer;
|
||||||
if (!server)
|
if (!server)
|
||||||
return;
|
return;
|
||||||
debugLog('closing websocket server');
|
debugLogger.log('server', 'closing websocket server');
|
||||||
const waitForClose = new Promise(f => server.close(f));
|
const waitForClose = new Promise(f => server.close(f));
|
||||||
// First disconnect all remaining clients.
|
// First disconnect all remaining clients.
|
||||||
await Promise.all(Array.from(server.clients).map(async ws => {
|
await Promise.all(Array.from(server.clients).map(async ws => {
|
||||||
|
|
@ -169,15 +165,15 @@ export class PlaywrightServer {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
await waitForClose;
|
await waitForClose;
|
||||||
debugLog('closing http server');
|
debugLogger.log('server', 'closing http server');
|
||||||
await new Promise(f => server.options.server!.close(f));
|
await new Promise(f => server.options.server!.close(f));
|
||||||
this._wsServer = undefined;
|
this._wsServer = undefined;
|
||||||
debugLog('closed server');
|
debugLogger.log('server', 'closed server');
|
||||||
|
|
||||||
debugLog('closing browsers');
|
debugLogger.log('server', 'closing browsers');
|
||||||
if (this._preLaunchedPlaywright)
|
if (this._preLaunchedPlaywright)
|
||||||
await Promise.all(this._preLaunchedPlaywright.allBrowsers().map(browser => browser.close()));
|
await Promise.all(this._preLaunchedPlaywright.allBrowsers().map(browser => browser.close()));
|
||||||
debugLog('closed browsers');
|
debugLogger.log('server', 'closed browsers');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@
|
||||||
"defaultBrowserType": "webkit"
|
"defaultBrowserType": "webkit"
|
||||||
},
|
},
|
||||||
"Galaxy S5": {
|
"Galaxy S5": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 360,
|
"width": 360,
|
||||||
"height": 640
|
"height": 640
|
||||||
|
|
@ -121,7 +121,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Galaxy S5 landscape": {
|
"Galaxy S5 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 640,
|
"width": 640,
|
||||||
"height": 360
|
"height": 360
|
||||||
|
|
@ -132,7 +132,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Galaxy S8": {
|
"Galaxy S8": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 360,
|
"width": 360,
|
||||||
"height": 740
|
"height": 740
|
||||||
|
|
@ -143,7 +143,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Galaxy S8 landscape": {
|
"Galaxy S8 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 740,
|
"width": 740,
|
||||||
"height": 360
|
"height": 360
|
||||||
|
|
@ -154,7 +154,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Galaxy S9+": {
|
"Galaxy S9+": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 320,
|
"width": 320,
|
||||||
"height": 658
|
"height": 658
|
||||||
|
|
@ -165,7 +165,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Galaxy S9+ landscape": {
|
"Galaxy S9+ landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 658,
|
"width": 658,
|
||||||
"height": 320
|
"height": 320
|
||||||
|
|
@ -176,7 +176,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Galaxy Tab S4": {
|
"Galaxy Tab S4": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 712,
|
"width": 712,
|
||||||
"height": 1138
|
"height": 1138
|
||||||
|
|
@ -187,7 +187,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Galaxy Tab S4 landscape": {
|
"Galaxy Tab S4 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 1138,
|
"width": 1138,
|
||||||
"height": 712
|
"height": 712
|
||||||
|
|
@ -836,7 +836,7 @@
|
||||||
"defaultBrowserType": "webkit"
|
"defaultBrowserType": "webkit"
|
||||||
},
|
},
|
||||||
"LG Optimus L70": {
|
"LG Optimus L70": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 384,
|
"width": 384,
|
||||||
"height": 640
|
"height": 640
|
||||||
|
|
@ -847,7 +847,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"LG Optimus L70 landscape": {
|
"LG Optimus L70 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 640,
|
"width": 640,
|
||||||
"height": 384
|
"height": 384
|
||||||
|
|
@ -858,7 +858,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Microsoft Lumia 550": {
|
"Microsoft Lumia 550": {
|
||||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36 Edge/14.14263",
|
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36 Edge/14.14263",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 640,
|
"width": 640,
|
||||||
"height": 360
|
"height": 360
|
||||||
|
|
@ -869,7 +869,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Microsoft Lumia 550 landscape": {
|
"Microsoft Lumia 550 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36 Edge/14.14263",
|
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36 Edge/14.14263",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 360,
|
"width": 360,
|
||||||
"height": 640
|
"height": 640
|
||||||
|
|
@ -880,7 +880,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Microsoft Lumia 950": {
|
"Microsoft Lumia 950": {
|
||||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36 Edge/14.14263",
|
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36 Edge/14.14263",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 360,
|
"width": 360,
|
||||||
"height": 640
|
"height": 640
|
||||||
|
|
@ -891,7 +891,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Microsoft Lumia 950 landscape": {
|
"Microsoft Lumia 950 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36 Edge/14.14263",
|
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36 Edge/14.14263",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 640,
|
"width": 640,
|
||||||
"height": 360
|
"height": 360
|
||||||
|
|
@ -902,7 +902,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 10": {
|
"Nexus 10": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 800,
|
"width": 800,
|
||||||
"height": 1280
|
"height": 1280
|
||||||
|
|
@ -913,7 +913,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 10 landscape": {
|
"Nexus 10 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 1280,
|
"width": 1280,
|
||||||
"height": 800
|
"height": 800
|
||||||
|
|
@ -924,7 +924,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 4": {
|
"Nexus 4": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 384,
|
"width": 384,
|
||||||
"height": 640
|
"height": 640
|
||||||
|
|
@ -935,7 +935,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 4 landscape": {
|
"Nexus 4 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 640,
|
"width": 640,
|
||||||
"height": 384
|
"height": 384
|
||||||
|
|
@ -946,7 +946,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 5": {
|
"Nexus 5": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 360,
|
"width": 360,
|
||||||
"height": 640
|
"height": 640
|
||||||
|
|
@ -957,7 +957,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 5 landscape": {
|
"Nexus 5 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 640,
|
"width": 640,
|
||||||
"height": 360
|
"height": 360
|
||||||
|
|
@ -968,7 +968,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 5X": {
|
"Nexus 5X": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 412,
|
"width": 412,
|
||||||
"height": 732
|
"height": 732
|
||||||
|
|
@ -979,7 +979,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 5X landscape": {
|
"Nexus 5X landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 732,
|
"width": 732,
|
||||||
"height": 412
|
"height": 412
|
||||||
|
|
@ -990,7 +990,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 6": {
|
"Nexus 6": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 412,
|
"width": 412,
|
||||||
"height": 732
|
"height": 732
|
||||||
|
|
@ -1001,7 +1001,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 6 landscape": {
|
"Nexus 6 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 732,
|
"width": 732,
|
||||||
"height": 412
|
"height": 412
|
||||||
|
|
@ -1012,7 +1012,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 6P": {
|
"Nexus 6P": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 412,
|
"width": 412,
|
||||||
"height": 732
|
"height": 732
|
||||||
|
|
@ -1023,7 +1023,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 6P landscape": {
|
"Nexus 6P landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 732,
|
"width": 732,
|
||||||
"height": 412
|
"height": 412
|
||||||
|
|
@ -1034,7 +1034,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 7": {
|
"Nexus 7": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 600,
|
"width": 600,
|
||||||
"height": 960
|
"height": 960
|
||||||
|
|
@ -1045,7 +1045,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Nexus 7 landscape": {
|
"Nexus 7 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 960,
|
"width": 960,
|
||||||
"height": 600
|
"height": 600
|
||||||
|
|
@ -1100,7 +1100,7 @@
|
||||||
"defaultBrowserType": "webkit"
|
"defaultBrowserType": "webkit"
|
||||||
},
|
},
|
||||||
"Pixel 2": {
|
"Pixel 2": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 411,
|
"width": 411,
|
||||||
"height": 731
|
"height": 731
|
||||||
|
|
@ -1111,7 +1111,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 2 landscape": {
|
"Pixel 2 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 731,
|
"width": 731,
|
||||||
"height": 411
|
"height": 411
|
||||||
|
|
@ -1122,7 +1122,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 2 XL": {
|
"Pixel 2 XL": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 411,
|
"width": 411,
|
||||||
"height": 823
|
"height": 823
|
||||||
|
|
@ -1133,7 +1133,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 2 XL landscape": {
|
"Pixel 2 XL landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 823,
|
"width": 823,
|
||||||
"height": 411
|
"height": 411
|
||||||
|
|
@ -1144,7 +1144,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 3": {
|
"Pixel 3": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 393,
|
"width": 393,
|
||||||
"height": 786
|
"height": 786
|
||||||
|
|
@ -1155,7 +1155,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 3 landscape": {
|
"Pixel 3 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 786,
|
"width": 786,
|
||||||
"height": 393
|
"height": 393
|
||||||
|
|
@ -1166,7 +1166,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 4": {
|
"Pixel 4": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 353,
|
"width": 353,
|
||||||
"height": 745
|
"height": 745
|
||||||
|
|
@ -1177,7 +1177,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 4 landscape": {
|
"Pixel 4 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 745,
|
"width": 745,
|
||||||
"height": 353
|
"height": 353
|
||||||
|
|
@ -1188,7 +1188,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 4a (5G)": {
|
"Pixel 4a (5G)": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"screen": {
|
"screen": {
|
||||||
"width": 412,
|
"width": 412,
|
||||||
"height": 892
|
"height": 892
|
||||||
|
|
@ -1203,7 +1203,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 4a (5G) landscape": {
|
"Pixel 4a (5G) landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"screen": {
|
"screen": {
|
||||||
"height": 892,
|
"height": 892,
|
||||||
"width": 412
|
"width": 412
|
||||||
|
|
@ -1218,7 +1218,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 5": {
|
"Pixel 5": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"screen": {
|
"screen": {
|
||||||
"width": 393,
|
"width": 393,
|
||||||
"height": 851
|
"height": 851
|
||||||
|
|
@ -1233,7 +1233,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Pixel 5 landscape": {
|
"Pixel 5 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"screen": {
|
"screen": {
|
||||||
"width": 851,
|
"width": 851,
|
||||||
"height": 393
|
"height": 393
|
||||||
|
|
@ -1248,7 +1248,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Moto G4": {
|
"Moto G4": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 360,
|
"width": 360,
|
||||||
"height": 640
|
"height": 640
|
||||||
|
|
@ -1259,7 +1259,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Moto G4 landscape": {
|
"Moto G4 landscape": {
|
||||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Mobile Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Mobile Safari/537.36",
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"width": 640,
|
"width": 640,
|
||||||
"height": 360
|
"height": 360
|
||||||
|
|
@ -1270,7 +1270,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Desktop Chrome HiDPI": {
|
"Desktop Chrome HiDPI": {
|
||||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Safari/537.36",
|
||||||
"screen": {
|
"screen": {
|
||||||
"width": 1792,
|
"width": 1792,
|
||||||
"height": 1120
|
"height": 1120
|
||||||
|
|
@ -1285,7 +1285,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Desktop Edge HiDPI": {
|
"Desktop Edge HiDPI": {
|
||||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Safari/537.36 Edg/114.0.5735.26",
|
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Safari/537.36 Edg/114.0.5735.35",
|
||||||
"screen": {
|
"screen": {
|
||||||
"width": 1792,
|
"width": 1792,
|
||||||
"height": 1120
|
"height": 1120
|
||||||
|
|
@ -1330,7 +1330,7 @@
|
||||||
"defaultBrowserType": "webkit"
|
"defaultBrowserType": "webkit"
|
||||||
},
|
},
|
||||||
"Desktop Chrome": {
|
"Desktop Chrome": {
|
||||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Safari/537.36",
|
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Safari/537.36",
|
||||||
"screen": {
|
"screen": {
|
||||||
"width": 1920,
|
"width": 1920,
|
||||||
"height": 1080
|
"height": 1080
|
||||||
|
|
@ -1345,7 +1345,7 @@
|
||||||
"defaultBrowserType": "chromium"
|
"defaultBrowserType": "chromium"
|
||||||
},
|
},
|
||||||
"Desktop Edge": {
|
"Desktop Edge": {
|
||||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.26 Safari/537.36 Edg/114.0.5735.26",
|
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.35 Safari/537.36 Edg/114.0.5735.35",
|
||||||
"screen": {
|
"screen": {
|
||||||
"width": 1920,
|
"width": 1920,
|
||||||
"height": 1080
|
"height": 1080
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,7 @@ export const deps: any = {
|
||||||
'libgles2',
|
'libgles2',
|
||||||
'libglib2.0-0',
|
'libglib2.0-0',
|
||||||
'libgtk-3-0',
|
'libgtk-3-0',
|
||||||
|
'libgudev-1.0-0',
|
||||||
'libharfbuzz-icu0',
|
'libharfbuzz-icu0',
|
||||||
'libharfbuzz0b',
|
'libharfbuzz0b',
|
||||||
'libhyphen0',
|
'libhyphen0',
|
||||||
|
|
@ -343,6 +344,7 @@ export const deps: any = {
|
||||||
'libgthread-2.0.so.0': 'libglib2.0-0',
|
'libgthread-2.0.so.0': 'libglib2.0-0',
|
||||||
'libgtk-3.so.0': 'libgtk-3-0',
|
'libgtk-3.so.0': 'libgtk-3-0',
|
||||||
'libgtk-x11-2.0.so.0': 'libgtk2.0-0',
|
'libgtk-x11-2.0.so.0': 'libgtk2.0-0',
|
||||||
|
'libgudev-1.0.so.0': 'libgudev-1.0-0',
|
||||||
'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',
|
'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',
|
||||||
'libharfbuzz.so.0': 'libharfbuzz0b',
|
'libharfbuzz.so.0': 'libharfbuzz0b',
|
||||||
'libhyphen.so.0': 'libhyphen0',
|
'libhyphen.so.0': 'libhyphen0',
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
||||||
for (const entry of entries)
|
for (const entry of entries)
|
||||||
zipFile.addFile(entry.value, entry.name);
|
zipFile.addFile(entry.value, entry.name);
|
||||||
zipFile.end();
|
zipFile.end();
|
||||||
const zipFileName = state.traceFile + '.zip';
|
const zipFileName = state.traceFile.file + '.zip';
|
||||||
zipFile.outputStream.pipe(fs.createWriteStream(zipFileName)).on('close', () => {
|
zipFile.outputStream.pipe(fs.createWriteStream(zipFileName)).on('close', () => {
|
||||||
const artifact = new Artifact(this._context, zipFileName);
|
const artifact = new Artifact(this._context, zipFileName);
|
||||||
artifact.reportFinished();
|
artifact.reportFinished();
|
||||||
|
|
|
||||||
4
packages/playwright-core/types/types.d.ts
vendored
4
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -16435,7 +16435,7 @@ export interface ConsoleMessage {
|
||||||
/**
|
/**
|
||||||
* The page that produced this console message, if any.
|
* The page that produced this console message, if any.
|
||||||
*/
|
*/
|
||||||
page(): Page|null;
|
page(): null|Page;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The text of the console message.
|
* The text of the console message.
|
||||||
|
|
@ -16637,7 +16637,7 @@ export interface Dialog {
|
||||||
/**
|
/**
|
||||||
* The page that initiated this dialog, if available.
|
* The page that initiated this dialog, if available.
|
||||||
*/
|
*/
|
||||||
page(): Page|null;
|
page(): null|Page;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns dialog's type, can be one of `alert`, `beforeunload`, `confirm` or `prompt`.
|
* Returns dialog's type, can be one of `alert`, `beforeunload`, `confirm` or `prompt`.
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,4 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
module.exports = require('@playwright/test/cli');
|
module.exports = require('@playwright/test/lib/cli');
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@playwright/experimental-ct-core",
|
"name": "@playwright/experimental-ct-core",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "Playwright Component Testing Helpers",
|
"description": "Playwright Component Testing Helpers",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vite": "^4.3.3",
|
"vite": "^4.3.3",
|
||||||
"@playwright/test": "1.34.0-next"
|
"@playwright/test": "1.34.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "./cli.js"
|
"playwright": "./cli.js"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@playwright/experimental-ct-react",
|
"name": "@playwright/experimental-ct-react",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "Playwright Component Testing for React",
|
"description": "Playwright Component Testing for React",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-react": "^4.0.0"
|
"@vitejs/plugin-react": "^4.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@playwright/experimental-ct-react17",
|
"name": "@playwright/experimental-ct-react17",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "Playwright Component Testing for React",
|
"description": "Playwright Component Testing for React",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-react": "^4.0.0"
|
"@vitejs/plugin-react": "^4.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@playwright/experimental-ct-solid",
|
"name": "@playwright/experimental-ct-solid",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "Playwright Component Testing for Solid",
|
"description": "Playwright Component Testing for Solid",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"vite-plugin-solid": "^2.7.0"
|
"vite-plugin-solid": "^2.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@playwright/experimental-ct-svelte",
|
"name": "@playwright/experimental-ct-svelte",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "Playwright Component Testing for Svelte",
|
"description": "Playwright Component Testing for Svelte",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.1.1"
|
"@sveltejs/vite-plugin-svelte": "^2.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@playwright/experimental-ct-vue",
|
"name": "@playwright/experimental-ct-vue",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "Playwright Component Testing for Vue",
|
"description": "Playwright Component Testing for Vue",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-vue": "^4.2.1"
|
"@vitejs/plugin-vue": "^4.2.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@playwright/experimental-ct-vue2",
|
"name": "@playwright/experimental-ct-vue2",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "Playwright Component Testing for Vue2",
|
"description": "Playwright Component Testing for Vue2",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@playwright/experimental-ct-core": "1.34.0-next",
|
"@playwright/experimental-ct-core": "1.34.3",
|
||||||
"@vitejs/plugin-vue2": "^2.2.0"
|
"@vitejs/plugin-vue2": "^2.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "playwright-firefox",
|
"name": "playwright-firefox",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "A high-level API to automate Firefox",
|
"description": "A high-level API to automate Firefox",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -27,6 +27,6 @@
|
||||||
"install": "node install.js"
|
"install": "node install.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,4 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
module.exports = require('./lib/cli');
|
module.exports = require('@playwright/test/lib/cli');
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,10 @@ function jsxs(type, props) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Fragment = {};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
Fragment,
|
||||||
jsx,
|
jsx,
|
||||||
jsxs,
|
jsxs,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
21
packages/playwright-test/jsx-runtime.mjs
Normal file
21
packages/playwright-test/jsx-runtime.mjs
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jsxRuntime from './jsx-runtime.js';
|
||||||
|
|
||||||
|
export const jsx = jsxRuntime.jsx;
|
||||||
|
export const jsxs = jsxRuntime.jsxs;
|
||||||
|
export const Fragment = jsxRuntime.Fragment;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@playwright/test",
|
"name": "@playwright/test",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "A high-level API to automate web browsers",
|
"description": "A high-level API to automate web browsers",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -23,7 +23,11 @@
|
||||||
"./lib/internalsForTest": "./lib/internalsForTest.js",
|
"./lib/internalsForTest": "./lib/internalsForTest.js",
|
||||||
"./lib/experimentalLoader": "./lib/experimentalLoader.js",
|
"./lib/experimentalLoader": "./lib/experimentalLoader.js",
|
||||||
"./lib/plugins": "./lib/plugins/index.js",
|
"./lib/plugins": "./lib/plugins/index.js",
|
||||||
"./jsx-runtime": "./jsx-runtime.js",
|
"./jsx-runtime": {
|
||||||
|
"import": "./jsx-runtime.mjs",
|
||||||
|
"require": "./jsx-runtime.js",
|
||||||
|
"default": "./jsx-runtime.js"
|
||||||
|
},
|
||||||
"./lib/util": "./lib/util.js",
|
"./lib/util": "./lib/util.js",
|
||||||
"./lib/utilsBundle": "./lib/utilsBundle.js",
|
"./lib/utilsBundle": "./lib/utilsBundle.js",
|
||||||
"./reporter": "./reporter.js"
|
"./reporter": "./reporter.js"
|
||||||
|
|
@ -37,7 +41,7 @@
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"fsevents": "2.3.2"
|
"fsevents": "2.3.2"
|
||||||
|
|
|
||||||
|
|
@ -558,7 +558,7 @@ class ArtifactsRecorder {
|
||||||
private _traceMode: TraceMode;
|
private _traceMode: TraceMode;
|
||||||
private _captureTrace = false;
|
private _captureTrace = false;
|
||||||
private _screenshotOptions: { mode: ScreenshotMode } & Pick<playwrightLibrary.PageScreenshotOptions, 'fullPage' | 'omitBackground'> | undefined;
|
private _screenshotOptions: { mode: ScreenshotMode } & Pick<playwrightLibrary.PageScreenshotOptions, 'fullPage' | 'omitBackground'> | undefined;
|
||||||
private _traceOptions: { screenshots: boolean, snapshots: boolean, sources: boolean, mode?: TraceMode };
|
private _traceOptions: { screenshots: boolean, snapshots: boolean, sources: boolean, attachments: boolean, mode?: TraceMode };
|
||||||
private _temporaryTraceFiles: string[] = [];
|
private _temporaryTraceFiles: string[] = [];
|
||||||
private _temporaryScreenshots: string[] = [];
|
private _temporaryScreenshots: string[] = [];
|
||||||
private _reusedContexts = new Set<BrowserContext>();
|
private _reusedContexts = new Set<BrowserContext>();
|
||||||
|
|
@ -572,7 +572,7 @@ class ArtifactsRecorder {
|
||||||
this._screenshotMode = normalizeScreenshotMode(screenshot);
|
this._screenshotMode = normalizeScreenshotMode(screenshot);
|
||||||
this._screenshotOptions = typeof screenshot === 'string' ? undefined : screenshot;
|
this._screenshotOptions = typeof screenshot === 'string' ? undefined : screenshot;
|
||||||
this._traceMode = normalizeTraceMode(trace);
|
this._traceMode = normalizeTraceMode(trace);
|
||||||
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true };
|
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true, attachments: true };
|
||||||
this._traceOptions = typeof trace === 'string' ? defaultTraceOptions : { ...defaultTraceOptions, ...trace, mode: undefined };
|
this._traceOptions = typeof trace === 'string' ? defaultTraceOptions : { ...defaultTraceOptions, ...trace, mode: undefined };
|
||||||
this._screenshottedSymbol = Symbol('screenshotted');
|
this._screenshottedSymbol = Symbol('screenshotted');
|
||||||
this._startedCollectingArtifacts = Symbol('startedCollectingArtifacts');
|
this._startedCollectingArtifacts = Symbol('startedCollectingArtifacts');
|
||||||
|
|
@ -661,6 +661,12 @@ class ArtifactsRecorder {
|
||||||
if (this._preserveTrace()) {
|
if (this._preserveTrace()) {
|
||||||
const events = this._testInfo._traceEvents;
|
const events = this._testInfo._traceEvents;
|
||||||
if (events.length) {
|
if (events.length) {
|
||||||
|
if (!this._traceOptions.attachments) {
|
||||||
|
for (const event of events) {
|
||||||
|
if (event.type === 'after')
|
||||||
|
delete event.attachments;
|
||||||
|
}
|
||||||
|
}
|
||||||
const tracePath = path.join(this._artifactsDir, createGuid() + '.zip');
|
const tracePath = path.join(this._artifactsDir, createGuid() + '.zip');
|
||||||
this._temporaryTraceFiles.push(tracePath);
|
this._temporaryTraceFiles.push(tracePath);
|
||||||
await saveTraceFile(tracePath, events, this._traceOptions.sources);
|
await saveTraceFile(tracePath, events, this._traceOptions.sources);
|
||||||
|
|
|
||||||
2
packages/playwright-test/types/test.d.ts
vendored
2
packages/playwright-test/types/test.d.ts
vendored
|
|
@ -3554,7 +3554,7 @@ export interface PlaywrightWorkerOptions {
|
||||||
*
|
*
|
||||||
* Learn more about [recording trace](https://playwright.dev/docs/test-configuration#record-test-trace).
|
* Learn more about [recording trace](https://playwright.dev/docs/test-configuration#record-test-trace).
|
||||||
*/
|
*/
|
||||||
trace: TraceMode | /** deprecated */ 'retry-with-trace' | { mode: TraceMode, snapshots?: boolean, screenshots?: boolean, sources?: boolean };
|
trace: TraceMode | /** deprecated */ 'retry-with-trace' | { mode: TraceMode, snapshots?: boolean, screenshots?: boolean, sources?: boolean, attachments?: boolean };
|
||||||
/**
|
/**
|
||||||
* Whether to record video for each test. Defaults to `'off'`.
|
* Whether to record video for each test. Defaults to `'off'`.
|
||||||
* - `'off'`: Do not record video.
|
* - `'off'`: Do not record video.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "playwright-webkit",
|
"name": "playwright-webkit",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "A high-level API to automate WebKit",
|
"description": "A high-level API to automate WebKit",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -27,6 +27,6 @@
|
||||||
"install": "node install.js"
|
"install": "node install.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "playwright",
|
"name": "playwright",
|
||||||
"version": "1.34.0-next",
|
"version": "1.34.3",
|
||||||
"description": "A high-level API to automate web browsers",
|
"description": "A high-level API to automate web browsers",
|
||||||
"repository": "github:Microsoft/playwright",
|
"repository": "github:Microsoft/playwright",
|
||||||
"homepage": "https://playwright.dev",
|
"homepage": "https://playwright.dev",
|
||||||
|
|
@ -28,6 +28,6 @@
|
||||||
"install": "node install.js"
|
"install": "node install.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.34.0-next"
|
"playwright-core": "1.34.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,13 +76,6 @@ export class TraceModel {
|
||||||
unzipProgress(++done, total);
|
unzipProgress(++done, total);
|
||||||
|
|
||||||
contextEntry.actions = [...actionMap.values()].sort((a1, a2) => a1.startTime - a2.startTime);
|
contextEntry.actions = [...actionMap.values()].sort((a1, a2) => a1.startTime - a2.startTime);
|
||||||
if (!backend.isLive()) {
|
|
||||||
for (const action of contextEntry.actions) {
|
|
||||||
if (!action.endTime && !action.error)
|
|
||||||
action.error = { name: 'Error', message: 'Timed out' };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const stacks = await this._backend.readText(ordinal + '.stacks');
|
const stacks = await this._backend.readText(ordinal + '.stacks');
|
||||||
if (stacks) {
|
if (stacks) {
|
||||||
const callMetadata = parseClientSideCallMetadata(JSON.parse(stacks));
|
const callMetadata = parseClientSideCallMetadata(JSON.parse(stacks));
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ export interface ActionListProps {
|
||||||
onSelected: (action: ActionTraceEvent) => void,
|
onSelected: (action: ActionTraceEvent) => void,
|
||||||
onHighlighted: (action: ActionTraceEvent | undefined) => void,
|
onHighlighted: (action: ActionTraceEvent | undefined) => void,
|
||||||
revealConsole: () => void,
|
revealConsole: () => void,
|
||||||
|
isLive?: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionTreeItem = {
|
type ActionTreeItem = {
|
||||||
|
|
@ -49,6 +50,7 @@ export const ActionList: React.FC<ActionListProps> = ({
|
||||||
onSelected,
|
onSelected,
|
||||||
onHighlighted,
|
onHighlighted,
|
||||||
revealConsole,
|
revealConsole,
|
||||||
|
isLive,
|
||||||
}) => {
|
}) => {
|
||||||
const [treeState, setTreeState] = React.useState<TreeState>({ expandedItems: new Map() });
|
const [treeState, setTreeState] = React.useState<TreeState>({ expandedItems: new Map() });
|
||||||
const { rootItem, itemMap } = React.useMemo(() => {
|
const { rootItem, itemMap } = React.useMemo(() => {
|
||||||
|
|
@ -86,14 +88,15 @@ export const ActionList: React.FC<ActionListProps> = ({
|
||||||
onSelected={item => onSelected(item.action!)}
|
onSelected={item => onSelected(item.action!)}
|
||||||
onHighlighted={item => onHighlighted(item?.action)}
|
onHighlighted={item => onHighlighted(item?.action)}
|
||||||
isError={item => !!item.action?.error?.message}
|
isError={item => !!item.action?.error?.message}
|
||||||
render={item => renderAction(item.action!, sdkLanguage, revealConsole)}
|
render={item => renderAction(item.action!, sdkLanguage, revealConsole, isLive || false)}
|
||||||
/>;
|
/>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderAction = (
|
const renderAction = (
|
||||||
action: ActionTraceEvent,
|
action: ActionTraceEvent,
|
||||||
sdkLanguage: Language | undefined,
|
sdkLanguage: Language | undefined,
|
||||||
revealConsole: () => void
|
revealConsole: () => void,
|
||||||
|
isLive: boolean,
|
||||||
) => {
|
) => {
|
||||||
const { errors, warnings } = modelUtil.stats(action);
|
const { errors, warnings } = modelUtil.stats(action);
|
||||||
const locator = action.params.selector ? asLocator(sdkLanguage || 'javascript', action.params.selector, false /* isFrameLocator */, true /* playSafe */) : undefined;
|
const locator = action.params.selector ? asLocator(sdkLanguage || 'javascript', action.params.selector, false /* isFrameLocator */, true /* playSafe */) : undefined;
|
||||||
|
|
@ -103,6 +106,8 @@ const renderAction = (
|
||||||
time = msToString(action.endTime - action.startTime);
|
time = msToString(action.endTime - action.startTime);
|
||||||
else if (action.error)
|
else if (action.error)
|
||||||
time = 'Timed out';
|
time = 'Timed out';
|
||||||
|
else if (!isLive)
|
||||||
|
time = '-';
|
||||||
return <>
|
return <>
|
||||||
<div className='action-title'>
|
<div className='action-title'>
|
||||||
<span>{action.apiName}</span>
|
<span>{action.apiName}</span>
|
||||||
|
|
|
||||||
|
|
@ -492,7 +492,7 @@ const TraceView: React.FC<{
|
||||||
item: { testFile?: SourceLocation, testCase?: TestCase },
|
item: { testFile?: SourceLocation, testCase?: TestCase },
|
||||||
rootDir?: string,
|
rootDir?: string,
|
||||||
}> = ({ item, rootDir }) => {
|
}> = ({ item, rootDir }) => {
|
||||||
const [model, setModel] = React.useState<MultiTraceModel | undefined>();
|
const [model, setModel] = React.useState<{ model: MultiTraceModel, isLive: boolean } | undefined>();
|
||||||
const [counter, setCounter] = React.useState(0);
|
const [counter, setCounter] = React.useState(0);
|
||||||
const pollTimer = React.useRef<NodeJS.Timeout | null>(null);
|
const pollTimer = React.useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
|
|
@ -505,7 +505,7 @@ const TraceView: React.FC<{
|
||||||
// This avoids auto-selection of the last action every time we reload the model.
|
// This avoids auto-selection of the last action every time we reload the model.
|
||||||
const [selectedActionId, setSelectedActionId] = React.useState<string | undefined>();
|
const [selectedActionId, setSelectedActionId] = React.useState<string | undefined>();
|
||||||
const onSelectionChanged = React.useCallback((action: ActionTraceEvent) => setSelectedActionId(idForAction(action)), [setSelectedActionId]);
|
const onSelectionChanged = React.useCallback((action: ActionTraceEvent) => setSelectedActionId(idForAction(action)), [setSelectedActionId]);
|
||||||
const initialSelection = selectedActionId ? model?.actions.find(a => idForAction(a) === selectedActionId) : undefined;
|
const initialSelection = selectedActionId ? model?.model.actions.find(a => idForAction(a) === selectedActionId) : undefined;
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (pollTimer.current)
|
if (pollTimer.current)
|
||||||
|
|
@ -520,7 +520,7 @@ const TraceView: React.FC<{
|
||||||
// Test finished.
|
// Test finished.
|
||||||
const attachment = result && result.duration >= 0 && result.attachments.find(a => a.name === 'trace');
|
const attachment = result && result.duration >= 0 && result.attachments.find(a => a.name === 'trace');
|
||||||
if (attachment && attachment.path) {
|
if (attachment && attachment.path) {
|
||||||
loadSingleTraceFile(attachment.path).then(model => setModel(model));
|
loadSingleTraceFile(attachment.path).then(model => setModel({ model, isLive: false }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -534,7 +534,7 @@ const TraceView: React.FC<{
|
||||||
pollTimer.current = setTimeout(async () => {
|
pollTimer.current = setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
const model = await loadSingleTraceFile(traceLocation);
|
const model = await loadSingleTraceFile(traceLocation);
|
||||||
setModel(model);
|
setModel({ model, isLive: true });
|
||||||
} catch {
|
} catch {
|
||||||
setModel(undefined);
|
setModel(undefined);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -549,14 +549,15 @@ const TraceView: React.FC<{
|
||||||
|
|
||||||
return <Workbench
|
return <Workbench
|
||||||
key='workbench'
|
key='workbench'
|
||||||
model={model}
|
model={model?.model}
|
||||||
hideTimelineBars={true}
|
hideTimelineBars={true}
|
||||||
hideStackFrames={true}
|
hideStackFrames={true}
|
||||||
showSourcesFirst={true}
|
showSourcesFirst={true}
|
||||||
rootDir={rootDir}
|
rootDir={rootDir}
|
||||||
initialSelection={initialSelection}
|
initialSelection={initialSelection}
|
||||||
onSelectionChanged={onSelectionChanged}
|
onSelectionChanged={onSelectionChanged}
|
||||||
fallbackLocation={item.testFile} />;
|
fallbackLocation={item.testFile}
|
||||||
|
isLive={model?.isLive} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@ export const Workbench: React.FunctionComponent<{
|
||||||
fallbackLocation?: modelUtil.SourceLocation,
|
fallbackLocation?: modelUtil.SourceLocation,
|
||||||
initialSelection?: ActionTraceEvent,
|
initialSelection?: ActionTraceEvent,
|
||||||
onSelectionChanged?: (action: ActionTraceEvent) => void,
|
onSelectionChanged?: (action: ActionTraceEvent) => void,
|
||||||
}> = ({ model, hideTimelineBars, hideStackFrames, showSourcesFirst, rootDir, fallbackLocation, initialSelection, onSelectionChanged }) => {
|
isLive?: boolean,
|
||||||
|
}> = ({ model, hideTimelineBars, hideStackFrames, showSourcesFirst, rootDir, fallbackLocation, initialSelection, onSelectionChanged, isLive }) => {
|
||||||
const [selectedAction, setSelectedAction] = React.useState<ActionTraceEvent | undefined>(undefined);
|
const [selectedAction, setSelectedAction] = React.useState<ActionTraceEvent | undefined>(undefined);
|
||||||
const [highlightedAction, setHighlightedAction] = React.useState<ActionTraceEvent | undefined>();
|
const [highlightedAction, setHighlightedAction] = React.useState<ActionTraceEvent | undefined>();
|
||||||
const [selectedNavigatorTab, setSelectedNavigatorTab] = React.useState<string>('actions');
|
const [selectedNavigatorTab, setSelectedNavigatorTab] = React.useState<string>('actions');
|
||||||
|
|
@ -142,6 +143,7 @@ export const Workbench: React.FunctionComponent<{
|
||||||
onSelected={onActionSelected}
|
onSelected={onActionSelected}
|
||||||
onHighlighted={setHighlightedAction}
|
onHighlighted={setHighlightedAction}
|
||||||
revealConsole={() => setSelectedPropertiesTab('console')}
|
revealConsole={() => setSelectedPropertiesTab('console')}
|
||||||
|
isLive={isLive}
|
||||||
/>
|
/>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -578,7 +578,6 @@ test('should record global request trace', async ({ request, context, server },
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should store global request traces separately', async ({ request, server, playwright, browserName, mode }, testInfo) => {
|
test('should store global request traces separately', async ({ request, server, playwright, browserName, mode }, testInfo) => {
|
||||||
test.fixme(browserName === 'chromium' && mode === 'driver', 'https://github.com/microsoft/playwright/issues/23108');
|
|
||||||
const request2 = await playwright.request.newContext();
|
const request2 = await playwright.request.newContext();
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
(request as any)._tracing.start({ snapshots: true }),
|
(request as any)._tracing.start({ snapshots: true }),
|
||||||
|
|
|
||||||
|
|
@ -488,6 +488,34 @@ test('should load a jsx/tsx files', async ({ runInlineTest }) => {
|
||||||
expect(exitCode).toBe(0);
|
expect(exitCode).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should load a jsx/tsx files in ESM mode', async ({ runInlineTest }) => {
|
||||||
|
const { exitCode, passed } = await runInlineTest({
|
||||||
|
'package.json': JSON.stringify({
|
||||||
|
type: 'module'
|
||||||
|
}),
|
||||||
|
'playwright.config.ts': `
|
||||||
|
import { defineConfig } from '@playwright/test';
|
||||||
|
export default defineConfig({ projects: [{name: 'foo'}] });
|
||||||
|
`,
|
||||||
|
'a.spec.tsx': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
const component = () => <div></div>;
|
||||||
|
test('succeeds', () => {
|
||||||
|
expect(1 + 1).toBe(2);
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'b.spec.jsx': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
const component = () => <div></div>;
|
||||||
|
test('succeeds', () => {
|
||||||
|
expect(1 + 1).toBe(2);
|
||||||
|
});
|
||||||
|
`
|
||||||
|
});
|
||||||
|
expect(passed).toBe(2);
|
||||||
|
expect(exitCode).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
test('should load jsx with top-level component', async ({ runInlineTest }) => {
|
test('should load jsx with top-level component', async ({ runInlineTest }) => {
|
||||||
const { exitCode, passed } = await runInlineTest({
|
const { exitCode, passed } = await runInlineTest({
|
||||||
'a.spec.tsx': `
|
'a.spec.tsx': `
|
||||||
|
|
|
||||||
|
|
@ -526,3 +526,59 @@ test(`trace:retain-on-failure should create trace if request context is disposed
|
||||||
expect(trace.apiNames).toContain('apiRequestContext.get');
|
expect(trace.apiNames).toContain('apiRequestContext.get');
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should include attachments by default', async ({ runInlineTest, server }, testInfo) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'playwright.config.ts': `
|
||||||
|
module.exports = { use: { trace: 'on' } };
|
||||||
|
`,
|
||||||
|
'a.spec.ts': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test('pass', async ({}, testInfo) => {
|
||||||
|
testInfo.attach('foo', { body: 'bar' });
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
}, { workers: 1 });
|
||||||
|
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
const trace = await parseTrace(testInfo.outputPath('test-results', 'a-pass', 'trace.zip'));
|
||||||
|
expect(trace.apiNames).toEqual([
|
||||||
|
'Before Hooks',
|
||||||
|
`attach "foo"`,
|
||||||
|
'After Hooks',
|
||||||
|
]);
|
||||||
|
expect(trace.actions[1].attachments).toEqual([{
|
||||||
|
name: 'foo',
|
||||||
|
contentType: 'text/plain',
|
||||||
|
sha1: expect.any(String),
|
||||||
|
}]);
|
||||||
|
expect([...trace.resources.keys()].filter(f => f.startsWith('resources/'))).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should opt out of attachments', async ({ runInlineTest, server }, testInfo) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'playwright.config.ts': `
|
||||||
|
module.exports = { use: { trace: { mode: 'on', attachments: false } } };
|
||||||
|
`,
|
||||||
|
'a.spec.ts': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test('pass', async ({}, testInfo) => {
|
||||||
|
testInfo.attach('foo', { body: 'bar' });
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
}, { workers: 1 });
|
||||||
|
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
const trace = await parseTrace(testInfo.outputPath('test-results', 'a-pass', 'trace.zip'));
|
||||||
|
expect(trace.apiNames).toEqual([
|
||||||
|
'Before Hooks',
|
||||||
|
`attach "foo"`,
|
||||||
|
'After Hooks',
|
||||||
|
]);
|
||||||
|
expect(trace.actions[1].attachments).toEqual(undefined);
|
||||||
|
expect([...trace.resources.keys()].filter(f => f.startsWith('resources/'))).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1348,7 +1348,7 @@ test.describe('labels', () => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'a.test.js': `
|
'a.test.js': `
|
||||||
const { expect, test } = require('@playwright/test');
|
const { expect, test } = require('@playwright/test');
|
||||||
const tags = ['@smoke:p1', '@issue[123]', '@issue#123', '@$$$', '@tl/dr'];
|
const tags = ['@smoke-p1', '@issue[123]', '@issue#123', '@$$$', '@tl/dr'];
|
||||||
|
|
||||||
test.describe('Error Pages', () => {
|
test.describe('Error Pages', () => {
|
||||||
tags.forEach(tag => {
|
tags.forEach(tag => {
|
||||||
|
|
@ -1364,7 +1364,7 @@ test.describe('labels', () => {
|
||||||
expect(result.passed).toBe(5);
|
expect(result.passed).toBe(5);
|
||||||
|
|
||||||
await showReport();
|
await showReport();
|
||||||
const tags = ['smoke:p1', 'issue[123]', 'issue#123', '$$$', 'tl/dr'];
|
const tags = ['smoke-p1', 'issue[123]', 'issue#123', '$$$', 'tl/dr'];
|
||||||
const searchInput = page.locator('.subnav-search-input');
|
const searchInput = page.locator('.subnav-search-input');
|
||||||
|
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
|
|
@ -1881,3 +1881,61 @@ test('should list tests in the right order', async ({ runInlineTest, showReport,
|
||||||
/main › second › passes\d+m?ssecond.ts:5/,
|
/main › second › passes\d+m?ssecond.ts:5/,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('tests should filter by file', async ({ runInlineTest, showReport, page }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'file-a.test.js': `
|
||||||
|
const { test } = require('@playwright/test');
|
||||||
|
test('a test 1', async ({}) => {});
|
||||||
|
test('a test 2', async ({}) => {});
|
||||||
|
`,
|
||||||
|
'file-b.test.js': `
|
||||||
|
const { test } = require('@playwright/test');
|
||||||
|
test('b test 1', async ({}) => {});
|
||||||
|
test('b test 2', async ({}) => {});
|
||||||
|
`,
|
||||||
|
}, { reporter: 'dot,html' }, { PW_TEST_HTML_REPORT_OPEN: 'never' });
|
||||||
|
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(4);
|
||||||
|
expect(result.failed).toBe(0);
|
||||||
|
|
||||||
|
await showReport();
|
||||||
|
|
||||||
|
const searchInput = page.locator('.subnav-search-input');
|
||||||
|
|
||||||
|
await searchInput.fill('file-a');
|
||||||
|
await expect(page.getByText('file-a.test.js', { exact: true })).toBeVisible();
|
||||||
|
await expect(page.getByText('a test 1')).toBeVisible();
|
||||||
|
await expect(page.getByText('a test 2')).toBeVisible();
|
||||||
|
await expect(page.getByText('file-b.test.js', { exact: true })).not.toBeVisible();
|
||||||
|
await expect(page.getByText('b test 1')).not.toBeVisible();
|
||||||
|
await expect(page.getByText('b test 2')).not.toBeVisible();
|
||||||
|
|
||||||
|
await searchInput.fill('file-a:3');
|
||||||
|
await expect(page.getByText('a test 1')).toBeVisible();
|
||||||
|
await expect(page.getByText('a test 2')).not.toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('tests should filter by status', async ({ runInlineTest, showReport, page }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'a.test.js': `
|
||||||
|
const { test, expect } = require('@playwright/test');
|
||||||
|
test('failed title', async ({}) => { expect(1).toBe(1); });
|
||||||
|
test('passes title', async ({}) => { expect(1).toBe(2); });
|
||||||
|
`,
|
||||||
|
}, { reporter: 'dot,html' }, { PW_TEST_HTML_REPORT_OPEN: 'never' });
|
||||||
|
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
expect(result.failed).toBe(1);
|
||||||
|
|
||||||
|
await showReport();
|
||||||
|
|
||||||
|
const searchInput = page.locator('.subnav-search-input');
|
||||||
|
|
||||||
|
await searchInput.fill('s:failed');
|
||||||
|
await expect(page.getByText('a.test.js', { exact: true })).toBeVisible();
|
||||||
|
await expect(page.getByText('failed title')).not.toBeVisible();
|
||||||
|
await expect(page.getByText('passes title')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -98,9 +98,12 @@ test('should merge screenshot assertions', async ({ runUITest }, testInfo) => {
|
||||||
'action list'
|
'action list'
|
||||||
).toHaveText([
|
).toHaveText([
|
||||||
/Before Hooks[\d.]+m?s/,
|
/Before Hooks[\d.]+m?s/,
|
||||||
/page\.setContent[\d.]+m?s/,
|
/page.setContent[\d.]+m?s/,
|
||||||
/expect\.toHaveScreenshot[\d.]+m?s/,
|
/expect.toHaveScreenshot[\d.]+m?s/,
|
||||||
/After Hooks/,
|
/After Hooks-/,
|
||||||
|
/fixture: page[\d.]+m?s/,
|
||||||
|
/fixture: context[\d.]+m?s/,
|
||||||
|
/fixture: browser[\d.]+m?s/,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ RUN mkdir /ms-playwright && \
|
||||||
mkdir /ms-playwright-agent && \
|
mkdir /ms-playwright-agent && \
|
||||||
cd /ms-playwright-agent && npm init -y && \
|
cd /ms-playwright-agent && npm init -y && \
|
||||||
npm i /tmp/playwright-core.tar.gz && \
|
npm i /tmp/playwright-core.tar.gz && \
|
||||||
npx playwright mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
|
npm exec --no -- playwright-core mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
|
||||||
npx playwright install --with-deps && rm -rf /var/lib/apt/lists/* && \
|
npm exec --no -- playwright-core install --with-deps && rm -rf /var/lib/apt/lists/* && \
|
||||||
rm /tmp/playwright-core.tar.gz && \
|
rm /tmp/playwright-core.tar.gz && \
|
||||||
chmod -R 777 /ms-playwright
|
chmod -R 777 /ms-playwright
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ RUN mkdir /ms-playwright && \
|
||||||
mkdir /ms-playwright-agent && \
|
mkdir /ms-playwright-agent && \
|
||||||
cd /ms-playwright-agent && npm init -y && \
|
cd /ms-playwright-agent && npm init -y && \
|
||||||
npm i /tmp/playwright-core.tar.gz && \
|
npm i /tmp/playwright-core.tar.gz && \
|
||||||
npx playwright mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
|
npm exec --no -- playwright-core mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
|
||||||
npx playwright install --with-deps && rm -rf /var/lib/apt/lists/* && \
|
npm exec --no -- playwright-core install --with-deps && rm -rf /var/lib/apt/lists/* && \
|
||||||
rm /tmp/playwright-core.tar.gz && \
|
rm /tmp/playwright-core.tar.gz && \
|
||||||
rm -rf /ms-playwright-agent && \
|
rm -rf /ms-playwright-agent && \
|
||||||
chmod -R 777 /ms-playwright
|
chmod -R 777 /ms-playwright
|
||||||
|
|
|
||||||
2
utils/generate_types/overrides-test.d.ts
vendored
2
utils/generate_types/overrides-test.d.ts
vendored
|
|
@ -206,7 +206,7 @@ export interface PlaywrightWorkerOptions {
|
||||||
launchOptions: LaunchOptions;
|
launchOptions: LaunchOptions;
|
||||||
connectOptions: ConnectOptions | undefined;
|
connectOptions: ConnectOptions | undefined;
|
||||||
screenshot: ScreenshotMode | { mode: ScreenshotMode } & Pick<PageScreenshotOptions, 'fullPage' | 'omitBackground'>;
|
screenshot: ScreenshotMode | { mode: ScreenshotMode } & Pick<PageScreenshotOptions, 'fullPage' | 'omitBackground'>;
|
||||||
trace: TraceMode | /** deprecated */ 'retry-with-trace' | { mode: TraceMode, snapshots?: boolean, screenshots?: boolean, sources?: boolean };
|
trace: TraceMode | /** deprecated */ 'retry-with-trace' | { mode: TraceMode, snapshots?: boolean, screenshots?: boolean, sources?: boolean, attachments?: boolean };
|
||||||
video: VideoMode | /** deprecated */ 'retry-with-video' | { mode: VideoMode, size?: ViewportSize };
|
video: VideoMode | /** deprecated */ 'retry-with-video' | { mode: VideoMode, size?: ViewportSize };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ apt-get update && apt-get install -y curl && \
|
||||||
apt-get update && apt-get install -y apt-file && apt-file update
|
apt-get update && apt-get install -y apt-file && apt-file update
|
||||||
|
|
||||||
# Install tip-of-tree playwright-core and browsers
|
# Install tip-of-tree playwright-core and browsers
|
||||||
mkdir /root/tmp && cd /root/tmp && npm init -y && npm i /root/hostfolder/playwright-core.tar.gz && npx playwright install
|
mkdir /root/tmp && cd /root/tmp && npm init -y && npm i /root/hostfolder/playwright-core.tar.gz && npx playwright-core install
|
||||||
|
|
||||||
cp /root/hostfolder/inside_docker/list_dependencies.js /root/tmp/list_dependencies.js
|
cp /root/hostfolder/inside_docker/list_dependencies.js /root/tmp/list_dependencies.js
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue