Merge branch 'main' into sharding-algorithm
This commit is contained in:
commit
7ea1506799
|
|
@ -6,9 +6,14 @@ module.exports = {
|
|||
sourceType: "module",
|
||||
},
|
||||
extends: [
|
||||
"plugin:react/recommended",
|
||||
"plugin:react-hooks/recommended"
|
||||
],
|
||||
|
||||
settings: {
|
||||
react: { version: "18" }
|
||||
},
|
||||
|
||||
/**
|
||||
* ESLint rules
|
||||
*
|
||||
|
|
@ -30,6 +35,7 @@ module.exports = {
|
|||
"avoidEscape": true,
|
||||
"allowTemplateLiterals": true
|
||||
}],
|
||||
"jsx-quotes": [2, "prefer-single"],
|
||||
"no-extra-semi": 2,
|
||||
"@typescript-eslint/semi": [2],
|
||||
"comma-style": [2, "last"],
|
||||
|
|
@ -123,5 +129,8 @@ module.exports = {
|
|||
"mustMatch": "Copyright",
|
||||
"templateFile": require("path").join(__dirname, "utils", "copyright.js"),
|
||||
}],
|
||||
|
||||
// react
|
||||
"react/react-in-jsx-scope": 0
|
||||
}
|
||||
};
|
||||
|
|
|
|||
1
.github/ISSUE_TEMPLATE/bug.yml
vendored
1
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
|
@ -24,6 +24,7 @@ body:
|
|||
## Make a minimal reproduction
|
||||
To file the report, you will need a GitHub repository with a minimal (but complete) example and simple/clear steps on how to reproduce the bug.
|
||||
The simpler you can make it, the more likely we are to successfully verify and fix the bug. You can create a new project with `npm init playwright@latest new-project` and then add the test code there.
|
||||
Please make sure you only include the code and the dependencies absolutely necessary for your repro. Due to the security considerations, we can only run the code we trust. Major web frameworks are Ok to use, but smaller convenience libraries are not.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
|
|
|
|||
2
.github/workflows/publish_canary.yml
vendored
2
.github/workflows/publish_canary.yml
vendored
|
|
@ -14,7 +14,7 @@ env:
|
|||
jobs:
|
||||
publish-canary:
|
||||
name: "publish canary NPM"
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
permissions:
|
||||
id-token: write # This is required for OIDC login (azure/login) to succeed
|
||||
|
|
|
|||
9
.github/workflows/publish_release_docker.yml
vendored
9
.github/workflows/publish_release_docker.yml
vendored
|
|
@ -2,12 +2,6 @@ name: "publish release - Docker"
|
|||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
is_release:
|
||||
required: true
|
||||
type: boolean
|
||||
description: "Is this a release image?"
|
||||
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
|
|
@ -45,6 +39,3 @@ jobs:
|
|||
- name: Login to ACR via OIDC
|
||||
run: az acr login --name playwright
|
||||
- run: ./utils/docker/publish_docker.sh stable
|
||||
if: (github.event_name != 'workflow_dispatch' && !github.event.release.prerelease) || (github.event_name == 'workflow_dispatch' && github.event.inputs.is_release == 'true')
|
||||
- run: ./utils/docker/publish_docker.sh canary
|
||||
if: (github.event_name != 'workflow_dispatch' && github.event.release.prerelease) || (github.event_name == 'workflow_dispatch' && github.event.inputs.is_release != 'true')
|
||||
|
|
|
|||
2
.github/workflows/publish_release_driver.yml
vendored
2
.github/workflows/publish_release_driver.yml
vendored
|
|
@ -10,7 +10,7 @@ env:
|
|||
jobs:
|
||||
publish-driver-release:
|
||||
name: "publish playwright driver to CDN"
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
permissions:
|
||||
id-token: write # This is required for OIDC login (azure/login) to succeed
|
||||
|
|
|
|||
42
.github/workflows/tests_bidi.yml
vendored
Normal file
42
.github/workflows/tests_bidi.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
name: tests BiDi
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- .github/workflows/tests_bidi.yml
|
||||
schedule:
|
||||
# Run every day at midnight
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
|
||||
|
||||
jobs:
|
||||
test_bidi:
|
||||
name: BiDi
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
id-token: write # This is required for OIDC login (azure/login) to succeed
|
||||
contents: read # This is required for actions/checkout to succeed
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# TODO: add Firefox
|
||||
channel: [bidi-chrome-stable]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- run: npm ci
|
||||
env:
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1'
|
||||
- run: npm run build
|
||||
- run: npx playwright install --with-deps chromium
|
||||
- name: Run tests
|
||||
run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run biditest -- --project=${{ matrix.channel }}*
|
||||
1
.github/workflows/tests_primary.yml
vendored
1
.github/workflows/tests_primary.yml
vendored
|
|
@ -219,7 +219,6 @@ jobs:
|
|||
with:
|
||||
command: npm run itest
|
||||
bot-name: "package-installations-${{ matrix.os }}"
|
||||
# TODO: figure out why itest fails with 'bash' on Windows.
|
||||
shell: ${{ matrix.os == 'windows-latest' && 'pwsh' || 'bash' }}
|
||||
flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }}
|
||||
flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }}
|
||||
|
|
|
|||
2
.github/workflows/tests_secondary.yml
vendored
2
.github/workflows/tests_secondary.yml
vendored
|
|
@ -529,7 +529,7 @@ jobs:
|
|||
|
||||
build-playwright-driver:
|
||||
name: "build-playwright-driver"
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
|
|
|
|||
2
.github/workflows/tests_service.yml
vendored
2
.github/workflows/tests_service.yml
vendored
|
|
@ -53,7 +53,7 @@ jobs:
|
|||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||
- run: npm run build
|
||||
- name: Download blob report artifact
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: all-blob-reports
|
||||
path: all-blob-reports
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -34,3 +34,4 @@ test-results
|
|||
/tests/installation/.registry.json
|
||||
.cache/
|
||||
.eslintcache
|
||||
playwright.env
|
||||
|
|
|
|||
|
|
@ -46,12 +46,16 @@ npm ci
|
|||
npm run build
|
||||
```
|
||||
|
||||
4. Run all Playwright tests locally. For more information about tests, read [Running & Writing Tests](#running--writing-tests).
|
||||
4. Run tests
|
||||
|
||||
This will run a test on line `23` in `page-fill.spec.ts`:
|
||||
|
||||
```bash
|
||||
npm test
|
||||
npm run ctest -- page-fill:23
|
||||
```
|
||||
|
||||
See [here](#running--writing-tests) for more information about running and writing tests.
|
||||
|
||||
### Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
|
|
@ -95,7 +99,7 @@ footer
|
|||
1. *label* is one of the following:
|
||||
- `fix` - playwright bug fixes.
|
||||
- `feat` - playwright features.
|
||||
- `docs` - changes to docs, e.g. `docs(api.md): ..` to change documentation.
|
||||
- `docs` - changes to docs, e.g. `docs(api): ..` to change documentation.
|
||||
- `test` - changes to playwright tests infrastructure.
|
||||
- `devops` - build-related work, e.g. CI related patches and general changes to the browser build infrastructure
|
||||
- `chore` - everything that doesn't fall under previous categories
|
||||
|
|
@ -159,11 +163,14 @@ npm run test
|
|||
Be sure to run `npm run build` or let `npm run watch` run before you re-run the
|
||||
tests after making your changes to check them.
|
||||
|
||||
- To run all tests in Chromium
|
||||
- To run tests in Chromium
|
||||
```bash
|
||||
npm run ctest # also `ftest` for firefox and `wtest` for WebKit
|
||||
npm run ctest -- page-fill:23 # runs line 23 of page-fill.spec.ts
|
||||
```
|
||||
|
||||
To run tests in WebKit / Firefox, use `wtest` or `ftest`.
|
||||
|
||||
- To run the Playwright test runner tests
|
||||
```bash
|
||||
npm run ttest
|
||||
|
|
@ -206,31 +213,13 @@ npm run ctest -- --headed
|
|||
CRPATH=<path-to-executable> npm run ctest
|
||||
```
|
||||
|
||||
- To run tests in slow-mode:
|
||||
|
||||
```bash
|
||||
SLOW_MO=500 npm run wtest -- --headed
|
||||
```
|
||||
|
||||
- When should a test be marked with `skip` or `fail`?
|
||||
- When should a test be marked with `skip` or `fixme`?
|
||||
|
||||
- **`skip(condition)`**: This test *should ***never*** work* for `condition`
|
||||
where `condition` is usually a certain browser like `FFOX` (for Firefox),
|
||||
`WEBKIT` (for WebKit), and `CHROMIUM` (for Chromium).
|
||||
where `condition` is usually something like: `test.skip(browserName === 'chromium', 'This does not work because of ...')`.
|
||||
|
||||
For example, the [alt-click downloads test](https://github.com/microsoft/playwright/blob/471ccc72d3f0847caa36f629b394a028c7750d93/test/download.spec.js#L86) is marked
|
||||
with `skip(FFOX)` since an alt-click in Firefox will not produce a download
|
||||
even if a person was driving the browser.
|
||||
|
||||
|
||||
- **`fail(condition)`**: This test *should ***eventually*** work* for `condition`
|
||||
where `condition` is usually a certain browser like `FFOX` (for Firefox),
|
||||
`WEBKIT` (for WebKit), and `CHROMIUM` (for Chromium).
|
||||
|
||||
For example, the [alt-click downloads test](https://github.com/microsoft/playwright/blob/471ccc72d3f0847caa36f629b394a028c7750d93/test/download.spec.js#L86) is marked
|
||||
with `fail(CHROMIUM || WEBKIT)` since Playwright performing these actions
|
||||
currently diverges from what a user would experience driving a Chromium or
|
||||
WebKit.
|
||||
- **`fixme(condition)`**: This test *should ***eventually*** work* for `condition`
|
||||
where `condition` is usually something like: `test.fixme(browserName === 'chromium', 'We are waiting for version x')`.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# 🎭 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 --> [](https://aka.ms/playwright/discord)
|
||||
|
||||
## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright)
|
||||
|
||||
|
|
@ -8,9 +8,9 @@ Playwright is a framework for Web Testing and Automation. It allows testing [Chr
|
|||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->127.0.6533.26<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->17.4<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Firefox <!-- GEN:firefox-version -->127.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Chromium <!-- GEN:chromium-version -->129.0.6668.29<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->18.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Firefox <!-- GEN:firefox-version -->130.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
|
||||
Headless execution is supported for all browsers on all platforms. Check out [system requirements](https://playwright.dev/docs/intro#system-requirements) for details.
|
||||
|
||||
|
|
|
|||
14
SECURITY.md
14
SECURITY.md
|
|
@ -1,18 +1,18 @@
|
|||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.3 BLOCK -->
|
||||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.9 BLOCK -->
|
||||
|
||||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
|
||||
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ Please include the requested information listed below (as much as you can provid
|
|||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
|
|
@ -36,6 +36,6 @@ We prefer all communications to be in English.
|
|||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
|
||||
|
||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
||||
|
|
|
|||
17
SUPPORT.md
Normal file
17
SUPPORT.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Support
|
||||
|
||||
## How to file issues and get help
|
||||
|
||||
This project uses GitHub issues to track bugs and feature requests. Please search the [existing issues][gh-issues] before filing new ones to avoid duplicates. For new issues, file your bug or feature request as a new issue using corresponding template.
|
||||
|
||||
For help and questions about using this project, please see the [docs site for Playwright][docs].
|
||||
|
||||
Join our community [Discord Server][discord-server] to connect with other developers using Playwright and ask questions in our 'help-playwright' forum.
|
||||
|
||||
## Microsoft Support Policy
|
||||
|
||||
Support for Playwright is limited to the resources listed above.
|
||||
|
||||
[gh-issues]: https://github.com/microsoft/playwright/issues/
|
||||
[docs]: https://playwright.dev/
|
||||
[discord-server]: https://aka.ms/playwright/discord
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
REMOTE_URL="https://github.com/mozilla/gecko-dev"
|
||||
BASE_BRANCH="release"
|
||||
BASE_REVISION="bd7e0ac24a6fb1cddde3e45ea191b7abcc90cf56"
|
||||
BASE_REVISION="cf0397e3ba298868fdca53f894da5b0d239dc09e"
|
||||
|
|
|
|||
|
|
@ -602,6 +602,8 @@ class NetworkObserver {
|
|||
proxyFilter.onProxyFilterResult(defaultProxyInfo);
|
||||
return;
|
||||
}
|
||||
if (this._targetRegistry.shouldBustHTTPAuthCacheForProxy(proxy))
|
||||
Services.obs.notifyObservers(null, "net:clear-active-logins");
|
||||
proxyFilter.onProxyFilterResult(protocolProxyService.newProxyInfo(
|
||||
proxy.type,
|
||||
proxy.host,
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ class TargetRegistry {
|
|||
this._browserToTarget = new Map();
|
||||
this._browserIdToTarget = new Map();
|
||||
|
||||
this._proxiesWithClashingAuthCacheKeys = new Set();
|
||||
this._browserProxy = null;
|
||||
|
||||
// Cleanup containers from previous runs (if any)
|
||||
|
|
@ -234,12 +235,50 @@ class TargetRegistry {
|
|||
onOpenWindow(win);
|
||||
}
|
||||
|
||||
// Firefox uses nsHttpAuthCache to cache authentication to the proxy.
|
||||
// If we're provided with a single proxy with a multiple different authentications, then
|
||||
// we should clear the nsHttpAuthCache on every request.
|
||||
shouldBustHTTPAuthCacheForProxy(proxy) {
|
||||
return this._proxiesWithClashingAuthCacheKeys.has(proxy);
|
||||
}
|
||||
|
||||
_updateProxiesWithSameAuthCacheAndDifferentCredentials() {
|
||||
const proxyIdToCredentials = new Map();
|
||||
const allProxies = [...this._browserContextIdToBrowserContext.values()].map(bc => bc._proxy).filter(Boolean);
|
||||
if (this._browserProxy)
|
||||
allProxies.push(this._browserProxy);
|
||||
const proxyAuthCacheKeyAndProxy = allProxies.map(proxy => [
|
||||
JSON.stringify({
|
||||
type: proxy.type,
|
||||
host: proxy.host,
|
||||
port: proxy.port,
|
||||
}),
|
||||
proxy,
|
||||
]);
|
||||
this._proxiesWithClashingAuthCacheKeys.clear();
|
||||
|
||||
proxyAuthCacheKeyAndProxy.sort(([cacheKey1], [cacheKey2]) => cacheKey1 < cacheKey2 ? -1 : 1);
|
||||
for (let i = 0; i < proxyAuthCacheKeyAndProxy.length - 1; ++i) {
|
||||
const [cacheKey1, proxy1] = proxyAuthCacheKeyAndProxy[i];
|
||||
const [cacheKey2, proxy2] = proxyAuthCacheKeyAndProxy[i + 1];
|
||||
if (cacheKey1 !== cacheKey2)
|
||||
continue;
|
||||
if (proxy1.username === proxy2.username && proxy1.password === proxy2.password)
|
||||
continue;
|
||||
// `proxy1` and `proxy2` have the same caching key, but serve different credentials.
|
||||
// We have to bust HTTP Auth Cache everytime there's a request that will use either of the proxies.
|
||||
this._proxiesWithClashingAuthCacheKeys.add(proxy1);
|
||||
this._proxiesWithClashingAuthCacheKeys.add(proxy2);
|
||||
}
|
||||
}
|
||||
|
||||
async cancelDownload(options) {
|
||||
this._downloadInterceptor.cancelDownload(options.uuid);
|
||||
}
|
||||
|
||||
setBrowserProxy(proxy) {
|
||||
this._browserProxy = proxy;
|
||||
this._updateProxiesWithSameAuthCacheAndDifferentCredentials();
|
||||
}
|
||||
|
||||
getProxyInfo(channel) {
|
||||
|
|
@ -368,7 +407,7 @@ class PageTarget {
|
|||
onLocationChange: (aWebProgress, aRequest, aLocation) => this._onNavigated(aLocation),
|
||||
};
|
||||
this._eventListeners = [
|
||||
helper.addObserver(this._updateModalDialogs.bind(this), 'tabmodal-dialog-loaded'),
|
||||
helper.addObserver(this._updateModalDialogs.bind(this), 'common-dialog-loaded'),
|
||||
helper.addProgressListener(tab.linkedBrowser, navigationListener, Ci.nsIWebProgress.NOTIFY_LOCATION),
|
||||
helper.addEventListener(this._linkedBrowser, 'DOMModalDialogClosed', event => this._updateModalDialogs()),
|
||||
helper.addEventListener(this._linkedBrowser, 'WillChangeBrowserRemoteness', event => this._willChangeBrowserRemoteness()),
|
||||
|
|
@ -499,7 +538,7 @@ class PageTarget {
|
|||
}
|
||||
|
||||
_updateModalDialogs() {
|
||||
const prompts = new Set(this._linkedBrowser.tabModalPromptBox ? this._linkedBrowser.tabModalPromptBox.listPrompts() : []);
|
||||
const prompts = new Set(this._linkedBrowser.tabDialogBox.getContentDialogManager().dialogs.map(dialog => dialog.frameContentWindow.Dialog));
|
||||
for (const dialog of this._dialogs.values()) {
|
||||
if (!prompts.has(dialog.prompt())) {
|
||||
this._dialogs.delete(dialog.id());
|
||||
|
|
@ -906,12 +945,14 @@ class BrowserContext {
|
|||
}
|
||||
this._registry._browserContextIdToBrowserContext.delete(this.browserContextId);
|
||||
this._registry._userContextIdToBrowserContext.delete(this.userContextId);
|
||||
this._registry._updateProxiesWithSameAuthCacheAndDifferentCredentials();
|
||||
}
|
||||
|
||||
setProxy(proxy) {
|
||||
// Clear AuthCache.
|
||||
Services.obs.notifyObservers(null, "net:clear-active-logins");
|
||||
this._proxy = proxy;
|
||||
this._registry._updateProxiesWithSameAuthCacheAndDifferentCredentials();
|
||||
}
|
||||
|
||||
setIgnoreHTTPSErrors(ignoreHTTPSErrors) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ const helper = new Helper();
|
|||
|
||||
let sameProcessInstanceNumber = 0;
|
||||
|
||||
const topBrowingContextToAgents = new Map();
|
||||
|
||||
class JugglerFrameChild extends JSWindowActorChild {
|
||||
constructor() {
|
||||
super();
|
||||
|
|
@ -16,46 +18,66 @@ class JugglerFrameChild extends JSWindowActorChild {
|
|||
}
|
||||
|
||||
handleEvent(aEvent) {
|
||||
if (this._agents && aEvent.type === 'DOMWillOpenModalDialog') {
|
||||
this._agents.channel.pause();
|
||||
const agents = this._agents();
|
||||
if (!agents)
|
||||
return;
|
||||
if (aEvent.type === 'DOMWillOpenModalDialog') {
|
||||
agents.channel.pause();
|
||||
return;
|
||||
}
|
||||
if (this._agents && aEvent.type === 'DOMModalDialogClosed') {
|
||||
this._agents.channel.resumeSoon();
|
||||
if (aEvent.type === 'DOMModalDialogClosed') {
|
||||
agents.channel.resumeSoon();
|
||||
return;
|
||||
}
|
||||
if (this._agents && aEvent.target === this.document)
|
||||
this._agents.pageAgent.onWindowEvent(aEvent);
|
||||
if (this._agents && aEvent.target === this.document)
|
||||
this._agents.frameTree.onWindowEvent(aEvent);
|
||||
if (aEvent.target === this.document) {
|
||||
agents.pageAgent.onWindowEvent(aEvent);
|
||||
agents.frameTree.onWindowEvent(aEvent);
|
||||
}
|
||||
}
|
||||
|
||||
_agents() {
|
||||
return topBrowingContextToAgents.get(this.browsingContext.top);
|
||||
}
|
||||
|
||||
actorCreated() {
|
||||
this.actorName = `content::${this.browsingContext.browserId}/${this.browsingContext.id}/${++sameProcessInstanceNumber}`;
|
||||
|
||||
this._eventListeners.push(helper.addEventListener(this.contentWindow, 'load', event => {
|
||||
this._agents?.pageAgent.onWindowEvent(event);
|
||||
this._agents()?.pageAgent.onWindowEvent(event);
|
||||
}));
|
||||
|
||||
if (this.document.documentURI.startsWith('moz-extension://'))
|
||||
return;
|
||||
this._agents = initialize(this.browsingContext, this.docShell, this);
|
||||
|
||||
// Child frame events will be forwarded to related top-level agents.
|
||||
if (this.browsingContext.parent)
|
||||
return;
|
||||
|
||||
let agents = topBrowingContextToAgents.get(this.browsingContext);
|
||||
if (!agents) {
|
||||
agents = initialize(this.browsingContext, this.docShell);
|
||||
topBrowingContextToAgents.set(this.browsingContext, agents);
|
||||
}
|
||||
|
||||
_dispose() {
|
||||
helper.removeListeners(this._eventListeners);
|
||||
// We do not cleanup since agents are shared for all frames in the process.
|
||||
|
||||
// TODO: restore the cleanup.
|
||||
// Reset transport so that all messages will be pending and will not throw any errors.
|
||||
// this._channel.resetTransport();
|
||||
// this._agents.pageAgent.dispose();
|
||||
// this._agents.frameTree.dispose();
|
||||
// this._agents = undefined;
|
||||
agents.channel.bindToActor(this);
|
||||
agents.actor = this;
|
||||
}
|
||||
|
||||
didDestroy() {
|
||||
this._dispose();
|
||||
helper.removeListeners(this._eventListeners);
|
||||
|
||||
if (this.browsingContext.parent)
|
||||
return;
|
||||
|
||||
const agents = topBrowingContextToAgents.get(this.browsingContext);
|
||||
// The agents are already re-bound to a new actor.
|
||||
if (agents?.actor !== this)
|
||||
return;
|
||||
|
||||
topBrowingContextToAgents.delete(this.browsingContext);
|
||||
|
||||
agents.channel.resetTransport();
|
||||
agents.pageAgent.dispose();
|
||||
agents.frameTree.dispose();
|
||||
}
|
||||
|
||||
receiveMessage() { }
|
||||
|
|
|
|||
|
|
@ -370,7 +370,12 @@ class PageAgent {
|
|||
const unsafeObject = frame.unsafeObject(objectId);
|
||||
if (!unsafeObject)
|
||||
throw new Error('Object is not input!');
|
||||
const nsFiles = await Promise.all(files.map(filePath => File.createFromFileName(filePath)));
|
||||
let nsFiles;
|
||||
if (unsafeObject.webkitdirectory) {
|
||||
nsFiles = await new Directory(files[0]).getFiles(true);
|
||||
} else {
|
||||
nsFiles = await Promise.all(files.map(filePath => File.createFromFileName(filePath)));
|
||||
}
|
||||
unsafeObject.mozSetFileArray(nsFiles);
|
||||
const events = [
|
||||
new (frame.domWindow().Event)('input', { bubbles: true, cancelable: true, composed: true }),
|
||||
|
|
|
|||
|
|
@ -7,24 +7,10 @@ const {FrameTree} = ChromeUtils.import('chrome://juggler/content/content/FrameTr
|
|||
const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js');
|
||||
const {PageAgent} = ChromeUtils.import('chrome://juggler/content/content/PageAgent.js');
|
||||
|
||||
const browsingContextToAgents = new Map();
|
||||
const helper = new Helper();
|
||||
|
||||
function initialize(browsingContext, docShell, actor) {
|
||||
if (browsingContext.parent) {
|
||||
// For child frames, return agents from the main frame.
|
||||
return browsingContextToAgents.get(browsingContext.top);
|
||||
}
|
||||
|
||||
let data = browsingContextToAgents.get(browsingContext);
|
||||
if (data) {
|
||||
// Rebind from one main frame actor to another one.
|
||||
data.channel.bindToActor(actor);
|
||||
return data;
|
||||
}
|
||||
|
||||
data = { channel: undefined, pageAgent: undefined, frameTree: undefined, failedToOverrideTimezone: false };
|
||||
browsingContextToAgents.set(browsingContext, data);
|
||||
function initialize(browsingContext, docShell) {
|
||||
const data = { channel: undefined, pageAgent: undefined, frameTree: undefined, failedToOverrideTimezone: false };
|
||||
|
||||
const applySetting = {
|
||||
geolocation: (geolocation) => {
|
||||
|
|
@ -84,7 +70,6 @@ function initialize(browsingContext, docShell, actor) {
|
|||
data.frameTree.addBinding(worldName, name, script);
|
||||
data.frameTree.setInitScripts([...contextCrossProcessCookie.initScripts, ...pageCrossProcessCookie.initScripts]);
|
||||
data.channel = new SimpleChannel('', 'process-' + Services.appinfo.processID);
|
||||
data.channel.bindToActor(actor);
|
||||
data.pageAgent = new PageAgent(data.channel, data.frameTree);
|
||||
docShell.fileInputInterceptionEnabled = !!pageCrossProcessCookie.interceptFileChooserDialog;
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ class nsScreencastService::Session : public rtc::VideoSinkInterface<webrtc::Vide
|
|||
capability.height = 960;
|
||||
capability.maxFPS = ScreencastEncoder::fps;
|
||||
capability.videoType = webrtc::VideoType::kI420;
|
||||
int error = mCaptureModule->StartCapture(capability);
|
||||
int error = mCaptureModule->StartCaptureCounted(capability);
|
||||
if (error) {
|
||||
fprintf(stderr, "StartCapture error %d\n", error);
|
||||
return false;
|
||||
|
|
@ -152,7 +152,7 @@ class nsScreencastService::Session : public rtc::VideoSinkInterface<webrtc::Vide
|
|||
mCaptureModule->DeRegisterCaptureDataCallback(this);
|
||||
else
|
||||
mCaptureModule->DeRegisterRawFrameCallback(this);
|
||||
mCaptureModule->StopCapture();
|
||||
mCaptureModule->StopCaptureCounted();
|
||||
if (mEncoder) {
|
||||
mEncoder->finish([this, protect = RefPtr{this}] {
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -47,6 +47,9 @@ pref("permissions.isolateBy.userContext", true);
|
|||
// |Page.setFileInputFiles| protocol method.
|
||||
pref("dom.file.createInChild", true);
|
||||
|
||||
// Allow uploading directorys in content process.
|
||||
pref("dom.filesystem.pathcheck.disabled", true);
|
||||
|
||||
// Do not warn when closing all open tabs
|
||||
pref("browser.tabs.warnOnClose", false);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
REMOTE_URL="https://github.com/WebKit/WebKit.git"
|
||||
BASE_BRANCH="main"
|
||||
BASE_REVISION="b2ca06dc3d84b356d01cdf09a82049f80515fbfe"
|
||||
BASE_REVISION="f371dbc2bb4292037ed394e2162150a16ef977fc"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -39,5 +39,4 @@ fi
|
|||
|
||||
# create a TMP directory to copy all necessary files
|
||||
cd ./x64/Release
|
||||
zip $ZIP_PATH ./PrintDeps.exe
|
||||
|
||||
7z a "$ZIP_PATH" ./PrintDeps.exe
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ A few examples of problems this can catch include:
|
|||
|
||||
The following examples rely on the [`com.deque.html.axe-core/playwright`](https://mvnrepository.com/artifact/com.deque.html.axe-core/playwright) Maven package which adds support for running the [axe accessibility testing engine](https://www.deque.com/axe/) as part of your Playwright tests.
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
## Disclaimer
|
||||
|
||||
Automated accessibility tests can detect some common accessibility problems such as missing or invalid properties. But many accessibility problems can only be discovered through manual testing. We recommend using a combination of automated testing, manual accessibility assessments, and inclusive user testing.
|
||||
|
|
@ -135,7 +133,7 @@ If the element in question is used repeatedly in many pages, consider [using a t
|
|||
|
||||
### Disabling individual scan rules
|
||||
|
||||
If your application contains many different pre-existing violations of a specific rule, you can use [`AxeBuilder.disableRules()`](https://github.com/dequelabs/axe-core-maven-html/blob/develop/playwright/README.md#axebuilderdisablerulesliststring-rules) to temporarily disable individual rules until you're able to fix the issues.
|
||||
If your application contains many different preexisting violations of a specific rule, you can use [`AxeBuilder.disableRules()`](https://github.com/dequelabs/axe-core-maven-html/blob/develop/playwright/README.md#axebuilderdisablerulesliststring-rules) to temporarily disable individual rules until you're able to fix the issues.
|
||||
|
||||
You can find the rule IDs to pass to `disableRules()` in the `id` property of the violations you want to suppress. A [complete list of axe's rules](https://github.com/dequelabs/axe-core/blob/master/doc/rule-descriptions.md) can be found in `axe-core`'s documentation.
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ If the element in question is used repeatedly in many pages, consider [using a t
|
|||
|
||||
### Disabling individual scan rules
|
||||
|
||||
If your application contains many different pre-existing violations of a specific rule, you can use [`AxeBuilder.disableRules()`](https://github.com/dequelabs/axe-core-npm/blob/develop/packages/playwright/README.md#axebuilderdisablerulesrules-stringarray) to temporarily disable individual rules until you're able to fix the issues.
|
||||
If your application contains many different preexisting violations of a specific rule, you can use [`AxeBuilder.disableRules()`](https://github.com/dequelabs/axe-core-npm/blob/develop/packages/playwright/README.md#axebuilderdisablerulesrules-stringarray) to temporarily disable individual rules until you're able to fix the issues.
|
||||
|
||||
You can find the rule IDs to pass to `disableRules()` in the `id` property of the violations you want to suppress. A [complete list of axe's rules](https://github.com/dequelabs/axe-core/blob/master/doc/rule-descriptions.md) can be found in `axe-core`'s documentation.
|
||||
|
||||
|
|
@ -167,7 +167,7 @@ test('should not have any accessibility violations outside of rules with known i
|
|||
|
||||
### Using snapshots to allow specific known issues
|
||||
|
||||
If you would like to allow for a more granular set of known issues, you can use [Snapshots](./test-snapshots.md) to verify that a set of pre-existing violations has not changed. This approach avoids the downsides of using `AxeBuilder.exclude()` at the cost of slightly more complexity and fragility.
|
||||
If you would like to allow for a more granular set of known issues, you can use [Snapshots](./test-snapshots.md) to verify that a set of preexisting violations has not changed. This approach avoids the downsides of using `AxeBuilder.exclude()` at the cost of slightly more complexity and fragility.
|
||||
|
||||
Do not use a snapshot of the entire `accessibilityScanResults.violations` array. It contains implementation details of the elements in question, such as a snippet of their rendered HTML; if you include these in your snapshots, it will make your tests prone to breaking every time one of the components in question changes for an unrelated reason:
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@ All of that could be achieved via [APIRequestContext] methods.
|
|||
|
||||
The following examples rely on the [`Microsoft.Playwright.MSTest`](./test-runners.md) package which creates a Playwright and Page instance for each test.
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
## Writing API Test
|
||||
|
||||
[APIRequestContext] can send all kinds of HTTP(S) requests over network.
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ A few examples where it may come in handy:
|
|||
|
||||
All of that could be achieved via [APIRequestContext] methods.
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
## Writing API Test
|
||||
|
||||
[APIRequestContext] can send all kinds of HTTP(S) requests over network.
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ A few examples where it may come in handy:
|
|||
|
||||
All of that could be achieved via [APIRequestContext] methods.
|
||||
|
||||
<!-- TOC3 -->
|
||||
|
||||
## Writing API Test
|
||||
|
||||
[APIRequestContext] can send all kinds of HTTP(S) requests over network.
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@ All of that could be achieved via [APIRequestContext] methods.
|
|||
|
||||
The following examples rely on the [`pytest-playwright`](./test-runners.md) package which add Playwright fixtures to the Pytest test-runner.
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
## Writing API Test
|
||||
|
||||
[APIRequestContext] can send all kinds of HTTP(S) requests over network.
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ see [APIRequestContext].
|
|||
|
||||
Creates new instances of [APIRequestContext].
|
||||
|
||||
### option: APIRequest.newContext.clientCertificates = %%-context-option-clientCertificates-%%
|
||||
* since: 1.46
|
||||
|
||||
### option: APIRequest.newContext.useragent = %%-context-option-useragent-%%
|
||||
* since: v1.16
|
||||
|
||||
|
|
|
|||
|
|
@ -138,10 +138,13 @@ context cookies from the response. The method will automatically follow redirect
|
|||
### param: APIRequestContext.delete.url = %%-fetch-param-url-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.delete.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.delete.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.delete.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.delete.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.delete.params = %%-csharp-fetch-option-params-%%
|
||||
|
|
@ -180,6 +183,9 @@ context cookies from the response. The method will automatically follow redirect
|
|||
### option: APIRequestContext.delete.maxRedirects = %%-js-python-csharp-fetch-option-maxredirects-%%
|
||||
* since: v1.26
|
||||
|
||||
### option: APIRequestContext.delete.maxRetries = %%-js-python-csharp-fetch-option-maxretries-%%
|
||||
* since: v1.46
|
||||
|
||||
## async method: APIRequestContext.dispose
|
||||
* since: v1.16
|
||||
|
||||
|
|
@ -294,10 +300,13 @@ await Request.FetchAsync("https://example.com/api/uploadScript", new() { Method
|
|||
|
||||
Target URL or Request to get all parameters from.
|
||||
|
||||
### option: APIRequestContext.fetch.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.fetch.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.fetch.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.fetch.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.fetch.params = %%-csharp-fetch-option-params-%%
|
||||
|
|
@ -360,12 +369,24 @@ context cookies from the response. The method will automatically follow redirect
|
|||
Request parameters can be configured with `params` option, they will be serialized into the URL search parameters:
|
||||
|
||||
```js
|
||||
// Passing params as object
|
||||
await request.get('https://example.com/api/getText', {
|
||||
params: {
|
||||
'isbn': '1234',
|
||||
'page': 23,
|
||||
}
|
||||
});
|
||||
|
||||
// Passing params as URLSearchParams
|
||||
const searchParams = new URLSearchParams();
|
||||
searchParams.set('isbn', '1234');
|
||||
searchParams.append('page', 23);
|
||||
searchParams.append('page', 24);
|
||||
await request.get('https://example.com/api/getText', { params: searchParams });
|
||||
|
||||
// Passing params as string
|
||||
const queryString = 'isbn=1234&page=23&page=24';
|
||||
await request.get('https://example.com/api/getText', { params: queryString });
|
||||
```
|
||||
|
||||
```java
|
||||
|
|
@ -394,10 +415,13 @@ await request.GetAsync("https://example.com/api/getText", new() { Params = query
|
|||
### param: APIRequestContext.get.url = %%-fetch-param-url-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.get.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.get.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.get.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.get.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.get.params = %%-csharp-fetch-option-params-%%
|
||||
|
|
@ -450,10 +474,13 @@ context cookies from the response. The method will automatically follow redirect
|
|||
### param: APIRequestContext.head.url = %%-fetch-param-url-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.head.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.head.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.head.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.head.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.head.params = %%-csharp-fetch-option-params-%%
|
||||
|
|
@ -506,10 +533,13 @@ context cookies from the response. The method will automatically follow redirect
|
|||
### param: APIRequestContext.patch.url = %%-fetch-param-url-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.patch.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.patch.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.patch.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.patch.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.patch.params = %%-csharp-fetch-option-params-%%
|
||||
|
|
@ -683,10 +713,13 @@ await request.PostAsync("https://example.com/api/uploadScript", new() { Multipar
|
|||
### param: APIRequestContext.post.url = %%-fetch-param-url-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.post.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.post.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.post.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.post.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.post.params = %%-csharp-fetch-option-params-%%
|
||||
|
|
@ -739,10 +772,13 @@ context cookies from the response. The method will automatically follow redirect
|
|||
### param: APIRequestContext.put.url = %%-fetch-param-url-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.put.params = %%-js-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### param: APIRequestContext.put.params = %%-java-csharp-fetch-params-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: APIRequestContext.put.params = %%-js-python-fetch-option-params-%%
|
||||
### option: APIRequestContext.put.params = %%-python-fetch-option-params-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequestContext.put.params = %%-csharp-fetch-option-params-%%
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ An object with all the response HTTP headers associated with this response.
|
|||
- `name` <[string]> Name of the header.
|
||||
- `value` <[string]> Value of the header.
|
||||
|
||||
An array with all the request HTTP headers associated with this response. Header names are not lower-cased.
|
||||
An array with all the response HTTP headers associated with this response. Header names are not lower-cased.
|
||||
Headers with multiple entries, such as `Set-Cookie`, appear in the array multiple times.
|
||||
|
||||
## async method: APIResponse.json
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
# class: Browser
|
||||
* since: v1.8
|
||||
* extends: [EventEmitter]
|
||||
|
||||
A Browser is created via [`method: BrowserType.launch`]. An example of using a [Browser] to create a [Page]:
|
||||
|
||||
|
|
@ -256,6 +255,9 @@ await browser.CloseAsync();
|
|||
### option: Browser.newContext.proxy = %%-context-option-proxy-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Browser.newContext.clientCertificates = %%-context-option-clientCertificates-%%
|
||||
* since: 1.46
|
||||
|
||||
### option: Browser.newContext.storageState = %%-js-python-context-option-storage-state-%%
|
||||
* since: v1.8
|
||||
|
||||
|
|
@ -281,6 +283,9 @@ testing frameworks should explicitly create [`method: Browser.newContext`] follo
|
|||
### option: Browser.newPage.proxy = %%-context-option-proxy-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Browser.newPage.clientCertificates = %%-context-option-clientCertificates-%%
|
||||
* since: 1.46
|
||||
|
||||
### option: Browser.newPage.storageState = %%-js-python-context-option-storage-state-%%
|
||||
* since: v1.8
|
||||
|
||||
|
|
@ -290,6 +295,20 @@ testing frameworks should explicitly create [`method: Browser.newContext`] follo
|
|||
### option: Browser.newPage.storageStatePath = %%-csharp-java-context-option-storage-state-path-%%
|
||||
* since: v1.9
|
||||
|
||||
## async method: Browser.removeAllListeners
|
||||
* since: v1.47
|
||||
* langs: js
|
||||
|
||||
Removes all the listeners of the given type (or all registered listeners if no type given).
|
||||
Allows to wait for async listeners to complete or to ignore subsequent errors from these listeners.
|
||||
|
||||
### param: Browser.removeAllListeners.type
|
||||
* since: v1.47
|
||||
- `type` ?<[string]>
|
||||
|
||||
### option: Browser.removeAllListeners.behavior = %%-remove-all-listeners-options-behavior-%%
|
||||
* since: v1.47
|
||||
|
||||
## async method: Browser.startTracing
|
||||
* since: v1.11
|
||||
* langs: java, js, python
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
# class: BrowserContext
|
||||
* since: v1.8
|
||||
* extends: [EventEmitter]
|
||||
|
||||
BrowserContexts provide a way to operate multiple independent browser sessions.
|
||||
|
||||
If a page opens another page, e.g. with a `window.open` call, the popup will belong to the parent page's browser
|
||||
context.
|
||||
|
||||
Playwright allows creating "incognito" browser contexts with [`method: Browser.newContext`] method. "Incognito" browser
|
||||
Playwright allows creating isolated non-persistent browser contexts with [`method: Browser.newContext`] method. Non-persistent browser
|
||||
contexts don't write any browsing data to disk.
|
||||
|
||||
```js
|
||||
|
|
@ -1016,6 +1015,20 @@ Creates a new page in the browser context.
|
|||
|
||||
Returns all open pages in the context.
|
||||
|
||||
## async method: BrowserContext.removeAllListeners
|
||||
* since: v1.47
|
||||
* langs: js
|
||||
|
||||
Removes all the listeners of the given type (or all registered listeners if no type given).
|
||||
Allows to wait for async listeners to complete or to ignore subsequent errors from these listeners.
|
||||
|
||||
### param: BrowserContext.removeAllListeners.type
|
||||
* since: v1.47
|
||||
- `type` ?<[string]>
|
||||
|
||||
### option: BrowserContext.removeAllListeners.behavior = %%-remove-all-listeners-options-behavior-%%
|
||||
* since: v1.47
|
||||
|
||||
## property: BrowserContext.request
|
||||
* since: v1.16
|
||||
* langs:
|
||||
|
|
|
|||
|
|
@ -343,6 +343,9 @@ use a temporary directory instead.
|
|||
### option: BrowserType.launchPersistentContext.firefoxUserPrefs2 = %%-csharp-java-browser-option-firefoxuserprefs-%%
|
||||
* since: v1.40
|
||||
|
||||
### option: BrowserType.launchPersistentContext.clientCertificates = %%-context-option-clientCertificates-%%
|
||||
* since: 1.46
|
||||
|
||||
## async method: BrowserType.launchServer
|
||||
* since: v1.8
|
||||
* langs: js
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
# class: CDPSession
|
||||
* since: v1.8
|
||||
* extends: [EventEmitter]
|
||||
|
||||
The `CDPSession` instances are used to talk raw Chrome Devtools Protocol:
|
||||
* protocol methods can be called with `session.send` method.
|
||||
|
|
|
|||
|
|
@ -64,11 +64,26 @@ Install fake implementations for the following time-related functions:
|
|||
Fake timers are used to manually control the flow of time in tests. They allow you to advance time, fire timers, and control the behavior of time-dependent functions. See [`method: Clock.runFor`] and [`method: Clock.fastForward`] for more information.
|
||||
|
||||
### option: Clock.install.time
|
||||
* langs: js, java
|
||||
* since: v1.45
|
||||
- `time` <[long]|[string]|[Date]>
|
||||
|
||||
Time to initialize with, current system time by default.
|
||||
|
||||
### option: Clock.install.time
|
||||
* langs: python
|
||||
* since: v1.45
|
||||
- `time` <[float]|[string]|[Date]>
|
||||
|
||||
Time to initialize with, current system time by default.
|
||||
|
||||
### option: Clock.install.time
|
||||
* langs: csharp
|
||||
* since: v1.45
|
||||
- `time` <[string]|[Date]>
|
||||
|
||||
Time to initialize with, current system time by default.
|
||||
|
||||
## async method: Clock.runFor
|
||||
* since: v1.45
|
||||
|
||||
|
|
@ -147,9 +162,25 @@ await page.Clock.PauseAtAsync("2020-02-02");
|
|||
```
|
||||
|
||||
### param: Clock.pauseAt.time
|
||||
* langs: js, java
|
||||
* since: v1.45
|
||||
- `time` <[long]|[string]|[Date]>
|
||||
|
||||
Time to pause at.
|
||||
|
||||
### param: Clock.pauseAt.time
|
||||
* langs: python
|
||||
* since: v1.45
|
||||
- `time` <[float]|[string]|[Date]>
|
||||
|
||||
Time to pause at.
|
||||
|
||||
### param: Clock.pauseAt.time
|
||||
* langs: csharp
|
||||
* since: v1.45
|
||||
- `time` <[Date]|[string]>
|
||||
|
||||
Time to pause at.
|
||||
|
||||
## async method: Clock.resume
|
||||
* since: v1.45
|
||||
|
|
@ -195,9 +226,24 @@ await page.Clock.SetFixedTimeAsync("2020-02-02");
|
|||
```
|
||||
|
||||
### param: Clock.setFixedTime.time
|
||||
* langs: js, java
|
||||
* since: v1.45
|
||||
- `time` <[long]|[string]|[Date]>
|
||||
|
||||
Time to be set in milliseconds.
|
||||
|
||||
### param: Clock.setFixedTime.time
|
||||
* langs: python
|
||||
* since: v1.45
|
||||
- `time` <[float]|[string]|[Date]>
|
||||
|
||||
Time to be set.
|
||||
|
||||
### param: Clock.setFixedTime.time
|
||||
* langs: csharp
|
||||
* since: v1.45
|
||||
- `time` <[string]|[Date]>
|
||||
|
||||
Time to be set.
|
||||
|
||||
## async method: Clock.setSystemTime
|
||||
|
|
@ -238,5 +284,22 @@ await page.Clock.SetSystemTimeAsync("2020-02-02");
|
|||
```
|
||||
|
||||
### param: Clock.setSystemTime.time
|
||||
* langs: js, java
|
||||
* since: v1.45
|
||||
- `time` <[long]|[string]|[Date]>
|
||||
|
||||
Time to be set in milliseconds.
|
||||
|
||||
### param: Clock.setSystemTime.time
|
||||
* langs: python
|
||||
* since: v1.45
|
||||
- `time` <[float]|[string]|[Date]>
|
||||
|
||||
Time to be set.
|
||||
|
||||
### param: Clock.setSystemTime.time
|
||||
* langs: csharp
|
||||
* since: v1.45
|
||||
- `time` <[string]|[Date]>
|
||||
|
||||
Time to be set.
|
||||
|
|
|
|||
|
|
@ -164,7 +164,6 @@ This method checks the element by performing the following steps:
|
|||
1. Wait for [actionability](../actionability.md) checks on the element, unless [`option: force`] option is set.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now checked. If not, this method throws.
|
||||
|
||||
If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
|
|
@ -178,7 +177,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: ElementHandle.check.force = %%-input-force-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.check.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: ElementHandle.check.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.check.timeout = %%-input-timeout-%%
|
||||
|
|
@ -251,8 +250,6 @@ This method double clicks the element by performing the following steps:
|
|||
1. Wait for [actionability](../actionability.md) checks on the element, unless [`option: force`] option is set.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to double click in the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set. Note that
|
||||
if the first click of the `dblclick()` triggers a navigation event, this method will throw.
|
||||
|
||||
If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
|
||||
|
|
@ -278,7 +275,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: ElementHandle.dblclick.force = %%-input-force-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.dblclick.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: ElementHandle.dblclick.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.dblclick.timeout = %%-input-timeout-%%
|
||||
|
|
@ -537,7 +534,7 @@ Value to set for the `<input>`, `<textarea>` or `[contenteditable]` element.
|
|||
### option: ElementHandle.fill.force = %%-input-force-%%
|
||||
* since: v1.13
|
||||
|
||||
### option: ElementHandle.fill.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: ElementHandle.fill.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.fill.timeout = %%-input-timeout-%%
|
||||
|
|
@ -573,7 +570,6 @@ This method hovers over the element by performing the following steps:
|
|||
1. Wait for [actionability](../actionability.md) checks on the element, unless [`option: force`] option is set.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to hover over the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
|
||||
|
||||
If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
|
||||
|
|
@ -598,7 +594,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: ElementHandle.hover.trial = %%-input-trial-%%
|
||||
* since: v1.11
|
||||
|
||||
### option: ElementHandle.hover.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: ElementHandle.hover.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.28
|
||||
|
||||
## async method: ElementHandle.innerHTML
|
||||
|
|
@ -870,7 +866,7 @@ await handle.SelectOptionAsync(new[] {
|
|||
### option: ElementHandle.selectOption.force = %%-input-force-%%
|
||||
* since: v1.13
|
||||
|
||||
### option: ElementHandle.selectOption.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: ElementHandle.selectOption.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.selectOption.timeout = %%-input-timeout-%%
|
||||
|
|
@ -920,7 +916,6 @@ This method checks or unchecks an element by performing the following steps:
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now checked or unchecked. If not, this method throws.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
|
|
@ -932,7 +927,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: ElementHandle.setChecked.force = %%-input-force-%%
|
||||
* since: v1.15
|
||||
|
||||
### option: ElementHandle.setChecked.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: ElementHandle.setChecked.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.15
|
||||
|
||||
### option: ElementHandle.setChecked.position = %%-input-position-%%
|
||||
|
|
@ -961,7 +956,7 @@ This method expects [ElementHandle] to point to an
|
|||
### param: ElementHandle.setInputFiles.files = %%-input-files-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.setInputFiles.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: ElementHandle.setInputFiles.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.setInputFiles.timeout = %%-input-timeout-%%
|
||||
|
|
@ -978,7 +973,6 @@ This method taps the element by performing the following steps:
|
|||
1. Wait for [actionability](../actionability.md) checks on the element, unless [`option: force`] option is set.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.touchscreen`] to tap the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
|
||||
If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
|
||||
|
|
@ -998,7 +992,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: ElementHandle.tap.force = %%-input-force-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.tap.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: ElementHandle.tap.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.tap.timeout = %%-input-timeout-%%
|
||||
|
|
@ -1039,7 +1033,7 @@ A text to type into a focused element.
|
|||
|
||||
Time to wait between key presses in milliseconds. Defaults to 0.
|
||||
|
||||
### option: ElementHandle.type.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: ElementHandle.type.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.type.timeout = %%-input-timeout-%%
|
||||
|
|
@ -1058,7 +1052,6 @@ This method checks the element by performing the following steps:
|
|||
1. Wait for [actionability](../actionability.md) checks on the element, unless [`option: force`] option is set.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now unchecked. If not, this method throws.
|
||||
|
||||
If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
|
|
@ -1072,7 +1065,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: ElementHandle.uncheck.force = %%-input-force-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.uncheck.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: ElementHandle.uncheck.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: ElementHandle.uncheck.timeout = %%-input-timeout-%%
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ they are resolved relative to the current working directory. For empty array, cl
|
|||
### param: FileChooser.setFiles.files = %%-input-files-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: FileChooser.setFiles.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: FileChooser.setFiles.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: FileChooser.setFiles.timeout = %%-input-timeout-%%
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ Raw JavaScript content to be injected into frame.
|
|||
* since: v1.8
|
||||
- `type` <[string]>
|
||||
|
||||
Script type. Use 'module' in order to load a Javascript ES6 module. See
|
||||
Script type. Use 'module' in order to load a JavaScript ES6 module. See
|
||||
[script](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script) for more details.
|
||||
|
||||
## async method: Frame.addStyleTag
|
||||
|
|
@ -198,7 +198,6 @@ This method checks an element matching [`param: selector`] by performing the fol
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now checked. If not, this method throws.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
|
|
@ -210,7 +209,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Frame.check.force = %%-input-force-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.check.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.check.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.check.position = %%-input-position-%%
|
||||
|
|
@ -303,7 +302,6 @@ This method double clicks an element matching [`param: selector`] by performing
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to double click in the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set. Note that
|
||||
if the first click of the `dblclick()` triggers a navigation event, this method will throw.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
|
|
@ -328,7 +326,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Frame.dblclick.modifiers = %%-input-modifiers-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.dblclick.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.dblclick.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.dblclick.position = %%-input-position-%%
|
||||
|
|
@ -463,7 +461,7 @@ Optional event-specific initialization properties.
|
|||
### option: Frame.dragAndDrop.force = %%-input-force-%%
|
||||
* since: v1.13
|
||||
|
||||
### option: Frame.dragAndDrop.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.dragAndDrop.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.13
|
||||
|
||||
### option: Frame.dragAndDrop.strict = %%-input-strict-%%
|
||||
|
|
@ -856,7 +854,7 @@ Value to fill for the `<input>`, `<textarea>` or `[contenteditable]` element.
|
|||
### option: Frame.fill.force = %%-input-force-%%
|
||||
* since: v1.13
|
||||
|
||||
### option: Frame.fill.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.fill.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.fill.strict = %%-input-strict-%%
|
||||
|
|
@ -1130,7 +1128,6 @@ This method hovers over an element matching [`param: selector`] by performing th
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to hover over the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
[TimeoutError]. Passing zero timeout disables this.
|
||||
|
|
@ -1159,7 +1156,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Frame.hover.trial = %%-input-trial-%%
|
||||
* since: v1.11
|
||||
|
||||
### option: Frame.hover.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.hover.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.28
|
||||
|
||||
## async method: Frame.innerHTML
|
||||
|
|
@ -1546,7 +1543,7 @@ await frame.SelectOptionAsync("select#colors", new[] { "red", "green", "blue" })
|
|||
### option: Frame.selectOption.force = %%-input-force-%%
|
||||
* since: v1.13
|
||||
|
||||
### option: Frame.selectOption.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.selectOption.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.selectOption.strict = %%-input-strict-%%
|
||||
|
|
@ -1583,7 +1580,6 @@ This method checks or unchecks an element matching [`param: selector`] by perfor
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now checked or unchecked. If not, this method throws.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
|
|
@ -1598,7 +1594,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Frame.setChecked.force = %%-input-force-%%
|
||||
* since: v1.15
|
||||
|
||||
### option: Frame.setChecked.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.setChecked.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.15
|
||||
|
||||
### option: Frame.setChecked.position = %%-input-position-%%
|
||||
|
|
@ -1652,7 +1648,7 @@ This method expects [`param: selector`] to point to an
|
|||
### param: Frame.setInputFiles.files = %%-input-files-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.setInputFiles.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.setInputFiles.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.setInputFiles.strict = %%-input-strict-%%
|
||||
|
|
@ -1675,7 +1671,6 @@ This method taps an element matching [`param: selector`] by performing the follo
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.touchscreen`] to tap the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
[TimeoutError]. Passing zero timeout disables this.
|
||||
|
|
@ -1693,7 +1688,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Frame.tap.modifiers = %%-input-modifiers-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.tap.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.tap.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.tap.position = %%-input-position-%%
|
||||
|
|
@ -1762,7 +1757,7 @@ A text to type into a focused element.
|
|||
|
||||
Time to wait between key presses in milliseconds. Defaults to 0.
|
||||
|
||||
### option: Frame.type.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.type.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.type.strict = %%-input-strict-%%
|
||||
|
|
@ -1787,7 +1782,6 @@ This method checks an element matching [`param: selector`] by performing the fol
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now unchecked. If not, this method throws.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
|
|
@ -1799,7 +1793,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Frame.uncheck.force = %%-input-force-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.uncheck.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Frame.uncheck.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Frame.uncheck.position = %%-input-position-%%
|
||||
|
|
|
|||
|
|
@ -231,7 +231,6 @@ Performs the following steps:
|
|||
1. Wait for [actionability](../actionability.md) checks on the element, unless [`option: force`] option is set.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now checked. If not, this method throws.
|
||||
|
||||
If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
|
|
@ -267,7 +266,7 @@ await page.GetByRole(AriaRole.Checkbox).CheckAsync();
|
|||
### option: Locator.check.force = %%-input-force-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.check.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.check.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.check.timeout = %%-input-timeout-%%
|
||||
|
|
@ -317,7 +316,7 @@ await page.GetByRole(AriaRole.Textbox).ClearAsync();
|
|||
### option: Locator.clear.force = %%-input-force-%%
|
||||
* since: v1.28
|
||||
|
||||
### option: Locator.clear.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.clear.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.28
|
||||
|
||||
### option: Locator.clear.timeout = %%-input-timeout-%%
|
||||
|
|
@ -483,8 +482,6 @@ This method double clicks the element by performing the following steps:
|
|||
1. Wait for [actionability](../actionability.md) checks on the element, unless [`option: force`] option is set.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to double click in the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set. Note that
|
||||
if the first click of the `dblclick()` triggers a navigation event, this method will throw.
|
||||
|
||||
If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
|
||||
|
|
@ -510,7 +507,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Locator.dblclick.force = %%-input-force-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.dblclick.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.dblclick.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.dblclick.timeout = %%-input-timeout-%%
|
||||
|
|
@ -709,7 +706,7 @@ Locator of the element to drag to.
|
|||
### option: Locator.dragTo.force = %%-input-force-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: Locator.dragTo.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.dragTo.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.18
|
||||
|
||||
### option: Locator.dragTo.timeout = %%-input-timeout-%%
|
||||
|
|
@ -986,7 +983,7 @@ Value to set for the `<input>`, `<textarea>` or `[contenteditable]` element.
|
|||
### option: Locator.fill.force = %%-input-force-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.fill.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.fill.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.fill.timeout = %%-input-timeout-%%
|
||||
|
|
@ -1248,7 +1245,6 @@ This method hovers over the element by performing the following steps:
|
|||
1. Wait for [actionability](../actionability.md) checks on the element, unless [`option: force`] option is set.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to hover over the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
|
||||
|
||||
If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
|
||||
|
|
@ -1273,7 +1269,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Locator.hover.trial = %%-input-trial-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.hover.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.hover.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.28
|
||||
|
||||
## async method: Locator.innerHTML
|
||||
|
|
@ -1876,7 +1872,7 @@ String of characters to sequentially press into a focused element.
|
|||
|
||||
Time to wait between key presses in milliseconds. Defaults to 0.
|
||||
|
||||
### option: Locator.pressSequentially.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.pressSequentially.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.38
|
||||
|
||||
### option: Locator.pressSequentially.timeout = %%-input-timeout-%%
|
||||
|
|
@ -2059,7 +2055,7 @@ await element.SelectOptionAsync(new[] { "red", "green", "blue" });
|
|||
### option: Locator.selectOption.force = %%-input-force-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.selectOption.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.selectOption.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.selectOption.timeout = %%-input-timeout-%%
|
||||
|
|
@ -2133,7 +2129,6 @@ This method checks or unchecks an element by performing the following steps:
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now checked or unchecked. If not, this method throws.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
|
|
@ -2145,7 +2140,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Locator.setChecked.force = %%-input-force-%%
|
||||
* since: v1.15
|
||||
|
||||
### option: Locator.setChecked.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.setChecked.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.15
|
||||
|
||||
### option: Locator.setChecked.position = %%-input-position-%%
|
||||
|
|
@ -2286,7 +2281,7 @@ This method expects [Locator] to point to an
|
|||
### param: Locator.setInputFiles.files = %%-input-files-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.setInputFiles.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.setInputFiles.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.setInputFiles.timeout = %%-input-timeout-%%
|
||||
|
|
@ -2306,7 +2301,6 @@ This method taps the element by performing the following steps:
|
|||
1. Wait for [actionability](../actionability.md) checks on the element, unless [`option: force`] option is set.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.touchscreen`] to tap the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
|
||||
If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
|
||||
|
|
@ -2326,7 +2320,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Locator.tap.force = %%-input-force-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.tap.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.tap.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.tap.timeout = %%-input-timeout-%%
|
||||
|
|
@ -2376,7 +2370,7 @@ A text to type into a focused element.
|
|||
|
||||
Time to wait between key presses in milliseconds. Defaults to 0.
|
||||
|
||||
### option: Locator.type.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.type.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.type.timeout = %%-input-timeout-%%
|
||||
|
|
@ -2420,7 +2414,6 @@ This method unchecks the element by performing the following steps:
|
|||
1. Wait for [actionability](../actionability.md) checks on the element, unless [`option: force`] option is set.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now unchecked. If not, this method throws.
|
||||
|
||||
If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
|
|
@ -2434,7 +2427,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Locator.uncheck.force = %%-input-force-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.uncheck.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.uncheck.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.14
|
||||
|
||||
### option: Locator.uncheck.timeout = %%-input-timeout-%%
|
||||
|
|
|
|||
|
|
@ -68,10 +68,14 @@ Shortcut for [`method: Mouse.move`], [`method: Mouse.down`], [`method: Mouse.up`
|
|||
* since: v1.8
|
||||
- `x` <[float]>
|
||||
|
||||
X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
|
||||
### param: Mouse.click.y
|
||||
* since: v1.8
|
||||
- `y` <[float]>
|
||||
|
||||
Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
|
||||
### option: Mouse.click.button = %%-input-button-%%
|
||||
* since: v1.8
|
||||
|
||||
|
|
@ -93,10 +97,14 @@ Shortcut for [`method: Mouse.move`], [`method: Mouse.down`], [`method: Mouse.up`
|
|||
* since: v1.8
|
||||
- `x` <[float]>
|
||||
|
||||
X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
|
||||
### param: Mouse.dblclick.y
|
||||
* since: v1.8
|
||||
- `y` <[float]>
|
||||
|
||||
Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
|
||||
### option: Mouse.dblclick.button = %%-input-button-%%
|
||||
* since: v1.8
|
||||
|
||||
|
|
@ -123,10 +131,14 @@ Dispatches a `mousemove` event.
|
|||
* since: v1.8
|
||||
- `x` <[float]>
|
||||
|
||||
X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
|
||||
### param: Mouse.move.y
|
||||
* since: v1.8
|
||||
- `y` <[float]>
|
||||
|
||||
Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
|
||||
### option: Mouse.move.steps
|
||||
* since: v1.8
|
||||
- `steps` <[int]>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
# class: Page
|
||||
* since: v1.8
|
||||
* extends: [EventEmitter]
|
||||
|
||||
Page provides methods to interact with a single tab in a [Browser], or an
|
||||
[extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. One [Browser]
|
||||
|
|
@ -688,7 +687,7 @@ Raw JavaScript content to be injected into frame.
|
|||
* since: v1.8
|
||||
- `type` <[string]>
|
||||
|
||||
Script type. Use 'module' in order to load a Javascript ES6 module. See
|
||||
Script type. Use 'module' in order to load a JavaScript ES6 module. See
|
||||
[script](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script) for more details.
|
||||
|
||||
## async method: Page.addStyleTag
|
||||
|
|
@ -735,7 +734,6 @@ This method checks an element matching [`param: selector`] by performing the fol
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now checked. If not, this method throws.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
|
|
@ -747,7 +745,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Page.check.force = %%-input-force-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.check.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.check.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.check.position = %%-input-position-%%
|
||||
|
|
@ -879,8 +877,6 @@ This method double clicks an element matching [`param: selector`] by performing
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to double click in the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set. Note that
|
||||
if the first click of the `dblclick()` triggers a navigation event, this method will throw.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
[TimeoutError]. Passing zero timeout disables this.
|
||||
|
|
@ -904,7 +900,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Page.dblclick.modifiers = %%-input-modifiers-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.dblclick.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.dblclick.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.dblclick.position = %%-input-position-%%
|
||||
|
|
@ -1092,7 +1088,7 @@ await Page.DragAndDropAsync("#source", "#target", new()
|
|||
### option: Page.dragAndDrop.force = %%-input-force-%%
|
||||
* since: v1.13
|
||||
|
||||
### option: Page.dragAndDrop.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.dragAndDrop.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.13
|
||||
|
||||
### option: Page.dragAndDrop.strict = %%-input-strict-%%
|
||||
|
|
@ -2050,7 +2046,7 @@ Value to fill for the `<input>`, `<textarea>` or `[contenteditable]` element.
|
|||
### option: Page.fill.force = %%-input-force-%%
|
||||
* since: v1.13
|
||||
|
||||
### option: Page.fill.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.fill.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.fill.strict = %%-input-strict-%%
|
||||
|
|
@ -2315,7 +2311,7 @@ Attribute name to get the value for.
|
|||
- returns: <[null]|[Response]>
|
||||
|
||||
Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
|
||||
last redirect. If can not go back, returns `null`.
|
||||
last redirect. If cannot go back, returns `null`.
|
||||
|
||||
Navigate to the previous page in history.
|
||||
|
||||
|
|
@ -2333,7 +2329,7 @@ Navigate to the previous page in history.
|
|||
- returns: <[null]|[Response]>
|
||||
|
||||
Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
|
||||
last redirect. If can not go forward, returns `null`.
|
||||
last redirect. If cannot go forward, returns `null`.
|
||||
|
||||
Navigate to the next page in history.
|
||||
|
||||
|
|
@ -2411,7 +2407,6 @@ This method hovers over an element matching [`param: selector`] by performing th
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to hover over the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
[TimeoutError]. Passing zero timeout disables this.
|
||||
|
|
@ -2440,7 +2435,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Page.hover.trial = %%-input-trial-%%
|
||||
* since: v1.11
|
||||
|
||||
### option: Page.hover.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.hover.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.28
|
||||
|
||||
## async method: Page.innerHTML
|
||||
|
|
@ -3344,6 +3339,32 @@ Specifies the maximum number of times this handler should be called. Unlimited b
|
|||
|
||||
By default, after calling the handler Playwright will wait until the overlay becomes hidden, and only then Playwright will continue with the action/assertion that triggered the handler. This option allows to opt-out of this behavior, so that overlay can stay visible after the handler has run.
|
||||
|
||||
## async method: Page.removeAllListeners
|
||||
* since: v1.47
|
||||
* langs: js
|
||||
|
||||
Removes all the listeners of the given type (or all registered listeners if no type given).
|
||||
Allows to wait for async listeners to complete or to ignore subsequent errors from these listeners.
|
||||
|
||||
**Usage**
|
||||
|
||||
```js
|
||||
page.on('request', async request => {
|
||||
const response = await request.response();
|
||||
const body = await response.body();
|
||||
console.log(body.byteLength);
|
||||
});
|
||||
await page.goto('https://playwright.dev', { waitUntil: 'domcontentloaded' });
|
||||
// Waits for all the reported 'request' events to resolve.
|
||||
await page.removeAllListeners('request', { behavior: 'wait' });
|
||||
```
|
||||
|
||||
### param: Page.removeAllListeners.type
|
||||
* since: v1.47
|
||||
- `type` ?<[string]>
|
||||
|
||||
### option: Page.removeAllListeners.behavior = %%-remove-all-listeners-options-behavior-%%
|
||||
* since: v1.47
|
||||
|
||||
## async method: Page.removeLocatorHandler
|
||||
* since: v1.44
|
||||
|
|
@ -3598,7 +3619,7 @@ A glob pattern, regular expression or predicate to match the request URL. Only r
|
|||
* since: v1.32
|
||||
- `updateMode` <[HarMode]<"full"|"minimal">>
|
||||
|
||||
When set to `minimal`, only record information necessary for routing from HAR. This omits sizes, timing, page, cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to `full`.
|
||||
When set to `minimal`, only record information necessary for routing from HAR. This omits sizes, timing, page, cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to `minimal`.
|
||||
|
||||
### option: Page.routeFromHAR.updateContent
|
||||
* since: v1.32
|
||||
|
|
@ -3705,7 +3726,7 @@ await page.SelectOptionAsync("select#colors", new[] { "red", "green", "blue" });
|
|||
### option: Page.selectOption.force = %%-input-force-%%
|
||||
* since: v1.13
|
||||
|
||||
### option: Page.selectOption.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.selectOption.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.selectOption.strict = %%-input-strict-%%
|
||||
|
|
@ -3742,7 +3763,6 @@ This method checks or unchecks an element matching [`param: selector`] by perfor
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now checked or unchecked. If not, this method throws.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
|
|
@ -3757,7 +3777,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Page.setChecked.force = %%-input-force-%%
|
||||
* since: v1.15
|
||||
|
||||
### option: Page.setChecked.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.setChecked.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.15
|
||||
|
||||
### option: Page.setChecked.position = %%-input-position-%%
|
||||
|
|
@ -3865,7 +3885,7 @@ This method expects [`param: selector`] to point to an
|
|||
### param: Page.setInputFiles.files = %%-input-files-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.setInputFiles.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.setInputFiles.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.setInputFiles.strict = %%-input-strict-%%
|
||||
|
|
@ -3949,7 +3969,6 @@ This method taps an element matching [`param: selector`] by performing the follo
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.touchscreen`] to tap the center of the element, or the specified [`option: position`].
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
[TimeoutError]. Passing zero timeout disables this.
|
||||
|
|
@ -3967,7 +3986,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Page.tap.modifiers = %%-input-modifiers-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.tap.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.tap.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.tap.position = %%-input-position-%%
|
||||
|
|
@ -4040,7 +4059,7 @@ A text to type into a focused element.
|
|||
|
||||
Time to wait between key presses in milliseconds. Defaults to 0.
|
||||
|
||||
### option: Page.type.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.type.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.type.strict = %%-input-strict-%%
|
||||
|
|
@ -4065,7 +4084,6 @@ This method unchecks an element matching [`param: selector`] by performing the f
|
|||
set. If the element is detached during the checks, the whole action is retried.
|
||||
1. Scroll the element into view if needed.
|
||||
1. Use [`property: Page.mouse`] to click in the center of the element.
|
||||
1. Wait for initiated navigations to either succeed or fail, unless [`option: noWaitAfter`] option is set.
|
||||
1. Ensure that the element is now unchecked. If not, this method throws.
|
||||
|
||||
When all steps combined have not finished during the specified [`option: timeout`], this method throws a
|
||||
|
|
@ -4077,7 +4095,7 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Page.uncheck.force = %%-input-force-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.uncheck.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Page.uncheck.noWaitAfter = %%-input-no-wait-after-removed-%%
|
||||
* since: v1.8
|
||||
|
||||
### option: Page.uncheck.position = %%-input-position-%%
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ namespace PlaywrightTests;
|
|||
public class ExampleTests : PageTest
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task NavigatetoLoginPage()
|
||||
public async Task NavigateToLoginPage()
|
||||
{
|
||||
await Page.GetByRole(AriaRole.Button, new() { Name = "Sign In" }).ClickAsync();
|
||||
await Expect(Page).ToHaveURLAsync(new Regex(".*/login"));
|
||||
|
|
@ -83,7 +83,7 @@ assertThat(page).not().hasURL("error");
|
|||
```
|
||||
|
||||
```csharp
|
||||
await Expect(Page).Not.ToHaveURL("error");
|
||||
await Expect(Page).Not.ToHaveURLAsync("error");
|
||||
```
|
||||
|
||||
## async method: PageAssertions.NotToHaveTitle
|
||||
|
|
@ -271,7 +271,7 @@ expect(page).to_have_title(re.compile(r".*checkout"))
|
|||
```
|
||||
|
||||
```csharp
|
||||
await Expect(Page).ToHaveTitle("Playwright");
|
||||
await Expect(Page).ToHaveTitleAsync("Playwright");
|
||||
```
|
||||
|
||||
### param: PageAssertions.toHaveTitle.titleOrRegExp
|
||||
|
|
@ -320,7 +320,7 @@ expect(page).to_have_url(re.compile(".*checkout"))
|
|||
```
|
||||
|
||||
```csharp
|
||||
await Expect(Page).ToHaveURL(new Regex(".*checkout"));
|
||||
await Expect(Page).ToHaveURLAsync(new Regex(".*checkout"));
|
||||
```
|
||||
|
||||
### param: PageAssertions.toHaveURL.urlOrRegExp
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ Headers with multiple entries, such as `Set-Cookie`, appear in the array multipl
|
|||
* since: v1.15
|
||||
- returns: <[null]|[string]>
|
||||
|
||||
Returns the value of the header matching the name. The name is case insensitive.
|
||||
Returns the value of the header matching the name. The name is case-insensitive.
|
||||
|
||||
### param: Request.headerValue.name
|
||||
* since: v1.15
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ Defaults to `20`. Pass `0` to not follow redirects.
|
|||
* since: v1.46
|
||||
- `maxRetries` <[int]>
|
||||
|
||||
Maximum number of times socket errors should be retried. Currently only `ECONNRESET` error is retried. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries.
|
||||
Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries.
|
||||
|
||||
## method: RequestOptions.setMethod
|
||||
* since: v1.18
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ Headers with multiple entries, such as `Set-Cookie`, appear in the array multipl
|
|||
* since: v1.15
|
||||
- returns: <[null]|[string]>
|
||||
|
||||
Returns the value of the header matching the name. The name is case insensitive. If multiple headers have
|
||||
Returns the value of the header matching the name. The name is case-insensitive. If multiple headers have
|
||||
the same name (except `set-cookie`), they are returned as a list separated by `, `. For `set-cookie`, the `\n` separator is used. If no headers are found, `null` is returned.
|
||||
|
||||
### param: Response.headerValue.name
|
||||
|
|
@ -72,7 +72,7 @@ Name of the header.
|
|||
* since: v1.15
|
||||
- returns: <[Array]<[string]>>
|
||||
|
||||
Returns all values of the headers matching the name, for example `set-cookie`. The name is case insensitive.
|
||||
Returns all values of the headers matching the name, for example `set-cookie`. The name is case-insensitive.
|
||||
|
||||
### param: Response.headerValues.name
|
||||
* since: v1.15
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ Optional error code. Defaults to `failed`, could be one of the following:
|
|||
- alias-java: resume
|
||||
- alias-python: continue_
|
||||
|
||||
Continues route's request with optional overrides.
|
||||
Sends route's request to the network with optional overrides.
|
||||
|
||||
**Usage**
|
||||
|
||||
|
|
@ -104,6 +104,8 @@ await page.RouteAsync("**/*", async route =>
|
|||
|
||||
Note that any overrides such as [`option: url`] or [`option: headers`] only apply to the request being routed. If this request results in a redirect, overrides will not be applied to the new redirected request. If you want to propagate a header through redirects, use the combination of [`method: Route.fetch`] and [`method: Route.fulfill`] instead.
|
||||
|
||||
[`method: Route.continue`] will immediately send the request to the network, other matching handlers won't be invoked. Use [`method: Route.fallback`] If you want next matching handler in the chain to be invoked.
|
||||
|
||||
### option: Route.continue.url
|
||||
* since: v1.8
|
||||
- `url` <[string]>
|
||||
|
|
@ -146,13 +148,15 @@ If set changes the request HTTP headers. Header values will be converted to a st
|
|||
## async method: Route.fallback
|
||||
* since: v1.23
|
||||
|
||||
Continues route's request with optional overrides. The method is similar to [`method: Route.continue`] with the difference that other matching handlers will be invoked before sending the request.
|
||||
|
||||
**Usage**
|
||||
|
||||
When several routes match the given pattern, they run in the order opposite to their registration.
|
||||
That way the last registered route can always override all the previous ones. In the example below,
|
||||
request will be handled by the bottom-most handler first, then it'll fall back to the previous one and
|
||||
in the end will be aborted by the first registered route.
|
||||
|
||||
**Usage**
|
||||
|
||||
```js
|
||||
await page.route('**/*', async route => {
|
||||
// Runs last.
|
||||
|
|
@ -386,6 +390,8 @@ await page.RouteAsync("**/*", async route =>
|
|||
});
|
||||
```
|
||||
|
||||
Use [`method: Route.continue`] to immediately send the request to the network, other matching handlers won't be invoked in that case.
|
||||
|
||||
### option: Route.fallback.url
|
||||
* since: v1.23
|
||||
- `url` <[string]>
|
||||
|
|
@ -503,6 +509,12 @@ If set changes the request URL. New URL must have same protocol as original one.
|
|||
Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is exceeded.
|
||||
Defaults to `20`. Pass `0` to not follow redirects.
|
||||
|
||||
### option: Route.fetch.maxRetries
|
||||
* since: v1.46
|
||||
- `maxRetries` <[int]>
|
||||
|
||||
Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries.
|
||||
|
||||
### option: Route.fetch.timeout
|
||||
* since: v1.33
|
||||
- `timeout` <[float]>
|
||||
|
|
|
|||
|
|
@ -17,26 +17,10 @@ Dispatches a `touchstart` and `touchend` event with a single touch at the positi
|
|||
* since: v1.8
|
||||
- `x` <[float]>
|
||||
|
||||
X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
|
||||
### param: Touchscreen.tap.y
|
||||
* since: v1.8
|
||||
- `y` <[float]>
|
||||
|
||||
## async method: Touchscreen.touch
|
||||
* since: v1.46
|
||||
|
||||
Synthesizes a touch event.
|
||||
|
||||
### param: Touchscreen.touch.type
|
||||
* since: v1.46
|
||||
- `type` <[TouchType]<"touchstart"|"touchend"|"touchmove"|"touchcancel">>
|
||||
|
||||
Type of the touch event.
|
||||
|
||||
### param: Touchscreen.touch.touches
|
||||
* since: v1.46
|
||||
- `touchPoints` <[Array]<[Object]>>
|
||||
- `x` <[float]> x coordinate of the event in CSS pixels.
|
||||
- `y` <[float]> y coordinate of the event in CSS pixels.
|
||||
- `id` ?<[int]> Identifier used to track the touch point between events, must be unique within an event. Optional.
|
||||
|
||||
List of touch points for this event. `id` is a unique identifier of a touch point that helps identify it between touch events for the duration of its movement around the surface.
|
||||
Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
|
|
|
|||
|
|
@ -62,12 +62,19 @@ Maximum time in milliseconds. Defaults to `0` - no timeout. The default value ca
|
|||
[`method: Page.setDefaultTimeout`] methods.
|
||||
|
||||
## input-no-wait-after
|
||||
* deprecated: This option will default to `true` in the future.
|
||||
- `noWaitAfter` <[boolean]>
|
||||
|
||||
Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating
|
||||
to inaccessible pages. Defaults to `false`.
|
||||
|
||||
## input-no-wait-after-removed
|
||||
* deprecated: This option has no effect.
|
||||
- `noWaitAfter` <[boolean]>
|
||||
|
||||
This option has no effect.
|
||||
|
||||
## input-force
|
||||
- `force` <[boolean]>
|
||||
|
||||
|
|
@ -349,8 +356,14 @@ Emulates consistent window screen size available inside web page via `window.scr
|
|||
|
||||
Target URL.
|
||||
|
||||
## js-python-fetch-option-params
|
||||
* langs: js, python
|
||||
## js-fetch-option-params
|
||||
* langs: js
|
||||
- `params` <[Object]<[string], [string]|[number]|[boolean]>|[URLSearchParams]|[string]>
|
||||
|
||||
Query parameters to be sent with the URL.
|
||||
|
||||
## python-fetch-option-params
|
||||
* langs: python
|
||||
- `params` <[Object]<[string], [string]|[float]|[boolean]>>
|
||||
|
||||
Query parameters to be sent with the URL.
|
||||
|
|
@ -462,7 +475,7 @@ Defaults to `20`. Pass `0` to not follow redirects.
|
|||
* langs: js, python, csharp
|
||||
- `maxRetries` <[int]>
|
||||
|
||||
Maximum number of times socket errors should be retried. Currently only `ECONNRESET` error is retried. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries.
|
||||
Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries.
|
||||
|
||||
## evaluate-expression
|
||||
- `expression` <[string]>
|
||||
|
|
@ -514,6 +527,31 @@ Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `no_
|
|||
|
||||
Does not enforce fixed viewport, allows resizing window in the headed mode.
|
||||
|
||||
## context-option-clientCertificates
|
||||
- `clientCertificates` <[Array]<[Object]>>
|
||||
- `origin` <[string]> Exact origin that the certificate is valid for. Origin includes `https` protocol, a hostname and optionally a port.
|
||||
- `certPath` ?<[path]> Path to the file with the certificate in PEM format.
|
||||
- `cert` ?<[Buffer]> Direct value of the certificate in PEM format.
|
||||
- `keyPath` ?<[path]> Path to the file with the private key in PEM format.
|
||||
- `key` ?<[Buffer]> Direct value of the private key in PEM format.
|
||||
- `pfxPath` ?<[path]> Path to the PFX or PKCS12 encoded private key and certificate chain.
|
||||
- `pfx` ?<[Buffer]> Direct value of the PFX or PKCS12 encoded private key and certificate chain.
|
||||
- `passphrase` ?<[string]> Passphrase for the private key (PEM or PFX).
|
||||
|
||||
TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
|
||||
**Details**
|
||||
|
||||
An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`, a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally, `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
|
||||
:::note
|
||||
Using Client Certificates in combination with Proxy Servers is not supported.
|
||||
:::
|
||||
|
||||
:::note
|
||||
When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it work by replacing `localhost` with `local.playwright`.
|
||||
:::
|
||||
|
||||
## context-option-useragent
|
||||
- `userAgent` <[string]>
|
||||
|
||||
|
|
@ -731,12 +769,6 @@ Actual picture of each page will be scaled down if necessary to fit the specifie
|
|||
|
||||
Network proxy settings to use with this context. Defaults to none.
|
||||
|
||||
:::note
|
||||
For Chromium on Windows the browser needs to be launched with the global proxy for this option to work. If all
|
||||
contexts override the proxy, global proxy will be never used and can be any string, for example
|
||||
`launch({ proxy: { server: 'http://per-context' } })`.
|
||||
:::
|
||||
|
||||
## context-option-strict
|
||||
- `strictSelectors` <[boolean]>
|
||||
|
||||
|
|
@ -752,6 +784,16 @@ Whether to allow sites to register Service workers. Defaults to `'allow'`.
|
|||
* `'allow'`: [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) can be registered.
|
||||
* `'block'`: Playwright will block all registration of Service Workers.
|
||||
|
||||
## remove-all-listeners-options-behavior
|
||||
* langs: js
|
||||
* since: v1.47
|
||||
- `behavior` <[RemoveAllListenersBehavior]<"wait"|"ignoreErrors"|"default">>
|
||||
|
||||
Specifies whether to wait for already running listeners and what to do if they throw errors:
|
||||
* `'default'` - do not wait for current listener calls (if any) to finish, if the listener throws, it may result in unhandled error
|
||||
* `'wait'` - wait for current listener calls (if any) to finish
|
||||
* `'ignoreErrors'` - do not wait for current listener calls (if any) to finish, all errors thrown by the listeners after removal are silently caught
|
||||
|
||||
## unroute-all-options-behavior
|
||||
* langs: js, csharp, python
|
||||
* since: v1.41
|
||||
|
|
@ -762,6 +804,7 @@ Specifies whether to wait for already running handlers and what to do if they th
|
|||
* `'wait'` - wait for current handler calls (if any) to finish
|
||||
* `'ignoreErrors'` - do not wait for current handler calls (if any) to finish, all errors thrown by the handlers after unrouting are silently caught
|
||||
|
||||
|
||||
## select-options-values
|
||||
* langs: java, js, csharp
|
||||
- `values` <[null]|[string]|[ElementHandle]|[Array]<[string]>|[Object]|[Array]<[ElementHandle]>|[Array]<[Object]>>
|
||||
|
|
|
|||
|
|
@ -47,8 +47,9 @@ Create `tests/auth.setup.ts` that will prepare authenticated browser state for a
|
|||
|
||||
```js title="tests/auth.setup.ts"
|
||||
import { test as setup, expect } from '@playwright/test';
|
||||
import path from 'path';
|
||||
|
||||
const authFile = 'playwright/.auth/user.json';
|
||||
const authFile = path.join(__dirname, '../playwright/.auth/user.json');
|
||||
|
||||
setup('authenticate', async ({ page }) => {
|
||||
// Perform authentication steps. Replace these actions with your own.
|
||||
|
|
@ -113,6 +114,8 @@ test('test', async ({ page }) => {
|
|||
});
|
||||
```
|
||||
|
||||
Note that you need to delete the stored state when it expires. If you don't need to keep the state between test runs, write the browser state under [`property: TestProject.outputDir`], which is automatically cleaned up before every test run.
|
||||
|
||||
### Authenticating in UI mode
|
||||
* langs: js
|
||||
|
||||
|
|
@ -263,7 +266,7 @@ existing authentication state instead.
|
|||
Playwright provides a way to reuse the signed-in state in the tests. That way you can log
|
||||
in only once and then skip the log in step for all of the tests.
|
||||
|
||||
Web apps use cookie-based or token-based authentication, where authenticated state is stored as [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) or in [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage). Playwright provides [`method: BrowserContext.storageState`] method that can be used to retrieve storage state from authenticated contexts and then create new contexts with pre-populated state.
|
||||
Web apps use cookie-based or token-based authentication, where authenticated state is stored as [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) or in [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage). Playwright provides [`method: BrowserContext.storageState`] method that can be used to retrieve storage state from authenticated contexts and then create new contexts with prepopulated state.
|
||||
|
||||
Cookies and local storage state can be used across different browsers. They depend on your application's authentication model: some apps might require both cookies and local storage.
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ You can also reuse the signed-in state in the tests with [setup project](./auth.
|
|||
|
||||
### Avoid testing third-party dependencies
|
||||
|
||||
Only test what you control. Don't try to test links to external sites or third party servers that you do not control. Not only is it time consuming and can slow down your tests but also you can not control the content of the page you are linking to, or if there are cookie banners or overlay pages or anything else that might cause your test to fail.
|
||||
Only test what you control. Don't try to test links to external sites or third party servers that you do not control. Not only is it time consuming and can slow down your tests but also you cannot control the content of the page you are linking to, or if there are cookie banners or overlay pages or anything else that might cause your test to fail.
|
||||
|
||||
Instead, use the [Playwright Network API](/network.md#handle-requests) and guarantee the response needed.
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ npx playwright show-report
|
|||
|
||||
<img width="1516" alt="Playwrights HTML report" loading="lazy" src="https://user-images.githubusercontent.com/13063165/212279022-d929d4c0-2271-486a-a75f-166ac231d25f.png" />
|
||||
|
||||
Traces can be opened by clicking on the icon next to the test or by opening each of the test reports and scrolling down to the traces section.
|
||||
Traces can be opened by clicking on the icon next to the test file name or by opening each of the test reports and scrolling down to the traces section.
|
||||
|
||||
<img width="1516" alt="Screenshot 2023-01-13 at 09 58 34" loading="lazy" src="https://user-images.githubusercontent.com/13063165/212279699-c9eb134f-4f4e-4f19-805c-37596d3272a6.png" />
|
||||
|
||||
|
|
@ -214,8 +214,8 @@ Playwright comes with a range of tooling to help you write tests.
|
|||
- The [VS Code extension](./getting-started-vscode.md) gives you a great developer experience when writing, running, and debugging tests.
|
||||
- The [test generator](./codegen.md) can generate tests and pick locators for you.
|
||||
- The [trace viewer](./trace-viewer.md) gives you a full trace of your tests as a local PWA that can easily be shared. With the trace viewer you can view the timeline, inspect DOM snapshots for each action, view network requests and more.
|
||||
- The [UI Mode](./test-ui-mode) let's you explore, run and debug tests with a time travel experience complete with watch mode. All test files are loaded into the testing sidebar where you can expand each file and describe block to individually run, view, watch and debug each test.
|
||||
- [Typescript](./test-typescript) in Playwright works out of the box and gives you better IDE integrations. Your IDE will show you everything you can do and highlight when you do something wrong. No TypeScript experience is needed and it is not necessary for your code to be in TypeScript, all you need to do is create your tests with a `.ts` extension.
|
||||
- The [UI Mode](./test-ui-mode) lets you explore, run and debug tests with a time travel experience complete with watch mode. All test files are loaded into the testing sidebar where you can expand each file and describe block to individually run, view, watch and debug each test.
|
||||
- [TypeScript](./test-typescript) in Playwright works out of the box and gives you better IDE integrations. Your IDE will show you everything you can do and highlight when you do something wrong. No TypeScript experience is needed and it is not necessary for your code to be in TypeScript, all you need to do is create your tests with a `.ts` extension.
|
||||
|
||||
### Test across all browsers
|
||||
|
||||
|
|
@ -261,11 +261,11 @@ npx playwright --version
|
|||
|
||||
Setup CI/CD and run your tests frequently. The more often you run your tests the better. Ideally you should run your tests on each commit and pull request. Playwright comes with a [GitHub actions workflow](/ci-intro.md) so that tests will run on CI for you with no setup required. Playwright can also be setup on the [CI environment](/ci.md) of your choice.
|
||||
|
||||
Use Linux when running your tests on CI as it is cheaper. Developers can use whatever environment when running locally but use linux on CI.
|
||||
Use Linux when running your tests on CI as it is cheaper. Developers can use whatever environment when running locally but use linux on CI. Consider setting up [Sharding](./test-sharding.md) to make CI faster.
|
||||
|
||||
### Lint your tests
|
||||
|
||||
Linting the tests helps catching errors early. Use [`@typescript-eslint/no-floating-promises`](https://typescript-eslint.io/rules/no-floating-promises/) [ESLint](https://eslint.org) rule to make sure there are no missing awaits before the asynchronous calls to the Playwright API.
|
||||
We recommend TypeScript and linting with ESLint for your tests to catch errors early. Use [`@typescript-eslint/no-floating-promises`](https://typescript-eslint.io/rules/no-floating-promises/) [ESLint](https://eslint.org) rule to make sure there are no missing awaits before the asynchronous calls to the Playwright API. On your CI you can run `tsc --noEmit` to ensure that functions are called with the right signature.
|
||||
|
||||
### Use parallelism and sharding
|
||||
|
||||
|
|
|
|||
|
|
@ -230,13 +230,13 @@ Running 1 test using 1 worker
|
|||
✓ [firefox] › example.spec.ts:3:1 › basic test (2s)
|
||||
```
|
||||
|
||||
The VS Code test runner runs your tests on the default browser of Chrome. To run on other/multiple browsers click the play button's dropdown from the testing sidebar and choose another profile or modify the default profile by clicking **Select Default Profile** and select the browsers you wish to run your tests on.
|
||||
With the VS Code extension you can run your tests on different browsers by checking the checkbox next to the browser name in the Playwright sidebar. These names are defined in your Playwright config file under the projects section. The default config when installing Playwright gives you 3 projects, Chromium, Firefox and WebKit. The first project is selected by default.
|
||||
|
||||
<img width="1464" alt="selecting browsers" src="https://user-images.githubusercontent.com/13063165/221136731-9d4bc18f-38a4-4adb-997b-5b98c98aec7f.png" />
|
||||

|
||||
|
||||
Choose a specific profile, various profiles or all profiles to run tests on.
|
||||
To run tests on multiple projects(browsers), select each project by checking the checkboxes next to the project name.
|
||||
|
||||
<img width="1536" alt="choosing default profiles" src="https://user-images.githubusercontent.com/13063165/221669537-e5df8672-f50d-4ff1-96f9-141cd67e12f8.png" />
|
||||

|
||||
|
||||
### Run tests on different browsers
|
||||
* langs: python
|
||||
|
|
@ -461,7 +461,7 @@ Playwright's Firefox version matches the recent [Firefox Stable](https://www.moz
|
|||
|
||||
### WebKit
|
||||
|
||||
Playwright's WebKit version matches the recent WebKit trunk build, before it is used in Apple Safari and other WebKit-based browsers. This gives a lot of lead time to react on the potential browser update issues. Playwright doesn't work with the branded version of Safari since it relies on patches. Instead you can test against the recent WebKit build.
|
||||
Playwright's WebKit is derived from the latest WebKit main branch sources, often before these updates are incorporated into Apple Safari and other WebKit-based browsers. This gives a lot of lead time to react on the potential browser update issues. Playwright doesn't work with the branded version of Safari since it relies on patches. Instead, you can test using the most recent WebKit build. Note that availability of certain features, which depend heavily on the underlying platform, may vary between operating systems.
|
||||
|
||||
## Install behind a firewall or a proxy
|
||||
|
||||
|
|
@ -763,7 +763,7 @@ pwsh bin/Debug/netX/playwright.ps1 install
|
|||
Playwright downloads Chromium, WebKit and Firefox browsers into the OS-specific cache folders:
|
||||
|
||||
- `%USERPROFILE%\AppData\Local\ms-playwright` on Windows
|
||||
- `~/Library/Caches/ms-playwright` on MacOS
|
||||
- `~/Library/Caches/ms-playwright` on macOS
|
||||
- `~/.cache/ms-playwright` on Linux
|
||||
|
||||
These browsers will take a few hundred megabytes of disk space when installed:
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
---
|
||||
id: ci-intro
|
||||
title: "CI GitHub Actions"
|
||||
title: "Setting up CI"
|
||||
---
|
||||
|
||||
## Introduction
|
||||
* langs: js
|
||||
|
||||
Playwright tests can be run on any CI provider. In this section we will cover running tests on GitHub using GitHub actions. If you would like to see how to configure other CI providers check out our detailed [doc on Continuous Integration](./ci.md).
|
||||
|
||||
When [installing Playwright](./intro.md) using the [VS Code extension](./getting-started-vscode.md) or with `npm init playwright@latest` you are given the option to add a [GitHub Actions](https://docs.github.com/en/actions) workflow. This creates a `playwright.yml` file inside a `.github/workflows` folder containing everything you need so that your tests run on each push and pull request into the main/master branch.
|
||||
Playwright tests can be run on any CI provider. This guide covers one way of running tests on GitHub using GitHub actions. If you would like to learn more, or how to configure other CI providers, check out our detailed [doc on Continuous Integration](./ci.md).
|
||||
|
||||
#### You will learn
|
||||
* langs: js
|
||||
|
||||
- [How to run tests on push/pull_request](/ci-intro.md#on-pushpull_request)
|
||||
- [How to set up GitHub Actions](/ci-intro.md#setting-up-github-actions)
|
||||
- [How to view test logs](/ci-intro.md#viewing-test-logs)
|
||||
- [How to view the HTML report](/ci-intro.md#viewing-the-html-report)
|
||||
- [How to view the trace](/ci-intro.md#viewing-the-trace)
|
||||
|
|
@ -25,22 +23,18 @@ When [installing Playwright](./intro.md) using the [VS Code extension](./getting
|
|||
|
||||
Playwright tests can be ran on any CI provider. In this section we will cover running tests on GitHub using GitHub actions. If you would like to see how to configure other CI providers check out our detailed doc on Continuous Integration.
|
||||
|
||||
To add a [GitHub Actions](https://docs.github.com/en/actions) file first create `.github/workflows` folder and inside it add a `playwright.yml` file containing the example code below so that your tests will run on each push and pull request for the main/master branch.
|
||||
|
||||
#### You will learn
|
||||
* langs: python, java, csharp
|
||||
|
||||
- [How to run tests on push/pull_request](/ci-intro.md#on-pushpull_request)
|
||||
- [How to set up GitHub Actions](/ci-intro.md#setting-up-github-actions)
|
||||
- [How to view test logs](/ci-intro.md#viewing-test-logs)
|
||||
- [How to view the trace](/ci-intro.md#viewing-the-trace)
|
||||
|
||||
|
||||
## Setting up GitHub Actions
|
||||
|
||||
### On push/pull_request
|
||||
* langs: js
|
||||
|
||||
Tests will run on push or pull request on branches main/master. The [workflow](https://docs.github.com/en/actions/using-workflows/about-workflows) will install all dependencies, install Playwright and then run the tests. It will also create the HTML report.
|
||||
When [installing Playwright](./intro.md) using the [VS Code extension](./getting-started-vscode.md) or with `npm init playwright@latest` you are given the option to add a [GitHub Actions](https://docs.github.com/en/actions) workflow. This creates a `playwright.yml` file inside a `.github/workflows` folder containing everything you need so that your tests run on each push and pull request into the main/master branch. Here's how that file looks:
|
||||
|
||||
```yml js title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
|
|
@ -57,7 +51,7 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: lts/*
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Install Playwright Browsers
|
||||
|
|
@ -72,10 +66,21 @@ jobs:
|
|||
retention-days: 30
|
||||
```
|
||||
|
||||
### On push/pull_request
|
||||
The workflow performs these steps:
|
||||
|
||||
1. Clone your repository
|
||||
2. Install Node.js
|
||||
3. Install NPM Dependencies
|
||||
4. Install Playwright Browsers
|
||||
5. Run Playwright tests
|
||||
6. Upload HTML report to the GitHub UI
|
||||
|
||||
To learn more about this, see ["Understanding GitHub Actions"](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions).
|
||||
|
||||
## Setting up GitHub Actions
|
||||
* langs: python, java, csharp
|
||||
|
||||
Tests will run on push or pull request on branches main/master. The [workflow](https://docs.github.com/en/actions/using-workflows/about-workflows) will install all dependencies, install Playwright and then run the tests.
|
||||
To add a [GitHub Actions](https://docs.github.com/en/actions) file first create `.github/workflows` folder and inside it add a `playwright.yml` file containing the example code below so that your tests will run on each push and pull request for the main/master branch.
|
||||
|
||||
```yml python title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
|
|
@ -128,7 +133,7 @@ jobs:
|
|||
java-version: '17'
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install Playwright
|
||||
- name: Ensure browsers are installed
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps"
|
||||
- name: Run tests
|
||||
run: mvn test
|
||||
|
|
@ -151,238 +156,23 @@ jobs:
|
|||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- run: dotnet build
|
||||
- name: Build & Install
|
||||
run: dotnet build
|
||||
- name: Ensure browsers are installed
|
||||
run: pwsh bin/Debug/net8.0/playwright.ps1 install --with-deps
|
||||
- name: Run your tests
|
||||
run: dotnet test
|
||||
```
|
||||
|
||||
### On push/pull_request (sharded)
|
||||
* langs: js
|
||||
To learn more about this, see ["Understanding GitHub Actions"](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions).
|
||||
|
||||
GitHub Actions supports [sharding tests between multiple jobs](https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs). Check out our [sharding doc](./test-sharding) to learn more about sharding and to see a [GitHub actions example](./test-sharding.md#github-actions-example) of how to configure a job to run your tests on multiple machines as well as how to merge the HTML reports.
|
||||
|
||||
### Via Containers
|
||||
|
||||
GitHub Actions support [running jobs in a container](https://docs.github.com/en/actions/using-jobs/running-jobs-in-a-container) by using the [`jobs.<job_id>.container`](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idcontainer) option. This is useful to not pollute the host environment with dependencies and to have a consistent environment for e.g. screenshots/visual regression testing across different operating systems.
|
||||
|
||||
```yml js title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
playwright:
|
||||
name: 'Playwright Tests'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright:v%%VERSION%%-jammy
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Run your tests
|
||||
run: npx playwright test
|
||||
env:
|
||||
HOME: /root
|
||||
```
|
||||
|
||||
```yml python title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
playwright:
|
||||
name: 'Playwright Tests'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright/python:v%%VERSION%%-jammy
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r local-requirements.txt
|
||||
pip install -e .
|
||||
- name: Run your tests
|
||||
run: pytest
|
||||
env:
|
||||
HOME: /root
|
||||
```
|
||||
|
||||
```yml java title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
playwright:
|
||||
name: 'Playwright Tests'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright/java:v%%VERSION%%-jammy
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Run tests
|
||||
run: mvn test
|
||||
env:
|
||||
HOME: /root
|
||||
```
|
||||
|
||||
```yml csharp title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
playwright:
|
||||
name: 'Playwright Tests'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-jammy
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- run: dotnet build
|
||||
- name: Run your tests
|
||||
run: dotnet test
|
||||
env:
|
||||
HOME: /root
|
||||
```
|
||||
|
||||
### On deployment
|
||||
|
||||
This will start the tests after a [GitHub Deployment](https://developer.github.com/v3/repos/deployments/) went into the `success` state.
|
||||
Services like Vercel use this pattern so you can run your end-to-end tests on their deployed environment.
|
||||
|
||||
```yml js title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
deployment_status:
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.deployment_status.state == 'success'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Install Playwright
|
||||
run: npx playwright install --with-deps
|
||||
- name: Run Playwright tests
|
||||
run: npx playwright test
|
||||
env:
|
||||
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
|
||||
```
|
||||
|
||||
```yml python title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
deployment_status:
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.deployment_status.state == 'success'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Ensure browsers are installed
|
||||
run: python -m playwright install --with-deps
|
||||
- name: Run tests
|
||||
run: pytest
|
||||
env:
|
||||
# This might depend on your test-runner
|
||||
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
|
||||
```
|
||||
|
||||
```yml java title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
deployment_status:
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.deployment_status.state == 'success'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install Playwright
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps"
|
||||
- name: Run tests
|
||||
run: mvn test
|
||||
env:
|
||||
# This might depend on your test-runner
|
||||
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
|
||||
```
|
||||
|
||||
```yml csharp title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
deployment_status:
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.deployment_status.state == 'success'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- run: dotnet build
|
||||
- name: Ensure browsers are installed
|
||||
run: pwsh bin/Debug/net8.0/playwright.ps1 install --with-deps
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
env:
|
||||
# This might depend on your test-runner
|
||||
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
|
||||
```
|
||||
Looking at the list of steps in `jobs.test.steps`, you can see that the workflow performs these steps:
|
||||
|
||||
1. Clone your repository
|
||||
2. Install language dependencies
|
||||
3. Install project dependencies and build
|
||||
4. Install Playwright Browsers
|
||||
5. Run tests
|
||||
|
||||
## Create a Repo and Push to GitHub
|
||||
|
||||
|
|
@ -532,4 +322,5 @@ This step will not work for pull requests created from a forked repository becau
|
|||
- [Learn how to perform Actions](./input.md)
|
||||
- [Learn how to write Assertions](./test-assertions.md)
|
||||
- [Learn more about the Trace Viewer](/trace-viewer.md)
|
||||
- [Learn more about running tests on other CI providers](/ci.md)
|
||||
- [Learn more ways of running tests on GitHub Actions](/ci.md)
|
||||
- [Learn more about running tests on other CI providers](/ci.md#github-actions) // TODO: is this link correct?
|
||||
440
docs/src/ci.md
440
docs/src/ci.md
|
|
@ -59,14 +59,402 @@ export default defineConfig({
|
|||
});
|
||||
```
|
||||
|
||||
|
||||
## CI configurations
|
||||
|
||||
The [Command line tools](./browsers#install-system-dependencies) can be used to install all operating system dependencies on GitHub Actions.
|
||||
The [Command line tools](./browsers#install-system-dependencies) can be used to install all operating system dependencies in CI.
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
Check out our [GitHub Actions](ci-intro.md) guide for more information on how to run your tests on GitHub.
|
||||
#### On push/pull_request
|
||||
* langs: js
|
||||
|
||||
Tests will run on push or pull request on branches main/master. The [workflow](https://docs.github.com/en/actions/using-workflows/about-workflows) will install all dependencies, install Playwright and then run the tests. It will also create the HTML report.
|
||||
|
||||
```yml js title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
- name: Run Playwright tests
|
||||
run: npx playwright test
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
```
|
||||
|
||||
#### On push/pull_request
|
||||
* langs: python, java, csharp
|
||||
|
||||
Tests will run on push or pull request on branches main/master. The [workflow](https://docs.github.com/en/actions/using-workflows/about-workflows) will install all dependencies, install Playwright and then run the tests.
|
||||
|
||||
```yml python title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Ensure browsers are installed
|
||||
run: python -m playwright install --with-deps
|
||||
- name: Run your tests
|
||||
run: pytest --tracing=retain-on-failure
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: playwright-traces
|
||||
path: test-results/
|
||||
```
|
||||
|
||||
```yml java title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Ensure browsers are installed
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps"
|
||||
- name: Run tests
|
||||
run: mvn test
|
||||
```
|
||||
|
||||
```yml csharp title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- name: Build & Install
|
||||
run: dotnet build
|
||||
- name: Ensure browsers are installed
|
||||
run: pwsh bin/Debug/net8.0/playwright.ps1 install --with-deps
|
||||
- name: Run your tests
|
||||
run: dotnet test
|
||||
```
|
||||
|
||||
#### On push/pull_request (sharded)
|
||||
* langs: js
|
||||
|
||||
GitHub Actions supports [sharding tests between multiple jobs](https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs). Check out our [sharding doc](./test-sharding) to learn more about sharding and to see a [GitHub actions example](./test-sharding.md#github-actions-example) of how to configure a job to run your tests on multiple machines as well as how to merge the HTML reports.
|
||||
|
||||
#### Via Containers
|
||||
|
||||
GitHub Actions support [running jobs in a container](https://docs.github.com/en/actions/using-jobs/running-jobs-in-a-container) by using the [`jobs.<job_id>.container`](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idcontainer) option. This is useful to not pollute the host environment with dependencies and to have a consistent environment for e.g. screenshots/visual regression testing across different operating systems.
|
||||
|
||||
```yml js title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
playwright:
|
||||
name: 'Playwright Tests'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright:v%%VERSION%%-jammy
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Run your tests
|
||||
run: npx playwright test
|
||||
env:
|
||||
HOME: /root
|
||||
```
|
||||
|
||||
```yml python title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
playwright:
|
||||
name: 'Playwright Tests'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright/python:v%%VERSION%%-jammy
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r local-requirements.txt
|
||||
pip install -e .
|
||||
- name: Run your tests
|
||||
run: pytest
|
||||
env:
|
||||
HOME: /root
|
||||
```
|
||||
|
||||
```yml java title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
playwright:
|
||||
name: 'Playwright Tests'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright/java:v%%VERSION%%-jammy
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Run tests
|
||||
run: mvn test
|
||||
env:
|
||||
HOME: /root
|
||||
```
|
||||
|
||||
```yml csharp title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
playwright:
|
||||
name: 'Playwright Tests'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-jammy
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- run: dotnet build
|
||||
- name: Run your tests
|
||||
run: dotnet test
|
||||
env:
|
||||
HOME: /root
|
||||
```
|
||||
|
||||
#### On deployment
|
||||
|
||||
This will start the tests after a [GitHub Deployment](https://developer.github.com/v3/repos/deployments/) went into the `success` state.
|
||||
Services like Vercel use this pattern so you can run your end-to-end tests on their deployed environment.
|
||||
|
||||
```yml js title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
deployment_status:
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.deployment_status.state == 'success'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Install Playwright
|
||||
run: npx playwright install --with-deps
|
||||
- name: Run Playwright tests
|
||||
run: npx playwright test
|
||||
env:
|
||||
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
|
||||
```
|
||||
|
||||
```yml python title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
deployment_status:
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.deployment_status.state == 'success'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Ensure browsers are installed
|
||||
run: python -m playwright install --with-deps
|
||||
- name: Run tests
|
||||
run: pytest
|
||||
env:
|
||||
# This might depend on your test-runner
|
||||
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
|
||||
```
|
||||
|
||||
```yml java title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
deployment_status:
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.deployment_status.state == 'success'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install Playwright
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps"
|
||||
- name: Run tests
|
||||
run: mvn test
|
||||
env:
|
||||
# This might depend on your test-runner
|
||||
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
|
||||
```
|
||||
|
||||
```yml csharp title=".github/workflows/playwright.yml"
|
||||
name: Playwright Tests
|
||||
on:
|
||||
deployment_status:
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.deployment_status.state == 'success'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- run: dotnet build
|
||||
- name: Ensure browsers are installed
|
||||
run: pwsh bin/Debug/net8.0/playwright.ps1 install --with-deps
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
env:
|
||||
# This might depend on your test-runner
|
||||
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
|
||||
```
|
||||
|
||||
#### Fail-Fast
|
||||
* langs: js
|
||||
|
||||
Large test suites can take very long to execute. By executing a preliminary test run with the `--only-changed` flag, you can run test files that are likely to fail first.
|
||||
This will give you a faster feedback loop and slightly lower CI consumption while working on Pull Requests.
|
||||
To detect test files affected by your changeset, `--only-changed` analyses your suites' dependency graph. This is a heuristic and might miss tests, so it's important that you always run the full test suite after the preliminary test run.
|
||||
|
||||
```yml js title=".github/workflows/playwright.yml" {20-23}
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Force a non-shallow checkout, so that we can reference $GITHUB_BASE_REF.
|
||||
# See https://github.com/actions/checkout for more details.
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
- name: Run changed Playwright tests
|
||||
run: npx playwright test --only-changed=$GITHUB_BASE_REF
|
||||
if: github.event_name == 'pull_request'
|
||||
- name: Run Playwright tests
|
||||
run: npx playwright test
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
|
|
@ -296,7 +684,7 @@ trigger:
|
|||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
container: mcr.microsoft.com/playwright:v%%VERSION%%-jammy
|
||||
container: mcr.microsoft.com/playwright:v%%VERSION%%-noble
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
|
|
@ -318,7 +706,7 @@ trigger:
|
|||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
container: mcr.microsoft.com/playwright/python:v%%VERSION%%-jammy
|
||||
container: mcr.microsoft.com/playwright/python:v%%VERSION%%-noble
|
||||
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
|
|
@ -340,7 +728,7 @@ trigger:
|
|||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
container: mcr.microsoft.com/playwright/java:v%%VERSION%%-jammy
|
||||
container: mcr.microsoft.com/playwright/java:v%%VERSION%%-noble
|
||||
|
||||
steps:
|
||||
- task: JavaToolInstaller@0
|
||||
|
|
@ -361,7 +749,7 @@ trigger:
|
|||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
container: mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-jammy
|
||||
container: mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-noble
|
||||
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
|
|
@ -384,28 +772,28 @@ Running Playwright on CircleCI is very similar to running on GitHub Actions. In
|
|||
executors:
|
||||
pw-jammy-development:
|
||||
docker:
|
||||
- image: mcr.microsoft.com/playwright:v%%VERSION%%-jammy
|
||||
- image: mcr.microsoft.com/playwright:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
```yml python
|
||||
executors:
|
||||
pw-jammy-development:
|
||||
docker:
|
||||
- image: mcr.microsoft.com/playwright/python:v%%VERSION%%-jammy
|
||||
- image: mcr.microsoft.com/playwright/python:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
```yml java
|
||||
executors:
|
||||
pw-jammy-development:
|
||||
docker:
|
||||
- image: mcr.microsoft.com/playwright/java:v%%VERSION%%-jammy
|
||||
- image: mcr.microsoft.com/playwright/java:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
```yml csharp
|
||||
executors:
|
||||
pw-jammy-development:
|
||||
docker:
|
||||
- image: mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-jammy
|
||||
- image: mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
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.
|
||||
|
|
@ -430,7 +818,7 @@ to run tests on Jenkins.
|
|||
|
||||
```groovy js
|
||||
pipeline {
|
||||
agent { docker { image 'mcr.microsoft.com/playwright:v%%VERSION%%-jammy' } }
|
||||
agent { docker { image 'mcr.microsoft.com/playwright:v%%VERSION%%-noble' } }
|
||||
stages {
|
||||
stage('e2e-tests') {
|
||||
steps {
|
||||
|
|
@ -444,7 +832,7 @@ pipeline {
|
|||
|
||||
```groovy python
|
||||
pipeline {
|
||||
agent { docker { image 'mcr.microsoft.com/playwright/python:v%%VERSION%%-jammy' } }
|
||||
agent { docker { image 'mcr.microsoft.com/playwright/python:v%%VERSION%%-noble' } }
|
||||
stages {
|
||||
stage('e2e-tests') {
|
||||
steps {
|
||||
|
|
@ -458,7 +846,7 @@ pipeline {
|
|||
|
||||
```groovy java
|
||||
pipeline {
|
||||
agent { docker { image 'mcr.microsoft.com/playwright/java:v%%VERSION%%-jammy' } }
|
||||
agent { docker { image 'mcr.microsoft.com/playwright/java:v%%VERSION%%-noble' } }
|
||||
stages {
|
||||
stage('e2e-tests') {
|
||||
steps {
|
||||
|
|
@ -472,7 +860,7 @@ pipeline {
|
|||
|
||||
```groovy csharp
|
||||
pipeline {
|
||||
agent { docker { image 'mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-jammy' } }
|
||||
agent { docker { image 'mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-noble' } }
|
||||
stages {
|
||||
stage('e2e-tests') {
|
||||
steps {
|
||||
|
|
@ -489,19 +877,19 @@ pipeline {
|
|||
Bitbucket Pipelines can use public [Docker images as build environments](https://confluence.atlassian.com/bitbucket/use-docker-images-as-build-environments-792298897.html). To run Playwright tests on Bitbucket, use our public Docker image ([see Dockerfile](./docker.md)).
|
||||
|
||||
```yml js
|
||||
image: mcr.microsoft.com/playwright:v%%VERSION%%-jammy
|
||||
image: mcr.microsoft.com/playwright:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
```yml python
|
||||
image: mcr.microsoft.com/playwright/python:v%%VERSION%%-jammy
|
||||
image: mcr.microsoft.com/playwright/python:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
```yml java
|
||||
image: mcr.microsoft.com/playwright/java:v%%VERSION%%-jammy
|
||||
image: mcr.microsoft.com/playwright/java:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
```yml csharp
|
||||
image: mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-jammy
|
||||
image: mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
### GitLab CI
|
||||
|
|
@ -514,7 +902,7 @@ stages:
|
|||
|
||||
tests:
|
||||
stage: test
|
||||
image: mcr.microsoft.com/playwright:v%%VERSION%%-jammy
|
||||
image: mcr.microsoft.com/playwright:v%%VERSION%%-noble
|
||||
script:
|
||||
...
|
||||
```
|
||||
|
|
@ -525,7 +913,7 @@ stages:
|
|||
|
||||
tests:
|
||||
stage: test
|
||||
image: mcr.microsoft.com/playwright/python:v%%VERSION%%-jammy
|
||||
image: mcr.microsoft.com/playwright/python:v%%VERSION%%-noble
|
||||
script:
|
||||
...
|
||||
```
|
||||
|
|
@ -536,7 +924,7 @@ stages:
|
|||
|
||||
tests:
|
||||
stage: test
|
||||
image: mcr.microsoft.com/playwright/java:v%%VERSION%%-jammy
|
||||
image: mcr.microsoft.com/playwright/java:v%%VERSION%%-noble
|
||||
script:
|
||||
...
|
||||
```
|
||||
|
|
@ -547,7 +935,7 @@ stages:
|
|||
|
||||
tests:
|
||||
stage: test
|
||||
image: mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-jammy
|
||||
image: mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-noble
|
||||
script:
|
||||
...
|
||||
```
|
||||
|
|
@ -563,7 +951,7 @@ stages:
|
|||
|
||||
tests:
|
||||
stage: test
|
||||
image: mcr.microsoft.com/playwright:v%%VERSION%%-jammy
|
||||
image: mcr.microsoft.com/playwright:v%%VERSION%%-noble
|
||||
parallel: 7
|
||||
script:
|
||||
- npm ci
|
||||
|
|
@ -578,7 +966,7 @@ stages:
|
|||
|
||||
tests:
|
||||
stage: test
|
||||
image: mcr.microsoft.com/playwright:v%%VERSION%%-jammy
|
||||
image: mcr.microsoft.com/playwright:v%%VERSION%%-noble
|
||||
parallel:
|
||||
matrix:
|
||||
- PROJECT: ['chromium', 'webkit']
|
||||
|
|
@ -594,7 +982,7 @@ To run Playwright tests on Google Cloud Build, use our public Docker image ([see
|
|||
|
||||
```yml
|
||||
steps:
|
||||
- name: mcr.microsoft.com/playwright:v%%VERSION%%-jammy
|
||||
- name: mcr.microsoft.com/playwright:v%%VERSION%%-noble
|
||||
script:
|
||||
...
|
||||
env:
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ The recommended approach is to use `setFixedTime` to set the time to a specific
|
|||
- `requestIdleCallback`
|
||||
- `cancelIdleCallback`
|
||||
- `performance`
|
||||
- `Event.timeStamp`
|
||||
:::
|
||||
|
||||
## Test with predefined time
|
||||
|
|
@ -43,7 +44,7 @@ That way the time flows naturally, but `Date.now` always returns a fixed value.
|
|||
<script>
|
||||
const renderTime = () => {
|
||||
document.getElementById('current-time').textContent =
|
||||
new Date().toLocaleTimeString();
|
||||
new Date().toLocaleString();
|
||||
};
|
||||
setInterval(renderTime, 1000);
|
||||
</script>
|
||||
|
|
@ -69,7 +70,7 @@ In this case, you can install the clock and fast forward to the time of interest
|
|||
<script>
|
||||
const renderTime = () => {
|
||||
document.getElementById('current-time').textContent =
|
||||
new Date().toLocaleTimeString();
|
||||
new Date().toLocaleString();
|
||||
};
|
||||
setInterval(renderTime, 1000);
|
||||
</script>
|
||||
|
|
@ -152,9 +153,9 @@ assertThat(locator).hasText("2/2/2024, 10:30:00 AM");
|
|||
```csharp
|
||||
// Initialize clock with some time before the test time and let the page load naturally.
|
||||
// `Date.now` will progress as the timers fire.
|
||||
await Page.Clock.InstallAsync(new
|
||||
await Page.Clock.InstallAsync(new()
|
||||
{
|
||||
Time = new DateTime(2024, 2, 2, 8, 0, 0)
|
||||
TimeDate = new DateTime(2024, 2, 2, 8, 0, 0)
|
||||
});
|
||||
await Page.GotoAsync("http://localhost:3333");
|
||||
|
||||
|
|
@ -176,6 +177,26 @@ Inactivity monitoring is a common feature in web applications that logs out user
|
|||
Testing this feature can be tricky because you need to wait for a long time to see the effect.
|
||||
With the help of the clock, you can speed up time and test this feature quickly.
|
||||
|
||||
```html
|
||||
<div id="remaining-time" data-testid="remaining-time"></div>
|
||||
<script>
|
||||
const endTime = Date.now() + 5 * 60_000;
|
||||
const renderTime = () => {
|
||||
const diffInSeconds = Math.round((endTime - Date.now()) / 1000);
|
||||
if (diffInSeconds <= 0) {
|
||||
document.getElementById('remaining-time').textContent =
|
||||
'You have been logged out due to inactivity.';
|
||||
} else {
|
||||
document.getElementById('remaining-time').textContent =
|
||||
`You will be logged out in ${diffInSeconds} seconds.`;
|
||||
}
|
||||
setTimeout(renderTime, 1000);
|
||||
};
|
||||
renderTime();
|
||||
</script>
|
||||
<button type="button">Interaction</button>
|
||||
```
|
||||
|
||||
```js
|
||||
// Initial time does not matter for the test, so we can pick current time.
|
||||
await page.clock.install();
|
||||
|
|
@ -186,7 +207,7 @@ await page.getByRole('button').click();
|
|||
// Fast forward time 5 minutes as if the user did not do anything.
|
||||
// Fast forward is like closing the laptop lid and opening it after 5 minutes.
|
||||
// All the timers due will fire once immediately, as in the real browser.
|
||||
await page.clock.fastForward('5:00');
|
||||
await page.clock.fastForward('05:00');
|
||||
|
||||
// Check that the user was logged out automatically.
|
||||
await expect(page.getByText('You have been logged out due to inactivity.')).toBeVisible();
|
||||
|
|
@ -202,7 +223,7 @@ await page.get_by_role("button").click()
|
|||
# Fast forward time 5 minutes as if the user did not do anything.
|
||||
# Fast forward is like closing the laptop lid and opening it after 5 minutes.
|
||||
# All the timers due will fire once immediately, as in the real browser.
|
||||
await page.clock.fast_forward("5:00")
|
||||
await page.clock.fast_forward("05:00")
|
||||
|
||||
# Check that the user was logged out automatically.
|
||||
await expect(page.getByText("You have been logged out due to inactivity.")).toBeVisible()
|
||||
|
|
@ -218,7 +239,7 @@ page.get_by_role("button").click()
|
|||
# Fast forward time 5 minutes as if the user did not do anything.
|
||||
# Fast forward is like closing the laptop lid and opening it after 5 minutes.
|
||||
# All the timers due will fire once immediately, as in the real browser.
|
||||
page.clock.fast_forward("5:00")
|
||||
page.clock.fast_forward("05:00")
|
||||
|
||||
# Check that the user was logged out automatically.
|
||||
expect(page.get_by_text("You have been logged out due to inactivity.")).to_be_visible()
|
||||
|
|
@ -236,7 +257,7 @@ locator.click();
|
|||
// Fast forward time 5 minutes as if the user did not do anything.
|
||||
// Fast forward is like closing the laptop lid and opening it after 5 minutes.
|
||||
// All the timers due will fire once immediately, as in the real browser.
|
||||
page.clock().fastForward("5:00");
|
||||
page.clock().fastForward("05:00");
|
||||
|
||||
// Check that the user was logged out automatically.
|
||||
assertThat(page.getByText("You have been logged out due to inactivity.")).isVisible();
|
||||
|
|
@ -253,7 +274,7 @@ await page.GetByRole("button").ClickAsync();
|
|||
// Fast forward time 5 minutes as if the user did not do anything.
|
||||
// Fast forward is like closing the laptop lid and opening it after 5 minutes.
|
||||
// All the timers due will fire once immediately, as in the real browser.
|
||||
await Page.Clock.FastForwardAsync("5:00");
|
||||
await Page.Clock.FastForwardAsync("05:00");
|
||||
|
||||
// Check that the user was logged out automatically.
|
||||
await Expect(Page.GetByText("You have been logged out due to inactivity.")).ToBeVisibleAsync();
|
||||
|
|
@ -269,7 +290,7 @@ animation frames in the process to achieve a fine-grained control over the passa
|
|||
<script>
|
||||
const renderTime = () => {
|
||||
document.getElementById('current-time').textContent =
|
||||
new Date().toLocaleTimeString();
|
||||
new Date().toLocaleString();
|
||||
};
|
||||
setInterval(renderTime, 1000);
|
||||
</script>
|
||||
|
|
@ -350,9 +371,9 @@ assertThat(locator).hasText("2/2/2024, 10:00:02 AM");
|
|||
|
||||
```csharp
|
||||
// Initialize clock with a specific time, let the page load naturally.
|
||||
await Page.Clock.InstallAsync(new
|
||||
await Page.Clock.InstallAsync(new()
|
||||
{
|
||||
Time = new DateTime(2024, 2, 2, 8, 0, 0, DateTimeKind.Pst)
|
||||
TimeDate = new DateTime(2024, 2, 2, 8, 0, 0, DateTimeKind.Pst)
|
||||
});
|
||||
await page.GotoAsync("http://localhost:3333");
|
||||
var locator = page.GetByTestId("current-time");
|
||||
|
|
|
|||
|
|
@ -125,14 +125,14 @@ With the test generator you can record:
|
|||
|
||||
When you have finished interacting with the page, press the **record** button to stop the recording and use the **copy** button to copy the generated code to your editor.
|
||||
|
||||
Use the **clear** button to clear the code to start recording again. Once finished close the Playwright inspector window or stop the terminal command.
|
||||
Use the **clear** button to clear the code to start recording again. Once finished, close the Playwright inspector window or stop the terminal command.
|
||||
|
||||
### Generating locators
|
||||
You can generate [locators](/locators.md) with the test generator.
|
||||
|
||||
* Press the `'Record'` button to stop the recording and the `'Pick Locator'` button will appear.
|
||||
* Click on the `'Pick Locator'` button and then hover over elements in the browser window to see the locator highlighted underneath each element.
|
||||
* To choose a locator click on the element you would like to locate and the code for that locator will appear in the field next to the Pick Locator button.
|
||||
* To choose a locator, click on the element you would like to locate and the code for that locator will appear in the field next to the Pick Locator button.
|
||||
* You can then edit the locator in this field to fine tune it or use the copy button to copy it and paste it into your code.
|
||||
|
||||
######
|
||||
|
|
@ -284,7 +284,7 @@ pwsh bin/Debug/netX/playwright.ps1 codegen --color-scheme=dark playwright.dev
|
|||
Record scripts and tests while emulating timezone, language & location using the `--timezone`, `--geolocation` and `--lang` options. Once the page opens:
|
||||
|
||||
1. Accept the cookies
|
||||
1. On the top right click on the locate me button to see geolocation in action.
|
||||
1. On the top right, click on the locate me button to see geolocation in action.
|
||||
|
||||
```bash js
|
||||
npx playwright codegen --timezone="Europe/Rome" --geolocation="41.890221,12.492348" --lang="it-IT" bing.com/maps
|
||||
|
|
@ -375,7 +375,7 @@ Make sure you only use the `auth.json` locally as it contains sensitive informat
|
|||
|
||||
#### Load authenticated state
|
||||
|
||||
Run with `--load-storage` to consume the previously loaded storage from the `auth.json`. This way, all [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) and [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) will be restored, bringing most web apps to the authenticated state without the need to login again. This means you can can continue generating tests from the logged in state.
|
||||
Run with `--load-storage` to consume the previously loaded storage from the `auth.json`. This way, all [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) and [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) will be restored, bringing most web apps to the authenticated state without the need to login again. This means you can continue generating tests from the logged in state.
|
||||
|
||||
```bash js
|
||||
npx playwright codegen --load-storage=auth.json github.com/microsoft/playwright
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ A browser window will open and the test will run and pause at where the breakpoi
|
|||
|
||||
### Debug in different Browsers
|
||||
|
||||
By default debugging is done using the Chromium profile. You can debug your tests on different browsers by right clicking on the debug icon in the testing sidebar and clicking on the 'Select Default Profile' option from the dropdown.
|
||||
By default, debugging is done using the Chromium profile. You can debug your tests on different browsers by right clicking on the debug icon in the testing sidebar and clicking on the 'Select Default Profile' option from the dropdown.
|
||||
|
||||
<img width="1312" alt="debugging on specific profile" src="https://user-images.githubusercontent.com/13063165/212879469-436f8130-c62a-49e1-9d67-c1903b478d5f.png" />
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ npx playwright test --debug
|
|||
```
|
||||
#### Debug one test on all browsers
|
||||
|
||||
To debug one test on a specific line run the test command followed by the name of the test file and the line number of the test you want to debug, followed by the `--debug` flag. This will run a single test in each browser configured in your [`playwright.config`](./test-projects.md#configure-projects-for-multiple-browsers) and open the inspector.
|
||||
To debug one test on a specific line, run the test command followed by the name of the test file and the line number of the test you want to debug, followed by the `--debug` flag. This will run a single test in each browser configured in your [`playwright.config`](./test-projects.md#configure-projects-for-multiple-browsers) and open the inspector.
|
||||
|
||||
```bash
|
||||
npx playwright test example.spec.ts:10 --debug
|
||||
|
|
@ -207,7 +207,7 @@ While running in debug mode you can live edit the locators. Next to the 'Pick Lo
|
|||
|
||||
### Picking locators
|
||||
|
||||
While debugging you might need to choose a more resilient locator. You can do this by clicking on the **Pick Locator** button and hovering over any element in the browser window. While hovering over an element you will see the code needed to locate this element highlighted below. Clicking an element in the browser will add the locator into the field where you can then either tweak it or copy it into your code.
|
||||
While debugging, you might need to choose a more resilient locator. You can do this by clicking on the **Pick Locator** button and hovering over any element in the browser window. While hovering over an element you will see the code needed to locate this element highlighted below. Clicking an element in the browser will add the locator into the field where you can then either tweak it or copy it into your code.
|
||||
|
||||
<img width="1392" alt="Picking locators" src="https://user-images.githubusercontent.com/13063165/212968640-ce82a027-9277-4bdf-b0a9-6282fb2becb7.png" />
|
||||
|
||||
|
|
@ -242,7 +242,7 @@ This will also set the default timeouts of Playwright to 0 (= no timeout).
|
|||
|
||||
<img width="1399" alt="Browser Developer Tools with Playwright object" src="https://user-images.githubusercontent.com/13063165/219128002-898f604d-9697-4b7f-95b5-a6a8260b7282.png" />
|
||||
|
||||
To debug your tests using the browser developer tools start by setting a breakpoint in your test to pause the execution using the [`method: Page.pause`] method.
|
||||
To debug your tests using the browser developer tools, start by setting a breakpoint in your test to pause the execution using the [`method: Page.pause`] method.
|
||||
|
||||
```js
|
||||
await page.pause();
|
||||
|
|
@ -264,7 +264,7 @@ page.pause()
|
|||
await page.PauseAsync();
|
||||
```
|
||||
|
||||
Once you have set a breakpoint in your test you can then run your test with `PWDEBUG=console`.
|
||||
Once you have set a breakpoint in your test, you can then run your test with `PWDEBUG=console`.
|
||||
|
||||
```bash tab=bash-bash lang=js
|
||||
PWDEBUG=console npx playwright test
|
||||
|
|
@ -327,7 +327,7 @@ $env:PWDEBUG=console
|
|||
dotnet test
|
||||
```
|
||||
|
||||
Once Playwright launches the browser window you can open the developer tools.
|
||||
Once Playwright launches the browser window, you can open the developer tools.
|
||||
The `playwright` object will be available in the console panel.
|
||||
|
||||
#### playwright.$(selector)
|
||||
|
|
|
|||
|
|
@ -18,19 +18,19 @@ This Docker image is intended to be used for testing and development purposes on
|
|||
### Pull the image
|
||||
|
||||
```bash js
|
||||
docker pull mcr.microsoft.com/playwright:v%%VERSION%%-jammy
|
||||
docker pull mcr.microsoft.com/playwright:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
```bash python
|
||||
docker pull mcr.microsoft.com/playwright/python:v%%VERSION%%-jammy
|
||||
docker pull mcr.microsoft.com/playwright/python:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
```bash csharp
|
||||
docker pull mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-jammy
|
||||
docker pull mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
```bash java
|
||||
docker pull mcr.microsoft.com/playwright/java:v%%VERSION%%-jammy
|
||||
docker pull mcr.microsoft.com/playwright/java:v%%VERSION%%-noble
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
```bash js
|
||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright:v%%VERSION%%-jammy /bin/bash
|
||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright:v%%VERSION%%-noble /bin/bash
|
||||
```
|
||||
|
||||
```bash python
|
||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/python:v%%VERSION%%-jammy /bin/bash
|
||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/python:v%%VERSION%%-noble /bin/bash
|
||||
```
|
||||
|
||||
```bash csharp
|
||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-jammy /bin/bash
|
||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-noble /bin/bash
|
||||
```
|
||||
|
||||
```bash java
|
||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/java:v%%VERSION%%-jammy /bin/bash
|
||||
docker run -it --rm --ipc=host mcr.microsoft.com/playwright/java:v%%VERSION%%-noble /bin/bash
|
||||
```
|
||||
|
||||
#### Crawling and scraping
|
||||
|
|
@ -62,19 +62,19 @@ docker run -it --rm --ipc=host mcr.microsoft.com/playwright/java:v%%VERSION%%-ja
|
|||
On untrusted websites, it's recommended to use a separate user for launching the browsers in combination with the seccomp profile. Inside the container or if you are using the Docker image as a base image you have to use `adduser` for it.
|
||||
|
||||
```bash js
|
||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright:v%%VERSION%%-jammy /bin/bash
|
||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright:v%%VERSION%%-noble /bin/bash
|
||||
```
|
||||
|
||||
```bash python
|
||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/python:v%%VERSION%%-jammy /bin/bash
|
||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/python:v%%VERSION%%-noble /bin/bash
|
||||
```
|
||||
|
||||
```bash csharp
|
||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-jammy /bin/bash
|
||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/dotnet:v%%VERSION%%-noble /bin/bash
|
||||
```
|
||||
|
||||
```bash java
|
||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/java:v%%VERSION%%-jammy /bin/bash
|
||||
docker run -it --rm --ipc=host --user pwuser --security-opt seccomp=seccomp_profile.json mcr.microsoft.com/playwright/java:v%%VERSION%%-noble /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:
|
||||
|
|
@ -108,9 +108,7 @@ See our [Continuous Integration guides](./ci.md) for sample configs.
|
|||
See [all available image tags].
|
||||
|
||||
We currently publish images with the following tags:
|
||||
- `:next` - tip-of-tree image version based on Ubuntu 22.04 LTS (Jammy Jellyfish).
|
||||
- `:next-jammy` - tip-of-tree image version based on Ubuntu 22.04 LTS (Jammy Jellyfish).
|
||||
- `:v%%VERSION%%` - Playwright v%%VERSION%% release docker image based on Ubuntu 22.04 LTS (Jammy Jellyfish).
|
||||
- `:v%%VERSION%%` - Playwright v%%VERSION%% release docker image based on Ubuntu 24.04 LTS (Noble Numbat).
|
||||
- `:v%%VERSION%%-noble` - Playwright v%%VERSION%% release docker image based on Ubuntu 24.04 LTS (Noble Numbat).
|
||||
- `:v%%VERSION%%-jammy` - Playwright v%%VERSION%% release docker image based on Ubuntu 22.04 LTS (Jammy Jellyfish).
|
||||
- `:v%%VERSION%%-focal` - Playwright v%%VERSION%% release docker image based on Ubuntu 20.04 LTS (Focal Fossa).
|
||||
|
|
|
|||
|
|
@ -68,9 +68,95 @@ int status = await page.EvaluateAsync<int>(@"async () => {
|
|||
}");
|
||||
```
|
||||
|
||||
## Different environments
|
||||
|
||||
Evaluated scripts run in the browser environment, while your test runs in a testing environments. This means you cannot use variables from your test in the page and vice versa. Instead, you should pass them explicitly as an argument.
|
||||
|
||||
The following snippet is **WRONG** because it uses the variable directly:
|
||||
|
||||
```js
|
||||
const data = 'some data';
|
||||
const result = await page.evaluate(() => {
|
||||
// WRONG: there is no "data" in the web page.
|
||||
window.myApp.use(data);
|
||||
});
|
||||
```
|
||||
|
||||
```java
|
||||
String data = "some data";
|
||||
Object result = page.evaluate("() => {\n" +
|
||||
" // WRONG: there is no 'data' in the web page.\n" +
|
||||
" window.myApp.use(data);\n" +
|
||||
"}");
|
||||
```
|
||||
|
||||
```python async
|
||||
data = "some data"
|
||||
result = await page.evaluate("""() => {
|
||||
// WRONG: there is no "data" in the web page.
|
||||
window.myApp.use(data)
|
||||
}""")
|
||||
```
|
||||
|
||||
```python sync
|
||||
data = "some data"
|
||||
result = page.evaluate("""() => {
|
||||
// WRONG: there is no "data" in the web page.
|
||||
window.myApp.use(data)
|
||||
}""")
|
||||
```
|
||||
|
||||
```csharp
|
||||
var data = "some data";
|
||||
var result = await page.EvaluateAsync(@"() => {
|
||||
// WRONG: there is no 'data' in the web page.
|
||||
window.myApp.use(data);
|
||||
}");
|
||||
```
|
||||
|
||||
The following snippet is **CORRECT** because it passes the value explicitly as an argument:
|
||||
|
||||
```js
|
||||
const data = 'some data';
|
||||
// Pass |data| as a parameter.
|
||||
const result = await page.evaluate(data => {
|
||||
window.myApp.use(data);
|
||||
}, data);
|
||||
```
|
||||
|
||||
```java
|
||||
String data = "some data";
|
||||
// Pass |data| as a parameter.
|
||||
Object result = page.evaluate("data => {\n" +
|
||||
" window.myApp.use(data);\n" +
|
||||
"}", data);
|
||||
```
|
||||
|
||||
```python async
|
||||
data = "some data"
|
||||
# Pass |data| as a parameter.
|
||||
result = await page.evaluate("""data => {
|
||||
window.myApp.use(data)
|
||||
}""", data)
|
||||
```
|
||||
|
||||
```python sync
|
||||
data = "some data"
|
||||
# Pass |data| as a parameter.
|
||||
result = page.evaluate("""data => {
|
||||
window.myApp.use(data)
|
||||
}""", data)
|
||||
```
|
||||
|
||||
```csharp
|
||||
var data = "some data";
|
||||
// Pass |data| as a parameter.
|
||||
var result = await page.EvaluateAsync("data => { window.myApp.use(data); }", data);
|
||||
```
|
||||
|
||||
## Evaluation Argument
|
||||
|
||||
Playwright evaluation methods like [`method: Page.evaluate`] take a single optional argument. This argument can be a mix of [Serializable] values and [JSHandle] or [ElementHandle] instances. Handles are automatically converted to the value they represent.
|
||||
Playwright evaluation methods like [`method: Page.evaluate`] take a single optional argument. This argument can be a mix of [Serializable] values and [JSHandle] instances. Handles are automatically converted to the value they represent.
|
||||
|
||||
```js
|
||||
// A primitive value.
|
||||
|
|
@ -86,7 +172,7 @@ await page.evaluate(object => object.foo, { foo: 'bar' });
|
|||
const button = await page.evaluateHandle('window.button');
|
||||
await page.evaluate(button => button.textContent, button);
|
||||
|
||||
// Alternative notation using elementHandle.evaluate.
|
||||
// Alternative notation using JSHandle.evaluate.
|
||||
await button.evaluate((button, from) => button.textContent.substring(from), 5);
|
||||
|
||||
// Object with multiple handles.
|
||||
|
|
@ -109,7 +195,7 @@ await page.evaluate(
|
|||
([b1, b2]) => b1.textContent + b2.textContent,
|
||||
[button1, button2]);
|
||||
|
||||
// Any non-cyclic mix of serializables and handles works.
|
||||
// Any mix of serializables and handles works.
|
||||
await page.evaluate(
|
||||
x => x.button1.textContent + x.list[0].textContent + String(x.foo),
|
||||
{ button1, list: [button2], foo: null });
|
||||
|
|
@ -131,7 +217,7 @@ page.evaluate("object => object.foo", obj);
|
|||
ElementHandle button = page.evaluateHandle("window.button");
|
||||
page.evaluate("button => button.textContent", button);
|
||||
|
||||
// Alternative notation using elementHandle.evaluate.
|
||||
// Alternative notation using JSHandle.evaluate.
|
||||
button.evaluate("(button, from) => button.textContent.substring(from)", 5);
|
||||
|
||||
// Object with multiple handles.
|
||||
|
|
@ -156,7 +242,7 @@ page.evaluate(
|
|||
"([b1, b2]) => b1.textContent + b2.textContent",
|
||||
Arrays.asList(button1, button2));
|
||||
|
||||
// Any non-cyclic mix of serializables and handles works.
|
||||
// Any mix of serializables and handles works.
|
||||
Map<String, Object> arg = new HashMap<>();
|
||||
arg.put("button1", button1);
|
||||
arg.put("list", Arrays.asList(button2));
|
||||
|
|
@ -180,7 +266,7 @@ await page.evaluate('object => object.foo', { 'foo': 'bar' })
|
|||
button = await page.evaluate_handle('button')
|
||||
await page.evaluate('button => button.textContent', button)
|
||||
|
||||
# Alternative notation using elementHandle.evaluate.
|
||||
# Alternative notation using JSHandle.evaluate.
|
||||
await button.evaluate('(button, from) => button.textContent.substring(from)', 5)
|
||||
|
||||
# Object with multiple handles.
|
||||
|
|
@ -203,7 +289,7 @@ await page.evaluate("""
|
|||
([b1, b2]) => b1.textContent + b2.textContent""",
|
||||
[button1, button2])
|
||||
|
||||
# Any non-cyclic mix of serializables and handles works.
|
||||
# Any mix of serializables and handles works.
|
||||
await page.evaluate("""
|
||||
x => x.button1.textContent + x.list[0].textContent + String(x.foo)""",
|
||||
{ 'button1': button1, 'list': [button2], 'foo': None })
|
||||
|
|
@ -223,7 +309,7 @@ page.evaluate('object => object.foo', { 'foo': 'bar' })
|
|||
button = page.evaluate_handle('window.button')
|
||||
page.evaluate('button => button.textContent', button)
|
||||
|
||||
# Alternative notation using elementHandle.evaluate.
|
||||
# Alternative notation using JSHandle.evaluate.
|
||||
button.evaluate('(button, from) => button.textContent.substring(from)', 5)
|
||||
|
||||
# Object with multiple handles.
|
||||
|
|
@ -245,7 +331,7 @@ page.evaluate("""
|
|||
([b1, b2]) => b1.textContent + b2.textContent""",
|
||||
[button1, button2])
|
||||
|
||||
# Any non-cyclic mix of serializables and handles works.
|
||||
# Any mix of serializables and handles works.
|
||||
page.evaluate("""
|
||||
x => x.button1.textContent + x.list[0].textContent + String(x.foo)""",
|
||||
{ 'button1': button1, 'list': [button2], 'foo': None })
|
||||
|
|
@ -265,7 +351,7 @@ await page.EvaluateAsync<object>("object => object.foo", new { foo = "bar" });
|
|||
var button = await page.EvaluateHandleAsync("window.button");
|
||||
await page.EvaluateAsync<IJSHandle>("button => button.textContent", button);
|
||||
|
||||
// Alternative notation using elementHandle.EvaluateAsync.
|
||||
// Alternative notation using JSHandle.EvaluateAsync.
|
||||
await button.EvaluateAsync<string>("(button, from) => button.textContent.substring(from)", 5);
|
||||
|
||||
// Object with multiple handles.
|
||||
|
|
@ -282,93 +368,69 @@ await page.EvaluateAsync("({ button1, button2 }) => button1.textContent + button
|
|||
// Note the required parenthesis.
|
||||
await page.EvaluateAsync("([b1, b2]) => b1.textContent + b2.textContent", new[] { button1, button2 });
|
||||
|
||||
// Any non-cyclic mix of serializables and handles works.
|
||||
// Any mix of serializables and handles works.
|
||||
await page.EvaluateAsync("x => x.button1.textContent + x.list[0].textContent + String(x.foo)", new { button1, list = new[] { button2 }, foo = null as object });
|
||||
```
|
||||
|
||||
Right:
|
||||
## Init scripts
|
||||
|
||||
Sometimes it is convenient to evaluate something in the page before it starts loading. For example, you might want to setup some mocks or test data.
|
||||
|
||||
In this case, use [`method: Page.addInitScript`] or [`method: BrowserContext.addInitScript`]. In the example below, we will replace `Math.random()` with a constant value.
|
||||
|
||||
First, create a `preload.js` file that contains the mock.
|
||||
|
||||
```js browser
|
||||
// preload.js
|
||||
Math.random = () => 42;
|
||||
```
|
||||
|
||||
Next, add init script to the page.
|
||||
|
||||
```js
|
||||
const data = { text: 'some data', value: 1 };
|
||||
// Pass |data| as a parameter.
|
||||
const result = await page.evaluate(data => {
|
||||
window.myApp.use(data);
|
||||
}, data);
|
||||
```
|
||||
import { test, expect } from '@playwright/test';
|
||||
import path from 'path';
|
||||
|
||||
```java
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("text", "some data");
|
||||
data.put("value", 1);
|
||||
// Pass |data| as a parameter.
|
||||
Object result = page.evaluate("data => {\n" +
|
||||
" window.myApp.use(data);\n" +
|
||||
"}", data);
|
||||
```
|
||||
|
||||
```python async
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
# Pass |data| as a parameter.
|
||||
result = await page.evaluate("""data => {
|
||||
window.myApp.use(data)
|
||||
}""", data)
|
||||
```
|
||||
|
||||
```python sync
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
# Pass |data| as a parameter.
|
||||
result = page.evaluate("""data => {
|
||||
window.myApp.use(data)
|
||||
}""", data)
|
||||
```
|
||||
|
||||
```csharp
|
||||
var data = new { text = "some data", value = 1};
|
||||
// Pass data as a parameter
|
||||
var result = await page.EvaluateAsync("data => { window.myApp.use(data); }", data);
|
||||
```
|
||||
|
||||
Wrong:
|
||||
|
||||
```js
|
||||
const data = { text: 'some data', value: 1 };
|
||||
const result = await page.evaluate(() => {
|
||||
// There is no |data| in the web page.
|
||||
window.myApp.use(data);
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Add script for every test in the beforeEach hook.
|
||||
// Make sure to correctly resolve the script path.
|
||||
await page.addInitScript({ path: path.resolve(__dirname, '../mocks/preload.js') });
|
||||
});
|
||||
```
|
||||
|
||||
```java
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("text", "some data");
|
||||
data.put("value", 1);
|
||||
Object result = page.evaluate("() => {\n" +
|
||||
" // There is no |data| in the web page.\n" +
|
||||
" window.myApp.use(data);\n" +
|
||||
"}");
|
||||
// In your test, assuming the "preload.js" file is in the "mocks" directory.
|
||||
page.addInitScript(Paths.get("mocks/preload.js"));
|
||||
```
|
||||
|
||||
```python async
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
result = await page.evaluate("""() => {
|
||||
// There is no |data| in the web page.
|
||||
window.myApp.use(data)
|
||||
}""")
|
||||
# In your test, assuming the "preload.js" file is in the "mocks" directory.
|
||||
await page.add_init_script(path="mocks/preload.js")
|
||||
```
|
||||
|
||||
```python sync
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
result = page.evaluate("""() => {
|
||||
// There is no |data| in the web page.
|
||||
window.myApp.use(data)
|
||||
}""")
|
||||
# In your test, assuming the "preload.js" file is in the "mocks" directory.
|
||||
page.add_init_script(path="mocks/preload.js")
|
||||
```
|
||||
|
||||
```csharp
|
||||
var data = new { text = "some data", value = 1};
|
||||
// Pass data as a parameter
|
||||
var result = await page.EvaluateAsync(@"data => {
|
||||
// There is no |data| in the web page.
|
||||
window.myApp.use(data);
|
||||
}");
|
||||
// In your test, assuming the "preload.js" file is in the "mocks" directory.
|
||||
await Page.AddInitScriptAsync(scriptPath: "mocks/preload.js");
|
||||
```
|
||||
|
||||
######
|
||||
* langs: js
|
||||
|
||||
Alternatively, you can pass a function instead of creating a preload script file. This is more convenient for short or one-off scripts. You can also pass an argument this way.
|
||||
|
||||
```js
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
// Add script for every test in the beforeEach hook.
|
||||
test.beforeEach(async ({ page }) => {
|
||||
const value = 42;
|
||||
await page.addInitScript(value => {
|
||||
Math.random = () => value;
|
||||
}, value);
|
||||
});
|
||||
```
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ title: "Events"
|
|||
|
||||
## Introduction
|
||||
|
||||
Playwright allows listening to various types of events happening on the web page, such as network requests, creation of child pages, dedicated workers etc. There are several ways to subscribe to such events such as waiting for events or adding or removing event listeners.
|
||||
Playwright allows listening to various types of events happening on the web page, such as network requests, creation of child pages, dedicated workers etc. There are several ways to subscribe to such events, such as waiting for events or adding or removing event listeners.
|
||||
|
||||
## Waiting for event
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ Install the [Pytest plugin](https://anaconda.org/Microsoft/pytest-playwright):
|
|||
```bash
|
||||
conda config --add channels conda-forge
|
||||
conda config --add channels microsoft
|
||||
conda install playwright
|
||||
conda install pytest-playwright
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ With a few lines of code, you can hook up Playwright to your favorite Java test
|
|||
In [JUnit](https://junit.org/junit5/), you can use Playwright [fixtures](./junit.md#fixtures) to automatically initialize [Playwright], [Browser], [BrowserContext] or [Page]. In the example below, all three test methods use the same
|
||||
[Browser]. Each test uses its own [BrowserContext] and [Page].
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
```java
|
||||
package org.example;
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ The key differences to note are as follows:
|
|||
| Installation | `npm install playwright` | `npm init playwright@latest` - note `install` vs. `init` |
|
||||
| Install browsers | Install `@playwright/browser-chromium`, `@playwright/browser-firefox` and/or `@playwright/browser-webkit` | `npx playwright install` or `npx playwright install chromium` for a single one |
|
||||
| `import` from | `playwright` | `@playwright/test` |
|
||||
| Initialization | Explicitly need to: <ol><li>Pick a browser to use, e.g. `chromium`</li><li>Launch browser with [`method: BrowserType.launch`]</li><li>Create a context with [`method: Browser.newContext`], <em>and</em> pass any context options explicitly, e.g. `devices['iPhone 11']`</li><li>Create a page with [`method: BrowserContext.newPage`]</li></ol> | An isolated `page` and `context` are provided to each test out-of the box, along with other [built-in fixtures](./test-fixtures.md#built-in-fixtures). No explicit creation. If referenced by the test in it's arguments, the Test Runner will create them for the test. (i.e. lazy-initialization) |
|
||||
| Initialization | Explicitly need to: <ol><li>Pick a browser to use, e.g. `chromium`</li><li>Launch browser with [`method: BrowserType.launch`]</li><li>Create a context with [`method: Browser.newContext`], <em>and</em> pass any context options explicitly, e.g. `devices['iPhone 11']`</li><li>Create a page with [`method: BrowserContext.newPage`]</li></ol> | An isolated `page` and `context` are provided to each test out-of the box, along with other [built-in fixtures](./test-fixtures.md#built-in-fixtures). No explicit creation. If referenced by the test in its arguments, the Test Runner will create them for the test. (i.e. lazy-initialization) |
|
||||
| Assertions | No built-in Web-First Assertions | [Web-First assertions](./test-assertions.md) like: <ul><li>[`method: PageAssertions.toHaveTitle`]</li><li>[`method: PageAssertions.toHaveScreenshot#1`]</li></ul> which auto-wait and retry for the condition to be met.|
|
||||
| Cleanup | Explicitly need to: <ol><li>Close context with [`method: BrowserContext.close`]</li><li>Close browser with [`method: Browser.close`]</li></ol> | No explicit close of [built-in fixtures](./test-fixtures.md#built-in-fixtures); the Test Runner will take care of it.
|
||||
| Running | When using the Library, you run the code as a node script, possibly with some compilation first. | When using the Test Runner, you use the `npx playwright test` command. Along with your [config](./test-configuration.md), the Test Runner handles any compilation and choosing what to run and how to run it. |
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ a way to find element(s) on the page at any moment.
|
|||
|
||||
### Quick Guide
|
||||
|
||||
These are the recommended built in locators.
|
||||
These are the recommended built-in locators.
|
||||
|
||||
- [`method: Page.getByRole`](#locate-by-role) to locate by explicit and implicit accessibility attributes.
|
||||
- [`method: Page.getByText`](#locate-by-text) to locate by text content.
|
||||
|
|
@ -513,7 +513,7 @@ Use this locator when your element has the `title` attribute.
|
|||
|
||||
### Locate by test id
|
||||
|
||||
Testing by test ids is the most resilient way of testing as even if your text or role of the attribute changes the test will still pass. QA's and developers should define explicit test ids and query them with [`method: Page.getByTestId`]. However testing by test ids is not user facing. If the role or text value is important to you then consider using user facing locators such as [role](#locate-by-role) and [text locators](#locate-by-text).
|
||||
Testing by test ids is the most resilient way of testing as even if your text or role of the attribute changes, the test will still pass. QA's and developers should define explicit test ids and query them with [`method: Page.getByTestId`]. However testing by test ids is not user facing. If the role or text value is important to you then consider using user facing locators such as [role](#locate-by-role) and [text locators](#locate-by-text).
|
||||
|
||||
For example, consider the following DOM structure.
|
||||
|
||||
|
|
@ -1501,7 +1501,7 @@ For example, consider the following DOM structure:
|
|||
</ul>
|
||||
```
|
||||
|
||||
Locate an item by it's test id of "orange" and then click it.
|
||||
Locate an item by its test id of "orange" and then click it.
|
||||
|
||||
```js
|
||||
await page.getByTestId('orange').click();
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ await Expect(page.GetByText("Strawberry")).ToBeVisibleAsync();
|
|||
|
||||
```java
|
||||
// Get the response from the HAR file
|
||||
page.routeFromHAR("./hars/fruit.har", new RouteFromHAROptions()
|
||||
page.routeFromHAR(Path.of("./hars/fruit.har"), new RouteFromHAROptions()
|
||||
.setUrl("*/**/api/v1/fruits")
|
||||
.setUpdate(true)
|
||||
);
|
||||
|
|
@ -386,7 +386,7 @@ await page.ExpectByTextAsync("Playwright", new() { Exact = true }).ToBeVisibleAs
|
|||
// Replay API requests from HAR.
|
||||
// Either use a matching response from the HAR,
|
||||
// or abort the request if nothing matches.
|
||||
page.routeFromHAR("./hars/fruit.har", new RouteFromHAROptions()
|
||||
page.routeFromHAR(Path.of("./hars/fruit.har"), new RouteFromHAROptions()
|
||||
.setUrl("*/**/api/v1/fruits")
|
||||
.setUpdate(false)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ const browser = await chromium.launch({
|
|||
Browser browser = chromium.launch(new BrowserType.LaunchOptions()
|
||||
.setProxy(new Proxy("http://myproxy.com:3128")
|
||||
.setUsername('usr')
|
||||
.setPassword('pwd'));
|
||||
.setPassword('pwd')));
|
||||
```
|
||||
|
||||
```python async
|
||||
|
|
@ -179,60 +179,48 @@ await using var browser = await BrowserType.LaunchAsync(new()
|
|||
});
|
||||
```
|
||||
|
||||
When specifying proxy for each context individually, **Chromium on Windows** needs a hint that proxy will be set. This is done via passing a non-empty proxy server to the browser itself. Here is an example of a context-specific proxy:
|
||||
Its also possible to specify it per context:
|
||||
|
||||
```js tab=js-test title="playwright.config.ts"
|
||||
import { defineConfig } from '@playwright/test';
|
||||
export default defineConfig({
|
||||
use: {
|
||||
launchOptions: {
|
||||
// Browser proxy option is required for Chromium on Windows.
|
||||
proxy: { server: 'per-context' }
|
||||
},
|
||||
```js tab=js-test title="example.spec.ts"
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('should use custom proxy on a new context', async ({ browser }) => {
|
||||
const context = await browser.newContext({
|
||||
proxy: {
|
||||
server: 'http://myproxy.com:3128',
|
||||
}
|
||||
}
|
||||
});
|
||||
const page = await context.newPage();
|
||||
|
||||
await context.close();
|
||||
});
|
||||
```
|
||||
|
||||
```js tab=js-library
|
||||
const browser = await chromium.launch({
|
||||
// Browser proxy option is required for Chromium on Windows.
|
||||
proxy: { server: 'per-context' }
|
||||
});
|
||||
const browser = await chromium.launch();
|
||||
const context = await browser.newContext({
|
||||
proxy: { server: 'http://myproxy.com:3128' }
|
||||
});
|
||||
```
|
||||
|
||||
```java
|
||||
Browser browser = chromium.launch(new BrowserType.LaunchOptions()
|
||||
// Browser proxy option is required for Chromium on Windows.
|
||||
.setProxy(new Proxy("per-context"));
|
||||
BrowserContext context = chromium.launch(new Browser.NewContextOptions()
|
||||
.setProxy(new Proxy("http://myproxy.com:3128"));
|
||||
Browser browser = chromium.launch();
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||
.setProxy(new Proxy("http://myproxy.com:3128")));
|
||||
```
|
||||
|
||||
```python async
|
||||
# Browser proxy option is required for Chromium on Windows.
|
||||
browser = await chromium.launch(proxy={"server": "per-context"})
|
||||
browser = await chromium.launch()
|
||||
context = await browser.new_context(proxy={"server": "http://myproxy.com:3128"})
|
||||
```
|
||||
|
||||
```python sync
|
||||
# Browser proxy option is required for Chromium on Windows.
|
||||
browser = chromium.launch(proxy={"server": "per-context"})
|
||||
browser = chromium.launch()
|
||||
context = browser.new_context(proxy={"server": "http://myproxy.com:3128"})
|
||||
```
|
||||
|
||||
```csharp
|
||||
var proxy = new Proxy { Server = "per-context" };
|
||||
await using var browser = await BrowserType.LaunchAsync(new()
|
||||
{
|
||||
// Browser proxy option is required for Chromium on Windows.
|
||||
Proxy = proxy
|
||||
});
|
||||
await using var browser = await BrowserType.LaunchAsync();
|
||||
await using var context = await browser.NewContextAsync(new()
|
||||
{
|
||||
Proxy = new Proxy { Server = "http://myproxy.com:3128" },
|
||||
|
|
|
|||
|
|
@ -668,7 +668,7 @@ We recommend [locating by label text](./locators.md#locate-by-label) instead of
|
|||
|
||||
Targeted input actions in Playwright automatically distinguish between labels and controls, so you can target the label to perform an action on the associated control.
|
||||
|
||||
For example, consider the following DOM structure: `<label for="password">Password:</label><input id="password" type="password">`. You can target the label by it's "Password" text using [`method: Page.getByText`]. However, the following actions will be performed on the input instead of the label:
|
||||
For example, consider the following DOM structure: `<label for="password">Password:</label><input id="password" type="password">`. You can target the label by its "Password" text using [`method: Page.getByText`]. However, the following actions will be performed on the input instead of the label:
|
||||
- [`method: Locator.click`] will click the label and automatically focus the input field;
|
||||
- [`method: Locator.fill`] will fill the input field;
|
||||
- [`method: Locator.inputValue`] will return the value of the input field;
|
||||
|
|
@ -881,7 +881,7 @@ await page.Locator("data-test-id=submit").ClickAsync();
|
|||
```
|
||||
|
||||
:::note
|
||||
Attribute selectors are not CSS selectors, so anything CSS-specific like `:enabled` is not supported. For more features, use a proper [css] selector, e.g. `css=[data-test="login"]:enabled`.
|
||||
Attribute selectors are not CSS selectors, so anything CSS-specific like `:enabled` is not supported. For more features, use a proper [css](#css-locator) selector, e.g. `css=[data-test="login"]:enabled`.
|
||||
:::
|
||||
|
||||
## Chaining selectors
|
||||
|
|
@ -918,11 +918,3 @@ We recommend [filtering by another locator](./locators.md#filter-by-childdescend
|
|||
By default, chained selectors resolve to an element queried by the last selector. A selector can be prefixed with `*` to capture elements that are queried by an intermediate selector.
|
||||
|
||||
For example, `css=article >> text=Hello` captures the element with the text `Hello`, and `*css=article >> text=Hello` (note the `*`) captures the `article` element that contains some element with the text `Hello`.
|
||||
|
||||
|
||||
[text]: #text-selector
|
||||
[css]: #css-selector
|
||||
[xpath]: #xpath-selectors
|
||||
[react]: #react-selectors
|
||||
[vue]: #vue-selectors
|
||||
[id]: #id-data-testid-data-test-id-data-test-selectors
|
||||
|
|
|
|||
|
|
@ -4,6 +4,81 @@ title: "Release notes"
|
|||
toc_max_heading_level: 2
|
||||
---
|
||||
|
||||
## Version 1.47
|
||||
|
||||
### Network Tab improvements
|
||||
|
||||
The Network tab in the trace viewer has several nice improvements:
|
||||
|
||||
- filtering by asset type and URL
|
||||
- better display of query string parameters
|
||||
- preview of font assets
|
||||
|
||||

|
||||
|
||||
### Miscellaneous
|
||||
|
||||
- The `mcr.microsoft.com/playwright-dotnet:v1.47.0` now serves a Playwright image based on Ubuntu 24.04 Noble.
|
||||
To use the 22.04 jammy-based image, please use `mcr.microsoft.com/playwright-dotnet:v1.47.0-jammy` instead.
|
||||
- TLS client certificates can now be passed from memory by passing [`option: cert`] and [`option: key`] as byte arrays instead of file paths.
|
||||
- [`option: noWaitAfter`] in [`method: Locator.selectOption`] was deprecated.
|
||||
- We've seen reports of WebGL in Webkit misbehaving on GitHub Actions `macos-13`. We recommend upgrading GitHub Actions to `macos-14`.
|
||||
|
||||
### Browser Versions
|
||||
|
||||
- Chromium 129.0.6668.29
|
||||
- Mozilla Firefox 130.0
|
||||
- WebKit 18.0
|
||||
|
||||
This version was also tested against the following stable channels:
|
||||
|
||||
- Google Chrome 128
|
||||
- Microsoft Edge 128
|
||||
|
||||
## Version 1.46
|
||||
|
||||
### TLS Client Certificates
|
||||
|
||||
Playwright now allows to supply client-side certificates, so that server can verify them, as specified by TLS Client Authentication.
|
||||
|
||||
You can provide client certificates as a parameter of [`method: Browser.newContext`] and [`method: APIRequest.newContext`]. The following snippet sets up a client certificate for `https://example.com`:
|
||||
|
||||
```csharp
|
||||
var context = await Browser.NewContextAsync(new() {
|
||||
ClientCertificates = [
|
||||
new() {
|
||||
Origin = "https://example.com",
|
||||
CertPath = "client-certificates/cert.pem",
|
||||
KeyPath = "client-certificates/key.pem",
|
||||
}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
### Trace Viewer Updates
|
||||
|
||||
- Content of text attachments is now rendered inline in the attachments pane.
|
||||
- New setting to show/hide routing actions like [`method: Route.continue`].
|
||||
- Request method and status are shown in the network details tab.
|
||||
- New button to copy source file location to clipboard.
|
||||
- Metadata pane now displays the `BaseURL`.
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
- New `maxRetries` option in [`method: APIRequestContext.fetch`] which retries on the `ECONNRESET` network error.
|
||||
|
||||
### Browser Versions
|
||||
|
||||
- Chromium 128.0.6613.18
|
||||
- Mozilla Firefox 128.0
|
||||
- WebKit 18.0
|
||||
|
||||
This version was also tested against the following stable channels:
|
||||
|
||||
- Google Chrome 127
|
||||
- Microsoft Edge 127
|
||||
|
||||
|
||||
## Version 1.45
|
||||
|
||||
### Clock
|
||||
|
|
@ -112,7 +187,6 @@ await Page.RemoveLocatorHandlerAsync(locator);
|
|||
**Miscellaneous options**
|
||||
|
||||
- New method [`method: FormData.append`] allows to specify repeating fields with the same name in [`Multipart`](./api/class-apirequestcontext#api-request-context-fetch-option-multipart) option in `APIRequestContext.FetchAsync()`:
|
||||
- ```
|
||||
```csharp
|
||||
var formData = Context.APIRequest.CreateFormData();
|
||||
formData.Append("file", new FilePayload()
|
||||
|
|
@ -1012,7 +1086,7 @@ Read more in [our documentation](./test-assertions).
|
|||
|
||||
### Announcements
|
||||
|
||||
- v1.20 is the last release to receive WebKit update for macOS 10.15 Catalina. Please update MacOS to keep using latest & greatest WebKit!
|
||||
- v1.20 is the last release to receive WebKit update for macOS 10.15 Catalina. Please update macOS to keep using latest & greatest WebKit!
|
||||
|
||||
### Browser Versions
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,76 @@ title: "Release notes"
|
|||
toc_max_heading_level: 2
|
||||
---
|
||||
|
||||
## Version 1.47
|
||||
|
||||
### Network Tab improvements
|
||||
|
||||
The Network tab in the trace viewer has several nice improvements:
|
||||
|
||||
- filtering by asset type and URL
|
||||
- better display of query string parameters
|
||||
- preview of font assets
|
||||
|
||||

|
||||
|
||||
### Miscellaneous
|
||||
|
||||
- The `mcr.microsoft.com/playwright-java:v1.47.0` now serves a Playwright image based on Ubuntu 24.04 Noble.
|
||||
To use the 22.02 jammy-based image, please use `mcr.microsoft.com/playwright-java:v1.47.0-jammy` instead.
|
||||
- TLS client certificates can now be passed from memory by passing [`option: cert`] and [`option: key`] as byte arrays instead of file paths.
|
||||
- [`option: noWaitAfter`] in [`method: Locator.selectOption`] was deprecated.
|
||||
- We've seen reports of WebGL in Webkit misbehaving on GitHub Actions `macos-13`. We recommend upgrading GitHub Actions to `macos-14`.
|
||||
|
||||
### Browser Versions
|
||||
|
||||
- Chromium 129.0.6668.29
|
||||
- Mozilla Firefox 130.0
|
||||
- WebKit 18.0
|
||||
|
||||
This version was also tested against the following stable channels:
|
||||
|
||||
- Google Chrome 128
|
||||
- Microsoft Edge 128
|
||||
|
||||
## Version 1.46
|
||||
|
||||
### TLS Client Certificates
|
||||
|
||||
Playwright now allows to supply client-side certificates, so that server can verify them, as specified by TLS Client Authentication.
|
||||
|
||||
You can provide client certificates as a parameter of [`method: Browser.newContext`] and [`method: APIRequest.newContext`]. The following snippet sets up a client certificate for `https://example.com`:
|
||||
|
||||
```java
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||
.setClientCertificates(asList(new ClientCertificate("https://example.com")
|
||||
.setCertPath(Paths.get("client-certificates/cert.pem"))
|
||||
.setKeyPath(Paths.get("client-certificates/key.pem")))));
|
||||
```
|
||||
|
||||
### Trace Viewer Updates
|
||||
|
||||
- Content of text attachments is now rendered inline in the attachments pane.
|
||||
- New setting to show/hide routing actions like [`method: Route.continue`].
|
||||
- Request method and status are shown in the network details tab.
|
||||
- New button to copy source file location to clipboard.
|
||||
- Metadata pane now displays the `baseURL`.
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
- New `maxRetries` option in [`method: APIRequestContext.fetch`] which retries on the `ECONNRESET` network error.
|
||||
|
||||
### Browser Versions
|
||||
|
||||
- Chromium 128.0.6613.18
|
||||
- Mozilla Firefox 128.0
|
||||
- WebKit 18.0
|
||||
|
||||
This version was also tested against the following stable channels:
|
||||
|
||||
- Google Chrome 127
|
||||
- Microsoft Edge 127
|
||||
|
||||
|
||||
## Version 1.45
|
||||
|
||||
### Clock
|
||||
|
|
@ -1008,7 +1078,7 @@ This version was also tested against the following stable channels:
|
|||
|
||||
### Announcements
|
||||
|
||||
- v1.20 is the last release to receive WebKit update for macOS 10.15 Catalina. Please update MacOS to keep using latest & greatest WebKit!
|
||||
- v1.20 is the last release to receive WebKit update for macOS 10.15 Catalina. Please update macOS to keep using latest & greatest WebKit!
|
||||
|
||||
### Browser Versions
|
||||
|
||||
|
|
@ -1457,7 +1527,7 @@ This version of Playwright was also tested against the following stable channels
|
|||
|
||||
#### New APIs
|
||||
|
||||
- [`browserType.launch()`](./api/class-browsertype#browsertypelaunchoptions) now accepts the new `'channel'` option. Read more in [our documentation](./browsers).
|
||||
- [`method: BrowserType.launch`] now accepts the new `'channel'` option. Read more in [our documentation](./browsers).
|
||||
|
||||
|
||||
## Version 1.9
|
||||
|
|
|
|||
|
|
@ -6,6 +6,164 @@ toc_max_heading_level: 2
|
|||
|
||||
import LiteYouTube from '@site/src/components/LiteYouTube';
|
||||
|
||||
## Version 1.47
|
||||
|
||||
### Network Tab improvements
|
||||
|
||||
The Network tab in the UI mode and trace viewer has several nice improvements:
|
||||
|
||||
- filtering by asset type and URL
|
||||
- better display of query string parameters
|
||||
- preview of font assets
|
||||
|
||||

|
||||
|
||||
|
||||
### `--tsconfig` CLI option
|
||||
|
||||
By default, Playwright will look up the closest tsconfig for each imported file using a heuristic. You can now specify a single tsconfig file in the command line, and Playwright will use it for all imported files, not only test files:
|
||||
|
||||
```sh
|
||||
# Pass a specific tsconfig
|
||||
npx playwright test --tsconfig tsconfig.test.json
|
||||
```
|
||||
|
||||
### [APIRequestContext] now accepts [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) and `string` as query parameters
|
||||
|
||||
You can now pass [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) and `string` as query parameters to [APIRequestContext]:
|
||||
|
||||
```ts
|
||||
test('query params', async ({ request }) => {
|
||||
const searchParams = new URLSearchParams();
|
||||
searchParams.set('userId', 1);
|
||||
const response = await request.get(
|
||||
'https://jsonplaceholder.typicode.com/posts',
|
||||
{
|
||||
params: searchParams // or as a string: 'userId=1'
|
||||
}
|
||||
);
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
- The `mcr.microsoft.com/playwright:v1.47.0` now serves a Playwright image based on Ubuntu 24.04 Noble.
|
||||
To use the 22.04 jammy-based image, please use `mcr.microsoft.com/playwright:v1.47.0-jammy` instead.
|
||||
- New option [`option: behavior`] in [`method: Page.removeAllListeners`], [`method: Browser.removeAllListeners`] and [`method: BrowserContext.removeAllListeners`] to wait for ongoing listeners to complete.
|
||||
- TLS client certificates can now be passed from memory by passing [`option: cert`] and [`option: key`] as buffers instead of file paths.
|
||||
- Attachments with a `text/html` content type can now be opened in a new tab in the HTML report. This is useful for including third-party reports or other HTML content in the Playwright test report and distributing it to your team.
|
||||
- [`option: noWaitAfter`] in [`method: Locator.selectOption`] was deprecated.
|
||||
- We've seen reports of WebGL in Webkit misbehaving on GitHub Actions `macos-13`. We recommend upgrading GitHub Actions to `macos-14`.
|
||||
|
||||
### Browser Versions
|
||||
|
||||
- Chromium 129.0.6668.29
|
||||
- Mozilla Firefox 130.0
|
||||
- WebKit 18.0
|
||||
|
||||
This version was also tested against the following stable channels:
|
||||
|
||||
- Google Chrome 128
|
||||
- Microsoft Edge 128
|
||||
|
||||
## Version 1.46
|
||||
|
||||
<LiteYouTube
|
||||
id="tQo7w-QQBsI"
|
||||
title="Playwright 1.46"
|
||||
/>
|
||||
|
||||
|
||||
### TLS Client Certificates
|
||||
|
||||
Playwright now allows you to supply client-side certificates, so that server can verify them, as specified by TLS Client Authentication.
|
||||
|
||||
The following snippet sets up a client certificate for `https://example.com`:
|
||||
|
||||
```ts
|
||||
import { defineConfig } from '@playwright/test';
|
||||
|
||||
export default defineConfig({
|
||||
// ...
|
||||
use: {
|
||||
clientCertificates: [{
|
||||
origin: 'https://example.com',
|
||||
certPath: './cert.pem',
|
||||
keyPath: './key.pem',
|
||||
passphrase: 'mysecretpassword',
|
||||
}],
|
||||
},
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
You can also provide client certificates to a particular [test project](./api/class-testproject#test-project-use) or as a parameter of [`method: Browser.newContext`] and [`method: APIRequest.newContext`].
|
||||
|
||||
### `--only-changed` cli option
|
||||
|
||||
New CLI option `--only-changed` will only run test files that have been changed since the last git commit or from a specific git "ref". This will also run all test files that import any changed files.
|
||||
|
||||
```sh
|
||||
# Only run test files with uncommitted changes
|
||||
npx playwright test --only-changed
|
||||
|
||||
# Only run test files changed relative to the "main" branch
|
||||
npx playwright test --only-changed=main
|
||||
```
|
||||
|
||||
### Component Testing: New `router` fixture
|
||||
|
||||
This release introduces an experimental `router` fixture to intercept and handle network requests in component testing.
|
||||
There are two ways to use the router fixture:
|
||||
|
||||
- Call `router.route(url, handler)` that behaves similarly to [`method: Page.route`].
|
||||
- Call `router.use(handlers)` and pass [MSW library](https://mswjs.io) request handlers to it.
|
||||
|
||||
Here is an example of reusing your existing MSW handlers in the test.
|
||||
|
||||
```ts
|
||||
import { handlers } from '@src/mocks/handlers';
|
||||
|
||||
test.beforeEach(async ({ router }) => {
|
||||
// install common handlers before each test
|
||||
await router.use(...handlers);
|
||||
});
|
||||
|
||||
test('example test', async ({ mount }) => {
|
||||
// test as usual, your handlers are active
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
This fixture is only available in [component tests](./test-components#handling-network-requests).
|
||||
|
||||
### UI Mode / Trace Viewer Updates
|
||||
|
||||
- Test annotations are now shown in UI mode.
|
||||
- Content of text attachments is now rendered inline in the attachments pane.
|
||||
- New setting to show/hide routing actions like [`method: Route.continue`].
|
||||
- Request method and status are shown in the network details tab.
|
||||
- New button to copy source file location to clipboard.
|
||||
- Metadata pane now displays the `baseURL`.
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
- New `maxRetries` option in [`method: APIRequestContext.fetch`] which retries on the `ECONNRESET` network error.
|
||||
- New option to [box a fixture](./test-fixtures#box-fixtures) to minimize the fixture exposure in test reports and error messages.
|
||||
- New option to provide a [custom fixture title](./test-fixtures#custom-fixture-title) to be used in test reports and error messages.
|
||||
|
||||
### Browser Versions
|
||||
|
||||
- Chromium 128.0.6613.18
|
||||
- Mozilla Firefox 128.0
|
||||
- WebKit 18.0
|
||||
|
||||
This version was also tested against the following stable channels:
|
||||
|
||||
- Google Chrome 127
|
||||
- Microsoft Edge 127
|
||||
|
||||
## Version 1.45
|
||||
|
||||
<LiteYouTube
|
||||
|
|
@ -44,7 +202,7 @@ See [the clock guide](./clock.md) for more details.
|
|||
|
||||
- New CLI option `--fail-on-flaky-tests` that sets exit code to `1` upon any flaky tests. Note that by default, the test runner exits with code `0` when all failed tests recovered upon a retry. With this option, the test run will fail in such case.
|
||||
|
||||
- New enviroment variable `PLAYWRIGHT_FORCE_TTY` controls whether built-in `list`, `line` and `dot` reporters assume a live terminal. For example, this could be useful to disable tty behavior when your CI environment does not handle ANSI control sequences well. Alternatively, you can enable tty behavior even when to live terminal is present, if you plan to post-process the output and handle control sequences.
|
||||
- New environment variable `PLAYWRIGHT_FORCE_TTY` controls whether built-in `list`, `line` and `dot` reporters assume a live terminal. For example, this could be useful to disable tty behavior when your CI environment does not handle ANSI control sequences well. Alternatively, you can enable tty behavior even when to live terminal is present, if you plan to post-process the output and handle control sequences.
|
||||
|
||||
```sh
|
||||
# Avoid TTY features that output ANSI control sequences
|
||||
|
|
@ -1841,7 +1999,7 @@ This version was also tested against the following stable channels:
|
|||
|
||||
- We now ship a designated Python docker image `mcr.microsoft.com/playwright/python`. Please switch over to it if you use
|
||||
Python. This is the last release that includes Python inside our javascript `mcr.microsoft.com/playwright` docker image.
|
||||
- v1.20 is the last release to receive WebKit update for macOS 10.15 Catalina. Please update MacOS to keep using latest & greatest WebKit!
|
||||
- v1.20 is the last release to receive WebKit update for macOS 10.15 Catalina. Please update macOS to keep using latest & greatest WebKit!
|
||||
|
||||
### Browser Versions
|
||||
|
||||
|
|
@ -2651,7 +2809,7 @@ This version of Playwright was also tested against the following stable channels
|
|||
|
||||
#### New APIs
|
||||
|
||||
- [`browserType.launch()`](./api/class-browsertype#browsertypelaunchoptions) now accepts the new `'channel'` option. Read more in [our documentation](./browsers).
|
||||
- [`method: BrowserType.launch`] now accepts the new `'channel'` option. Read more in [our documentation](./browsers).
|
||||
|
||||
|
||||
## Version 1.9
|
||||
|
|
|
|||
|
|
@ -4,6 +4,81 @@ title: "Release notes"
|
|||
toc_max_heading_level: 2
|
||||
---
|
||||
|
||||
## Version 1.47
|
||||
|
||||
### Network Tab improvements
|
||||
|
||||
The Network tab in the trace viewer has several nice improvements:
|
||||
|
||||
- filtering by asset type and URL
|
||||
- better display of query string parameters
|
||||
- preview of font assets
|
||||
|
||||

|
||||
|
||||
### Miscellaneous
|
||||
|
||||
- The `mcr.microsoft.com/playwright-python:v1.47.0` now serves a Playwright image based on Ubuntu 24.04 Noble.
|
||||
To use the 22.04 jammy-based image, please use `mcr.microsoft.com/playwright-python:v1.47.0-jammy` instead.
|
||||
- TLS client certificates can now be passed from memory by passing [`option: cert`] and [`option: key`] as bytes instead of file paths.
|
||||
- [`option: noWaitAfter`] in [`method: Locator.selectOption`] was deprecated.
|
||||
- We've seen reports of WebGL in Webkit misbehaving on GitHub Actions `macos-13`. We recommend upgrading GitHub Actions to `macos-14`.
|
||||
|
||||
### Browser Versions
|
||||
|
||||
- Chromium 129.0.6668.29
|
||||
- Mozilla Firefox 130.0
|
||||
- WebKit 18.0
|
||||
|
||||
This version was also tested against the following stable channels:
|
||||
|
||||
- Google Chrome 128
|
||||
- Microsoft Edge 128
|
||||
|
||||
## Version 1.46
|
||||
|
||||
### TLS Client Certificates
|
||||
|
||||
Playwright now allows to supply client-side certificates, so that server can verify them, as specified by TLS Client Authentication.
|
||||
|
||||
You can provide client certificates as a parameter of [`method: Browser.newContext`] and [`method: APIRequest.newContext`]. The following snippet sets up a client certificate for `https://example.com`:
|
||||
|
||||
```python
|
||||
context = browser.new_context(
|
||||
client_certificates=[
|
||||
{
|
||||
"origin": "https://example.com",
|
||||
"certPath": "client-certificates/cert.pem",
|
||||
"keyPath": "client-certificates/key.pem",
|
||||
}
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
### Trace Viewer Updates
|
||||
|
||||
- Content of text attachments is now rendered inline in the attachments pane.
|
||||
- New setting to show/hide routing actions like [`method: Route.continue`].
|
||||
- Request method and status are shown in the network details tab.
|
||||
- New button to copy source file location to clipboard.
|
||||
- Metadata pane now displays the `base_url`.
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
- New `maxRetries` option in [`method: APIRequestContext.fetch`] which retries on the `ECONNRESET` network error.
|
||||
|
||||
### Browser Versions
|
||||
|
||||
- Chromium 128.0.6613.18
|
||||
- Mozilla Firefox 128.0
|
||||
- WebKit 18.0
|
||||
|
||||
This version was also tested against the following stable channels:
|
||||
|
||||
- Google Chrome 127
|
||||
- Microsoft Edge 127
|
||||
|
||||
|
||||
## Version 1.45
|
||||
|
||||
### Clock
|
||||
|
|
@ -969,7 +1044,7 @@ This version was also tested against the following stable channels:
|
|||
|
||||
- We now ship a designated Python docker image `mcr.microsoft.com/playwright/python`. Please switch over to it if you use
|
||||
Python. This is the last release that includes Python inside our javascript `mcr.microsoft.com/playwright` docker image.
|
||||
- v1.20 is the last release to receive WebKit update for macOS 10.15 Catalina. Please update MacOS to keep using latest & greatest WebKit!
|
||||
- v1.20 is the last release to receive WebKit update for macOS 10.15 Catalina. Please update macOS to keep using latest & greatest WebKit!
|
||||
|
||||
### Browser Versions
|
||||
|
||||
|
|
@ -1433,7 +1508,7 @@ This version of Playwright was also tested against the following stable channels
|
|||
|
||||
#### New APIs
|
||||
|
||||
- [`browserType.launch()`](./api/class-browsertype#browsertypelaunchoptions) now accepts the new `'channel'` option. Read more in [our documentation](./browsers).
|
||||
- [`method: BrowserType.launch`] now accepts the new `'channel'` option. Read more in [our documentation](./browsers).
|
||||
|
||||
|
||||
## Version 1.9
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ await Page.ScreenshotAsync(new()
|
|||
|
||||
[Screenshots API](./api/class-page#page-screenshot) accepts many parameters for image format, clip area, quality, etc. Make sure to check them out.
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
## Full page screenshots
|
||||
|
||||
Full page screenshot is a screenshot of a full scrollable page, as if you had a very
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ Playwright's inspection and routing of requests made by Service Workers are **ex
|
|||
|
||||
Set the `PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS` environment variable to `1` (or any other value) to enable the feature. Only Chrome/Chromium are currently supported.
|
||||
|
||||
If you're using (or are interested in using this this feature), please comment on [this issue](https://github.com/microsoft/playwright/issues/15684) letting us know your use case.
|
||||
If you're using (or are interested in using this feature), please comment on [this issue](https://github.com/microsoft/playwright/issues/15684) letting us know your use case.
|
||||
|
||||
## Service Worker Fetch
|
||||
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ You can also filter tests in the configuration file via [`property: TestConfig.g
|
|||
|
||||
## Annotate tests
|
||||
|
||||
If you would like to annotate your tests with something more substantial than a tag, you can do that when declaring a test. Annotations have a `type` and a `description` for more context, and will be visible in the test report.
|
||||
If you would like to annotate your tests with something more substantial than a tag, you can do that when declaring a test. Annotations have a `type` and a `description` for more context and available in reporter API. Playwright's built-in HTML reporter shows all annotations, except those where `type` starts with `_` symbol.
|
||||
|
||||
For example, to annotate a test with an issue url:
|
||||
|
||||
|
|
|
|||
35
docs/src/test-api/class-testinfoerror-matcherresult.md
Normal file
35
docs/src/test-api/class-testinfoerror-matcherresult.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# class: TestInfoErrorMatcherResult
|
||||
* since: v1.48
|
||||
* langs: js
|
||||
|
||||
Matcher-specific details for the error thrown during the `expect` call.
|
||||
|
||||
## property: TestInfoErrorMatcherResult.actual
|
||||
* since: v1.48
|
||||
- type: ?<[unknown]>
|
||||
|
||||
Actual value.
|
||||
|
||||
## property: TestInfoErrorMatcherResult.expected
|
||||
* since: v1.48
|
||||
- type: ?<[unknown]>
|
||||
|
||||
Expected value.
|
||||
|
||||
## property: TestInfoErrorMatcherResult.name
|
||||
* since: v1.48
|
||||
- type: ?<[string]>
|
||||
|
||||
Matcher name.
|
||||
|
||||
## property: TestInfoErrorMatcherResult.pass
|
||||
* since: v1.48
|
||||
- type: <[string]>
|
||||
|
||||
Whether the matcher passed.
|
||||
|
||||
## property: TestInfoErrorMatcherResult.timeout
|
||||
* since: v1.48
|
||||
- type: ?<[int]>
|
||||
|
||||
Timeout that was used during matching.
|
||||
|
|
@ -4,6 +4,12 @@
|
|||
|
||||
Information about an error thrown during test execution.
|
||||
|
||||
## property: TestInfoError.matcherResult
|
||||
* since: v1.48
|
||||
- type: ?<[TestInfoErrorMatcherResult]>
|
||||
|
||||
Matcher result details.
|
||||
|
||||
## property: TestInfoError.message
|
||||
* since: v1.10
|
||||
- type: ?<[string]>
|
||||
|
|
|
|||
|
|
@ -138,6 +138,27 @@ export default defineConfig({
|
|||
]
|
||||
});
|
||||
```
|
||||
|
||||
## property: TestOptions.clientCertificates = %%-context-option-clientCertificates-%%
|
||||
* since: 1.46
|
||||
|
||||
**Usage**
|
||||
|
||||
```js title="playwright.config.ts"
|
||||
import { defineConfig } from '@playwright/test';
|
||||
|
||||
export default defineConfig({
|
||||
use: {
|
||||
clientCertificates: [{
|
||||
origin: 'https://example.com',
|
||||
certPath: './cert.pem',
|
||||
keyPath: './key.pem',
|
||||
passphrase: 'mysecretpassword',
|
||||
}],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## property: TestOptions.colorScheme = %%-context-option-colorscheme-%%
|
||||
* since: v1.10
|
||||
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ Use [`property: TestConfig.repeatEach`] to change this option for all projects.
|
|||
* since: v1.45
|
||||
- type: ?<[boolean]>
|
||||
|
||||
Whether to skip entries from `.gitignore` when searching for test files. By default, if neither [`property: TestConfig.testDir`] nor [`property: TestProject.testDir`] are explicitely specified, Playwright will ignore any test files matching `.gitignore` entries. This option allows to override that behavior.
|
||||
Whether to skip entries from `.gitignore` when searching for test files. By default, if neither [`property: TestConfig.testDir`] nor [`property: TestProject.testDir`] are explicitly specified, Playwright will ignore any test files matching `.gitignore` entries. This option allows to override that behavior.
|
||||
|
||||
## property: TestProject.retries
|
||||
* since: v1.10
|
||||
|
|
|
|||
|
|
@ -308,6 +308,8 @@ test('amount', async () => {
|
|||
});
|
||||
```
|
||||
|
||||
### Compatibility with expect library
|
||||
|
||||
:::note
|
||||
Do not confuse Playwright's `expect` with the [`expect` library](https://jestjs.io/docs/expect). The latter is not fully integrated with Playwright test runner, so make sure to use Playwright's own `expect`.
|
||||
:::
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ Complete set of Playwright Test options is available in the [configuration file]
|
|||
| `--max-failures <N>` or `-x`| Stop after the first `N` test failures. Passing `-x` stops after the first failure.|
|
||||
| `--no-deps` | Ignore the dependencies between projects and behave as if they were not specified. |
|
||||
| `--output <dir>` | Directory for artifacts produced by tests, defaults to `test-results`. |
|
||||
| `--only-changed [ref]` | Only run test files that have been changed between working tree and "ref". Defaults to running all uncommitted changes with ref=HEAD. Only supports Git. |
|
||||
| `--pass-with-no-tests` | Allows the test suite to pass when no files are found. |
|
||||
| `--project <name>` | Only run tests from the specified [projects](./test-projects.md), supports '*' wildcard. Defaults to running all projects defined in the configuration file.|
|
||||
| `--quiet` | Whether to suppress stdout and stderr from the tests. |
|
||||
|
|
@ -102,5 +103,6 @@ Complete set of Playwright Test options is available in the [configuration file]
|
|||
| `--shard <shard>` | [Shard](./test-parallel.md#shard-tests-between-multiple-machines) tests and execute only selected shard, specified in the form `current/all`, 1-based, for example `3/5`.|
|
||||
| `--timeout <number>` | Maximum timeout in milliseconds for each test, defaults to 30 seconds. Learn more about [various timeouts](./test-timeouts.md).|
|
||||
| `--trace <mode>` | Force tracing mode, can be `on`, `off`, `on-first-retry`, `on-all-retries`, `retain-on-failure` |
|
||||
| `--tsconfig <path>` | Path to a single tsconfig applicable to all imported files. See [tsconfig resolution](./test-typescript.md#tsconfig-resolution) for more details. |
|
||||
| `--update-snapshots` or `-u` | Whether to update [snapshots](./test-snapshots.md) with actual results instead of comparing them. Use this when snapshot expectations have changed.|
|
||||
| `--workers <number>` or `-j <number>`| The maximum number of concurrent worker processes that run in [parallel](./test-parallel.md). |
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ test('slot', async ({ mount }) => {
|
|||
|
||||
### hooks
|
||||
|
||||
You can use `beforeMount` and `afterMount` hooks to configure your app. This lets you setup things like your app router, fake server etc. giving you the flexibility you need. You can also pass custom configuration from the `mount` call from a test, which is accessible from the `hooksConfig` fixture. This includes any config that needs to be run before or after mounting the component. An example of configuring a router is provided below:
|
||||
You can use `beforeMount` and `afterMount` hooks to configure your app. This lets you set up things like your app router, fake server etc. giving you the flexibility you need. You can also pass custom configuration from the `mount` call from a test, which is accessible from the `hooksConfig` fixture. This includes any config that needs to be run before or after mounting the component. An example of configuring a router is provided below:
|
||||
|
||||
<Tabs
|
||||
defaultValue="react"
|
||||
|
|
@ -697,7 +697,7 @@ test('update', async ({ mount }) => {
|
|||
|
||||
```js
|
||||
test('update', async ({ mount }) => {
|
||||
const component = await mount(<Component/>);
|
||||
const component = await mount(Component);
|
||||
await component.update({
|
||||
props: { msg: 'greetings' },
|
||||
on: { callback: () => {} },
|
||||
|
|
@ -711,7 +711,7 @@ test('update', async ({ mount }) => {
|
|||
|
||||
```js
|
||||
test('update', async ({ mount }) => {
|
||||
const component = await mount(<Component/>);
|
||||
const component = await mount(Component);
|
||||
await component.update({
|
||||
props: { msg: 'greetings' },
|
||||
on: { callback: () => {} },
|
||||
|
|
@ -724,6 +724,43 @@ test('update', async ({ mount }) => {
|
|||
|
||||
</Tabs>
|
||||
|
||||
### Handling network requests
|
||||
|
||||
Playwright provides an **experimental** `router` fixture to intercept and handle network requests. There are two ways to use the `router` fixture:
|
||||
* Call `router.route(url, handler)` that behaves similarly to [`method: Page.route`]. See the [network mocking guide](./mock.md) for more details.
|
||||
* Call `router.use(handlers)` and pass [MSW library](https://mswjs.io/) request handlers to it.
|
||||
|
||||
Here is an example of reusing your existing MSW handlers in the test.
|
||||
|
||||
```ts
|
||||
import { handlers } from '@src/mocks/handlers';
|
||||
|
||||
test.beforeEach(async ({ router }) => {
|
||||
// install common handlers before each test
|
||||
await router.use(...handlers);
|
||||
});
|
||||
|
||||
test('example test', async ({ mount }) => {
|
||||
// test as usual, your handlers are active
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
You can also introduce a one-off handler for a specific test.
|
||||
|
||||
```ts
|
||||
import { http, HttpResponse } from 'msw';
|
||||
|
||||
test('example test', async ({ mount, router }) => {
|
||||
await router.use(http.get('/data', async ({ request }) => {
|
||||
return HttpResponse.json({ value: 'mocked' });
|
||||
}));
|
||||
|
||||
// test as usual, your handler is active
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
## Frequently asked questions
|
||||
|
||||
### What's the difference between `@playwright/test` and `@playwright/experimental-ct-{react,svelte,vue,solid}`?
|
||||
|
|
|
|||
|
|
@ -454,10 +454,6 @@ test('example test', async ({ slowFixture }) => {
|
|||
|
||||
## Fixtures-options
|
||||
|
||||
:::note
|
||||
Overriding custom fixtures in the config file has changed in version 1.18. [Learn more](./release-notes#breaking-change-custom-config-options).
|
||||
:::
|
||||
|
||||
Playwright Test supports running multiple test projects that can be separately configured. You can use "option" fixtures to make your configuration options declarative and type-checked. Learn more about [parametrizing tests](./test-parameterize.md).
|
||||
|
||||
Below we'll create a `defaultItem` option in addition to the `todoPage` fixture from other examples. This option will be set in configuration file. Note the tuple syntax and `{ option: true }` argument.
|
||||
|
|
@ -555,6 +551,30 @@ export default defineConfig<MyOptions>({
|
|||
});
|
||||
```
|
||||
|
||||
**Array as an option value**
|
||||
|
||||
If the value of your option is an array, for example `[{ name: 'Alice' }, { name: 'Bob' }]`, you'll need to wrap it into an extra array when providing the value. This is best illustrated with an example.
|
||||
|
||||
```js
|
||||
type Person = { name: string };
|
||||
const test = base.extend<{ persons: Person[] }>({
|
||||
// Declare the option, default value is an empty array.
|
||||
persons: [[], { option: true }],
|
||||
});
|
||||
|
||||
// Option value is an array of persons.
|
||||
const actualPersons = [{ name: 'Alice' }, { name: 'Bob' }];
|
||||
test.use({
|
||||
// CORRECT: Wrap the value into an array and pass the scope.
|
||||
persons: [actualPersons, { scope: 'test' }],
|
||||
});
|
||||
|
||||
test.use({
|
||||
// WRONG: passing an array value directly will not work.
|
||||
persons: actualPersons,
|
||||
});
|
||||
```
|
||||
|
||||
## Execution order
|
||||
|
||||
Each fixture has a setup and teardown phase separated by the `await use()` call in the fixture. Setup is executed before the fixture is used by the test/hook, and teardown is executed when the fixture will not be used by the test/hook anymore.
|
||||
|
|
@ -675,27 +695,91 @@ test('passes', async ({ database, page, a11y }) => {
|
|||
|
||||
## Box fixtures
|
||||
|
||||
You can minimize the fixture exposure to the reporters UI and error messages via boxing it:
|
||||
Usually, custom fixtures are reported as separate steps in in the UI mode, Trace Viewer and various test reports. They also appear in error messages from the test runner. For frequently-used fixtures, this can mean lots of noise. You can stop the fixtures steps from being shown in the UI by "boxing" it.
|
||||
|
||||
```js
|
||||
import { test as base } from '@playwright/test';
|
||||
|
||||
export const test = base.extend({
|
||||
_helperFixture: [async ({}, use, testInfo) => {
|
||||
helperFixture: [async ({}, use, testInfo) => {
|
||||
// ...
|
||||
}, { box: true }],
|
||||
});
|
||||
```
|
||||
|
||||
This is useful for non-interesting helper fixtures. For example, an [automatic](./test-fixtures.md#automatic-fixtures) fixture that sets up some common data can be safely hidden from a test report.
|
||||
|
||||
## Custom fixture title
|
||||
|
||||
You can assign a custom title to a fixture to be used in error messages and in the
|
||||
reporters UI:
|
||||
Instead of the usual fixture name, you can give fixtures a custom title that will be shown in test reports and error messages.
|
||||
|
||||
```js
|
||||
import { test as base } from '@playwright/test';
|
||||
|
||||
export const test = base.extend({
|
||||
_innerFixture: [async ({}, use, testInfo) => {
|
||||
innerFixture: [async ({}, use, testInfo) => {
|
||||
// ...
|
||||
}, { title: 'my fixture' }],
|
||||
});
|
||||
```
|
||||
|
||||
## Adding global beforeEach/afterEach hooks
|
||||
|
||||
[`method: Test.beforeEach`] and [`method: Test.afterEach`] hooks run before/after each test declared in the same file and same [`method: Test.describe`] block (if any). If you want to declare hooks that run before/after each test globally, you can declare them as auto fixtures like this:
|
||||
|
||||
```ts title="fixtures.ts"
|
||||
import { test as base } from '@playwright/test';
|
||||
|
||||
export const test = base.extend<{ forEachTest: void }>({
|
||||
forEachTest: [async ({ page }, use) => {
|
||||
// This code runs before every test.
|
||||
await page.goto('http://localhost:8000');
|
||||
await use();
|
||||
// This code runs after every test.
|
||||
console.log('Last URL:', page.url());
|
||||
}, { auto: true }], // automatically starts for every test.
|
||||
});
|
||||
```
|
||||
|
||||
And then import the fixtures in all your tests:
|
||||
|
||||
```ts title="mytest.spec.ts"
|
||||
import { test } from './fixtures';
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
test('basic', async ({ page }) => {
|
||||
expect(page).toHaveURL('http://localhost:8000');
|
||||
await page.goto('https://playwright.dev');
|
||||
});
|
||||
```
|
||||
|
||||
## Adding global beforeAll/afterAll hooks
|
||||
|
||||
[`method: Test.beforeAll`] and [`method: Test.afterAll`] hooks run before/after all tests declared in the same file and same [`method: Test.describe`] block (if any), once per worker process. If you want to declare hooks
|
||||
that run before/after all tests in every file, you can declare them as auto fixtures with `scope: 'worker'` as follows:
|
||||
|
||||
```ts title="fixtures.ts"
|
||||
import { test as base } from '@playwright/test';
|
||||
|
||||
export const test = base.extend<{}, { forEachWorker: void }>({
|
||||
forEachWorker: [async ({}, use) => {
|
||||
// This code runs before all the tests in the worker process.
|
||||
console.log(`Starting test worker ${test.info().workerIndex}`);
|
||||
await use();
|
||||
// This code runs after all the tests in the worker process.
|
||||
console.log(`Stopping test worker ${test.info().workerIndex}`);
|
||||
}, { scope: 'worker', auto: true }], // automatically starts for every worker.
|
||||
});
|
||||
```
|
||||
|
||||
And then import the fixtures in all your tests:
|
||||
|
||||
```ts title="mytest.spec.ts"
|
||||
import { test } from './fixtures';
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
test('basic', async ({ }) => {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
Note that the fixtures will still run once per [worker process](./test-parallel.md#worker-processes), but you don't need to redeclare them in every file.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ test.afterEach(async ({ page }) => {
|
|||
});
|
||||
```
|
||||
|
||||
If you want to have hooks for each test, you can put them inside a `describe()` - so they are executed for each iteration / each invidual test:
|
||||
If you want to have hooks for each test, you can put them inside a `describe()` - so they are executed for each iteration / each individual test:
|
||||
|
||||
```js title="example.spec.ts"
|
||||
[
|
||||
|
|
|
|||
35
docs/src/test-reporter-api/class-testerror-matcherresult.md
Normal file
35
docs/src/test-reporter-api/class-testerror-matcherresult.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# class: TestErrorMatcherResult
|
||||
* since: v1.48
|
||||
* langs: js
|
||||
|
||||
Matcher-specific details for the error thrown during the `expect` call.
|
||||
|
||||
## property: TestErrorMatcherResult.actual
|
||||
* since: v1.48
|
||||
- type: ?<[unknown]>
|
||||
|
||||
Actual value.
|
||||
|
||||
## property: TestErrorMatcherResult.expected
|
||||
* since: v1.48
|
||||
- type: ?<[unknown]>
|
||||
|
||||
Expected value.
|
||||
|
||||
## property: TestErrorMatcherResult.name
|
||||
* since: v1.48
|
||||
- type: ?<[string]>
|
||||
|
||||
Matcher name.
|
||||
|
||||
## property: TestErrorMatcherResult.pass
|
||||
* since: v1.48
|
||||
- type: <[string]>
|
||||
|
||||
Whether the matcher passed.
|
||||
|
||||
## property: TestErrorMatcherResult.timeout
|
||||
* since: v1.48
|
||||
- type: ?<[int]>
|
||||
|
||||
Timeout that was used during matching.
|
||||
|
|
@ -4,6 +4,12 @@
|
|||
|
||||
Information about an error thrown during test execution.
|
||||
|
||||
## property: TestError.matcherResult
|
||||
* since: v1.48
|
||||
- type: ?<[TestErrorMatcherResult]>
|
||||
|
||||
Matcher result details.
|
||||
|
||||
## property: TestError.message
|
||||
* since: v1.10
|
||||
- type: ?<[string]>
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ List report supports the following configuration options and environment variabl
|
|||
| Environment Variable Name | Reporter Config Option| Description | Default
|
||||
|---|---|---|---|
|
||||
| `PLAYWRIGHT_LIST_PRINT_STEPS` | `printSteps` | Whether to print each step on its own line. | `false`
|
||||
| `PLAYWRIGHT_FORCE_TTY` | | Whether to produce output suitable for a live terminal. | `true` when terminal is in TTY mode, `false` otherwise.
|
||||
| `PLAYWRIGHT_FORCE_TTY` | | Whether to produce output suitable for a live terminal. If a number is specified, it will also be used as the terminal width. | `true` when terminal is in TTY mode, `false` otherwise.
|
||||
| `FORCE_COLOR` | | Whether to produce colored output. | `true` when terminal is in TTY mode, `false` otherwise.
|
||||
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ Line report supports the following configuration options and environment variabl
|
|||
|
||||
| Environment Variable Name | Reporter Config Option| Description | Default
|
||||
|---|---|---|---|
|
||||
| `PLAYWRIGHT_FORCE_TTY` | | Whether to produce output suitable for a live terminal. | `true` when terminal is in TTY mode, `false` otherwise.
|
||||
| `PLAYWRIGHT_FORCE_TTY` | | Whether to produce output suitable for a live terminal. If a number is specified, it will also be used as the terminal width. | `true` when terminal is in TTY mode, `false` otherwise.
|
||||
| `FORCE_COLOR` | | Whether to produce colored output. | `true` when terminal is in TTY mode, `false` otherwise.
|
||||
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ Dot report supports the following configuration options and environment variable
|
|||
|
||||
| Environment Variable Name | Reporter Config Option| Description | Default
|
||||
|---|---|---|---|
|
||||
| `PLAYWRIGHT_FORCE_TTY` | | Whether to produce output suitable for a live terminal. | `true` when terminal is in TTY mode, `false` otherwise.
|
||||
| `PLAYWRIGHT_FORCE_TTY` | | Whether to produce output suitable for a live terminal. If a number is specified, it will also be used as the terminal width. | `true` when terminal is in TTY mode, `false` otherwise.
|
||||
| `FORCE_COLOR` | | Whether to produce colored output. | `true` when terminal is in TTY mode, `false` otherwise.
|
||||
|
||||
### HTML reporter
|
||||
|
|
@ -429,6 +429,8 @@ npx playwright test --reporter="./myreporter/my-awesome-reporter.ts"
|
|||
* [Currents](https://www.npmjs.com/package/@currents/playwright)
|
||||
* [GitHub Actions Reporter](https://www.npmjs.com/package/@estruyf/github-actions-reporter)
|
||||
* [GitHub Pull Request Comment](https://github.com/marketplace/actions/playwright-report-comment)
|
||||
* [Mail Reporter](https://www.npmjs.com/package/playwright-mail-reporter)
|
||||
* [Microsoft Teams Reporter](https://www.npmjs.com/package/playwright-msteams-reporter)
|
||||
* [Monocart](https://github.com/cenfun/monocart-reporter)
|
||||
* [ReportPortal](https://github.com/reportportal/agent-js-playwright)
|
||||
* [Serenity/JS](https://serenity-js.org/handbook/test-runners/playwright-test)
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ Playwright and Browser instances can be reused between tests for better performa
|
|||
recommend running each test case in a new BrowserContext, this way browser state will be
|
||||
isolated between the tests.
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
## JUnit
|
||||
|
||||
In [JUnit](https://junit.org/junit5/) you can initialize [Playwright] and [Browser] in [@BeforeAll](https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/BeforeAll.html) method and
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ title: "TypeScript"
|
|||
|
||||
## Introduction
|
||||
|
||||
Playwright supports TypeScript out of the box. You just write tests in TypeScript, and Playwright will read them, transform to JavaScript and run. Note that Playwright does not check the types and will run tests even if there are non-critical TypeScript compilation errors.
|
||||
Playwright supports TypeScript out of the box. You just write tests in TypeScript, and Playwright will read them, transform to JavaScript and run.
|
||||
|
||||
We recommend you run TypeScript compiler alongside Playwright. For example on GitHub actions:
|
||||
Note that Playwright does not check the types and will run tests even if there are non-critical TypeScript compilation errors. We recommend you run TypeScript compiler alongside Playwright. For example on GitHub actions:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
|
|
@ -28,7 +28,7 @@ npx tsc -p tsconfig.json --noEmit -w
|
|||
|
||||
## tsconfig.json
|
||||
|
||||
Playwright will pick up `tsconfig.json` for each source file it loads. Note that Playwright **only supports** the following tsconfig options: `paths` and `baseUrl`.
|
||||
Playwright will pick up `tsconfig.json` for each source file it loads. Note that Playwright **only supports** the following tsconfig options: `allowJs`, `baseUrl`, `paths` and `references`.
|
||||
|
||||
We recommend setting up a separate `tsconfig.json` in the tests directory so that you can change some preferences specifically for the tests. Here is an example directory structure.
|
||||
|
||||
|
|
@ -49,12 +49,12 @@ playwright.config.ts
|
|||
|
||||
Playwright supports [path mapping](https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping) declared in the `tsconfig.json`. Make sure that `baseUrl` is also set.
|
||||
|
||||
Here is an example `tsconfig.json` that works with Playwright Test:
|
||||
Here is an example `tsconfig.json` that works with Playwright:
|
||||
|
||||
```json
|
||||
```json title="tsconfig.json"
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".", // This must be specified if "paths" is.
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@myhelper/*": ["packages/myhelper/*"] // This mapping is relative to "baseUrl".
|
||||
}
|
||||
|
|
@ -74,6 +74,22 @@ test('example', async ({ page }) => {
|
|||
});
|
||||
```
|
||||
|
||||
### tsconfig resolution
|
||||
|
||||
By default, Playwright will look up a closest tsconfig for each imported file by going up the directory structure and looking for `tsconfig.json` or `jsconfig.json`. This way, you can create a `tests/tsconfig.json` file that will be used only for your tests and Playwright will pick it up automatically.
|
||||
|
||||
```sh
|
||||
# Playwright will choose tsconfig automatically
|
||||
npx playwright test
|
||||
```
|
||||
|
||||
Alternatively, you can specify a single tsconfig file to use in the command line, and Playwright will use it for all imported files, not only test files.
|
||||
|
||||
```sh
|
||||
# Pass a specific tsconfig
|
||||
npx playwright test --tsconfig=tsconfig.test.json
|
||||
```
|
||||
|
||||
## Manually compile tests with TypeScript
|
||||
|
||||
Sometimes, Playwright Test will not be able to transform your TypeScript code correctly, for example when you are using experimental or very recent features of TypeScript, usually configured in `tsconfig.json`.
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Playwright Trace Viewer is a GUI tool that lets you explore recorded Playwright
|
|||
- [How to open and view the trace](/trace-viewer-intro.md#opening-the-trace)
|
||||
|
||||
<LiteYouTube
|
||||
id="lfxjs--9ZQs"
|
||||
id="yP6AnTxC34s"
|
||||
title="Viewing Playwright Traces"
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import LiteYouTube from '@site/src/components/LiteYouTube';
|
|||
|
||||
## Introduction
|
||||
|
||||
Playwright Trace Viewer is a GUI tool that helps you explore recorded Playwright traces after the script has ran. Traces are a great way for debugging your tests when they fail on CI. You can open traces [locally](#opening-the-trace) or in your browser on [trace.playwright.dev](https://trace.playwright.dev).
|
||||
Playwright Trace Viewer is a GUI tool that helps you explore recorded Playwright traces after the script has run. Traces are a great way for debugging your tests when they fail on CI. You can open traces [locally](#opening-the-trace) or in your browser on [trace.playwright.dev](https://trace.playwright.dev).
|
||||
|
||||
######
|
||||
* langs: js
|
||||
|
||||
<LiteYouTube
|
||||
id="lfxjs--9ZQs"
|
||||
id="yP6AnTxC34s"
|
||||
title="Viewing Playwright Traces"
|
||||
/>
|
||||
|
||||
|
|
@ -493,7 +493,7 @@ pwsh bin/Debug/netX/playwright.ps1 show-trace trace.zip
|
|||
|
||||
## Viewing remote traces
|
||||
|
||||
You can open remote traces using it's URL. They could be generated on a CI run which makes it easy to view the remote trace without having to manually download the file.
|
||||
You can open remote traces using its URL. They could be generated on a CI run which makes it easy to view the remote trace without having to manually download the file.
|
||||
|
||||
```bash js
|
||||
npx playwright show-trace https://example.com/trace.zip
|
||||
|
|
|
|||
1473
package-lock.json
generated
1473
package-lock.json
generated
File diff suppressed because it is too large
Load diff
26
package.json
26
package.json
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "playwright-internal",
|
||||
"private": true,
|
||||
"version": "1.46.0-next",
|
||||
"version": "1.48.0-next",
|
||||
"description": "A high-level API to automate web browsers",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
@ -24,13 +24,14 @@
|
|||
"webview2test": "playwright test --config=tests/webview2/playwright.config.ts",
|
||||
"itest": "playwright test --config=tests/installation/playwright.config.ts",
|
||||
"stest": "playwright test --config=tests/stress/playwright.config.ts",
|
||||
"biditest": "playwright test --config=tests/bidi/playwright.config.ts",
|
||||
"test-html-reporter": "playwright test --config=packages/html-reporter",
|
||||
"test-web": "playwright test --config=packages/web",
|
||||
"ttest": "node ./tests/playwright-test/stable-test-runner/node_modules/@playwright/test/cli test --config=tests/playwright-test/playwright.config.ts",
|
||||
"ct": "playwright test tests/components/test-all.spec.js --reporter=list",
|
||||
"test": "playwright test --config=tests/library/playwright.config.ts",
|
||||
"eslint": "eslint --cache --report-unused-disable-directives --ext ts,tsx,js,jsx,mjs .",
|
||||
"tsc": "tsc -p .",
|
||||
"tsc": "tsc -p . && tsc -p packages/html-reporter/",
|
||||
"build-installer": "babel -s --extensions \".ts\" --out-dir packages/playwright-core/lib/utils/ packages/playwright-core/src/utils",
|
||||
"doc": "node utils/doclint/cli.js",
|
||||
"lint": "npm run eslint && npm run tsc && npm run doc && npm run check-deps && node utils/generate_channels.js && node utils/generate_types/ && npm run lint-tests && npm run test-types && npm run lint-packages",
|
||||
|
|
@ -64,41 +65,38 @@
|
|||
"@types/babel__core": "^7.20.2",
|
||||
"@types/codemirror": "^5.60.7",
|
||||
"@types/formidable": "^2.0.4",
|
||||
"@types/node": "^18.15.3",
|
||||
"@types/node": "^18.19.39",
|
||||
"@types/react": "^18.0.12",
|
||||
"@types/react-dom": "^18.0.5",
|
||||
"@types/resize-observer-browser": "^0.1.7",
|
||||
"@types/ws": "^8.5.3",
|
||||
"@types/xml2js": "^0.4.9",
|
||||
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
||||
"@typescript-eslint/parser": "^6.13.2",
|
||||
"@typescript-eslint/utils": "^6.13.2",
|
||||
"@typescript-eslint/eslint-plugin": "^7.15.0",
|
||||
"@typescript-eslint/parser": "^7.15.0",
|
||||
"@typescript-eslint/utils": "^7.15.0",
|
||||
"@vitejs/plugin-basic-ssl": "^1.1.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"@zip.js/zip.js": "^2.7.29",
|
||||
"chokidar": "^3.5.3",
|
||||
"chromium-bidi": "^0.6.4",
|
||||
"colors": "^1.4.0",
|
||||
"commonmark": "^0.30.0",
|
||||
"concurrently": "^6.2.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"dotenv": "^16.0.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"electron": "^30.1.2",
|
||||
"enquirer": "^2.3.6",
|
||||
"esbuild": "^0.18.11",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-plugin-internal-playwright": "file:utils/eslint-plugin-internal-playwright",
|
||||
"eslint-plugin-notice": "^0.9.10",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-react": "^7.35.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"formidable": "^2.1.1",
|
||||
"license-checker": "^25.0.1",
|
||||
"mime": "^3.0.0",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"socksv5": "0.0.6",
|
||||
"ssim.js": "^3.5.0",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript": "^5.5.3",
|
||||
"vite": "^5.0.13",
|
||||
"ws": "^8.17.1",
|
||||
"xml2js": "^0.5.0",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs, { existsSync } from 'fs';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import type { Plugin, UserConfig } from 'vite';
|
||||
|
||||
|
|
@ -26,14 +26,14 @@ export function bundle(): Plugin {
|
|||
config = c;
|
||||
},
|
||||
transformIndexHtml: {
|
||||
transform(html, ctx) {
|
||||
handler(html, ctx) {
|
||||
if (!ctx || !ctx.bundle)
|
||||
return html;
|
||||
html = html.replace(/(?=<!--)([\s\S]*?)-->/, '');
|
||||
for (const [name, value] of Object.entries(ctx.bundle) as any) {
|
||||
for (const [name, value] of Object.entries(ctx.bundle)) {
|
||||
if (name.endsWith('.map'))
|
||||
continue;
|
||||
if (value.code)
|
||||
if ('code' in value)
|
||||
html = html.replace(/<script type="module".*<\/script>/, () => `<script type="module">${value.code}</script>`);
|
||||
else
|
||||
html = html.replace(/<link rel="stylesheet"[^>]*>/, () => `<style type='text/css'>${value.source}</style>`);
|
||||
|
|
@ -42,7 +42,7 @@ export function bundle(): Plugin {
|
|||
},
|
||||
},
|
||||
closeBundle: () => {
|
||||
if (existsSync(path.join(config.build!.outDir!, 'index.html'))) {
|
||||
if (fs.existsSync(path.join(config.build!.outDir!, 'index.html'))) {
|
||||
const targetDir = path.join(__dirname, '..', 'playwright-core', 'lib', 'vite', 'htmlReport');
|
||||
fs.mkdirSync(targetDir, { recursive: true });
|
||||
fs.copyFileSync(
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
"name": "html-reporter",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build && tsc",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
import { devices, defineConfig } from '@playwright/experimental-ct-react';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
|
||||
export default defineConfig({
|
||||
testDir: 'src',
|
||||
|
|
@ -28,7 +29,7 @@ export default defineConfig({
|
|||
ctViteConfig: {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@web': path.resolve(__dirname, '../web/src'),
|
||||
'@web': path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), '../web/src'),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import './chip.css';
|
|||
import './colors.css';
|
||||
import './common.css';
|
||||
import * as icons from './icons';
|
||||
import { clsx } from '@web/uiUtils';
|
||||
|
||||
export const Chip: React.FC<{
|
||||
header: JSX.Element | string,
|
||||
|
|
@ -31,14 +32,14 @@ export const Chip: React.FC<{
|
|||
}> = ({ header, expanded, setExpanded, children, noInsets, dataTestId, targetRef }) => {
|
||||
return <div className='chip' data-testid={dataTestId} ref={targetRef}>
|
||||
<div
|
||||
className={'chip-header' + (setExpanded ? ' expanded-' + expanded : '')}
|
||||
className={clsx('chip-header', setExpanded && ' expanded-' + expanded)}
|
||||
onClick={() => setExpanded?.(!expanded)}
|
||||
title={typeof header === 'string' ? header : undefined}>
|
||||
{setExpanded && !!expanded && icons.downArrow()}
|
||||
{setExpanded && !expanded && icons.rightArrow()}
|
||||
{header}
|
||||
</div>
|
||||
{(!setExpanded || expanded) && <div className={'chip-body' + (noInsets ? ' chip-body-no-insets' : '')}>{children}</div>}
|
||||
{(!setExpanded || expanded) && <div className={clsx('chip-body', noInsets && 'chip-body-no-insets')}>{children}</div>}
|
||||
</div>;
|
||||
};
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue