Compare commits
12 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c6335edda | ||
|
|
29ec22b9c9 | ||
|
|
8f292e09bf | ||
|
|
270675a89f | ||
|
|
7b78e71433 | ||
|
|
c74c9a3690 | ||
|
|
c175d6fa8e | ||
|
|
7f74063549 | ||
|
|
d3e80664e8 | ||
|
|
c840a28946 | ||
|
|
82769c23de | ||
|
|
0b30dd2537 |
|
|
@ -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 -->
|
||||
|
||||
## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright)
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ Playwright is a framework for Web Testing and Automation. It allows testing [Chr
|
|||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->103.0.5060.53<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Chromium <!-- GEN:chromium-version -->104.0.5112.20<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->15.4<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Firefox <!-- GEN:firefox-version -->100.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
|
||||
|
|
|
|||
|
|
@ -1025,6 +1025,30 @@ handler function to route the request.
|
|||
|
||||
How often a route should be used. By default it will be used every time.
|
||||
|
||||
## async method: BrowserContext.routeFromHAR
|
||||
|
||||
If specified the network requests that are made in the context will be served from the HAR file. Read more about [Replaying from HAR](../network.md#replaying-from-har).
|
||||
|
||||
Playwright will not serve requests intercepted by Service Worker from the HAR file. See [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using request interception by setting [`option: Browser.newContext.serviceWorkers`] to `'block'`.
|
||||
|
||||
### param: BrowserContext.routeFromHAR.har
|
||||
- `har` <[path]>
|
||||
|
||||
Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a relative path, then it is resolved relative to the current working directory.
|
||||
|
||||
### option: BrowserContext.routeFromHAR.notFound
|
||||
- `notFound` ?<[HarNotFound]<"abort"|"fallback">>
|
||||
|
||||
* If set to 'abort' any request not found in the HAR file will be aborted.
|
||||
* If set to 'fallback' falls through to the next route handler in the handler chain.
|
||||
|
||||
Defaults to abort.
|
||||
|
||||
### option: BrowserContext.routeFromHAR.url
|
||||
- `url` <[string]|[RegExp]|[function]\([URL]\):[boolean]>
|
||||
|
||||
A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
|
||||
## method: BrowserContext.serviceWorkers
|
||||
* langs: js, python
|
||||
- returns: <[Array]<[Worker]>>
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ Maximum time in milliseconds to wait for the application to start. Defaults to `
|
|||
### option: Electron.launch.recordhar = %%-context-option-recordhar-%%
|
||||
### option: Electron.launch.recordharpath = %%-context-option-recordhar-path-%%
|
||||
### option: Electron.launch.recordHarOmitContent = %%-context-option-recordhar-omit-content-%%
|
||||
### option: Electron.launch.har = %%-js-context-option-har-%%
|
||||
### option: Electron.launch.recordvideo = %%-context-option-recordvideo-%%
|
||||
### option: Electron.launch.recordvideodir = %%-context-option-recordvideo-dir-%%
|
||||
### option: Electron.launch.recordvideosize = %%-context-option-recordvideo-size-%%
|
||||
|
|
|
|||
|
|
@ -2732,6 +2732,30 @@ handler function to route the request.
|
|||
|
||||
How often a route should be used. By default it will be used every time.
|
||||
|
||||
## async method: Page.routeFromHAR
|
||||
|
||||
If specified the network requests that are made in the page will be served from the HAR file. Read more about [Replaying from HAR](../network.md#replaying-from-har).
|
||||
|
||||
Playwright will not serve requests intercepted by Service Worker from the HAR file. See [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using request interception by setting [`option: Browser.newContext.serviceWorkers`] to `'block'`.
|
||||
|
||||
### param: Page.routeFromHAR.har
|
||||
- `har` <[path]>
|
||||
|
||||
Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a relative path, then it is resolved relative to the current working directory.
|
||||
|
||||
### option: Page.routeFromHAR.notFound
|
||||
- `notFound` ?<[HarNotFound]<"abort"|"fallback">>
|
||||
|
||||
* If set to 'abort' any request not found in the HAR file will be aborted.
|
||||
* If set to 'fallback' missing requests will be sent to the network.
|
||||
|
||||
Defaults to abort.
|
||||
|
||||
### option: Page.routeFromHAR.url
|
||||
- `url` <[string]|[RegExp]|[function]\([URL]\):[boolean]>
|
||||
|
||||
A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
|
||||
## async method: Page.screenshot
|
||||
- returns: <[Buffer]>
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@ Returns the [Frame] that initiated this request.
|
|||
## method: Request.headers
|
||||
- returns: <[Object]<[string], [string]>>
|
||||
|
||||
**DEPRECATED** Incomplete list of headers as seen by the rendering engine. Use [`method: Request.allHeaders`] instead.
|
||||
An object with the request HTTP headers. The header names are lower-cased.
|
||||
Note that this method does not return security-related headers, including cookie-related ones.
|
||||
You can use [`method: Request.allHeaders`] for complete list of headers that include `cookie` information.
|
||||
|
||||
## async method: Request.headersArray
|
||||
- returns: <[Array]<[Object]>>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ Indicates whether this Response was fullfilled by a Service Worker's Fetch Handl
|
|||
## method: Response.headers
|
||||
- returns: <[Object]<[string], [string]>>
|
||||
|
||||
**DEPRECATED** Incomplete list of headers as seen by the rendering engine. Use [`method: Response.allHeaders`] instead.
|
||||
An object with the response HTTP headers. The header names are lower-cased.
|
||||
Note that this method does not return security-related headers, including cookie-related ones.
|
||||
You can use [`method: Response.allHeaders`] for complete list of headers that include `cookie` information.
|
||||
|
||||
## async method: Response.headersArray
|
||||
- returns: <[Array]<[Object]>>
|
||||
|
|
|
|||
|
|
@ -247,37 +247,6 @@ The file path to save the storage state to. If [`option: path`] is a relative pa
|
|||
current working directory. If no path is provided, storage
|
||||
state is still returned, but won't be saved to the disk.
|
||||
|
||||
## js-context-option-har
|
||||
* langs: js, python
|
||||
- `har` <[Object]>
|
||||
- `path` <[path]> Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a relative path, then it is resolved relative to the current working directory.
|
||||
- `fallback` ?<[HarFallback]<"abort"|"continue">> If set to 'abort' any request not found in the HAR file will be aborted. If set to'continue' missing requests will be sent to the network. Defaults to 'abort'.
|
||||
- `urlFilter` ?<[string]|[RegExp]> A glob pattern or regular expression to match request URL while routing. Only requests with URL matching the pattern will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
|
||||
If specified the network requests that are made in the context will be served from the HAR file. Read more about [Replaying from HAR](../network.md#replaying-from-har).
|
||||
|
||||
:::note
|
||||
Playwright will not serve requests intercepted by Service Worker from the HAR file. See [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using request interception by setting [`option: Browser.newContext.serviceWorkers`] to `'block'`.
|
||||
:::
|
||||
|
||||
## csharp-java-python-context-option-har-path
|
||||
* langs: csharp, java, python
|
||||
- `harPath` <[path]>
|
||||
|
||||
Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If the HAR file contains an entry with the matching URL and HTTP method, then the entry's headers, status and body will be used to fulfill the network request. An entry resulting in a redirect will be followed automatically. If `path` is a relative path, then it is resolved relative to the current working directory.
|
||||
|
||||
## csharp-java-python-context-option-har-fallback
|
||||
* langs: csharp, java, python
|
||||
- `harFallback` ?<[HarFallback]<"abort"|"continue">>
|
||||
|
||||
If set to 'abort' any request not found in the HAR file will be aborted. If set to'continue' missing requests will be sent to the network. Defaults to 'abort'.
|
||||
|
||||
## csharp-java-python-context-option-har-urlfilter
|
||||
* langs: csharp, java, python
|
||||
- `harUrlFilter` ?<[string]|[RegExp]>
|
||||
|
||||
A glob pattern or regular expression to match request URL while routing. Only requests with URL matching the pattern will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
|
||||
## context-option-acceptdownloads
|
||||
- `acceptDownloads` <[boolean]>
|
||||
|
||||
|
|
@ -594,6 +563,7 @@ Logger sink for Playwright logging.
|
|||
`false`. Deprecated, use `content` policy instead.
|
||||
- `content` ?<[HarContentPolicy]<"omit"|"embed"|"attach">> Optional setting to control resource content management. If `omit` is specified, content is not persisted. If `attach` is specified, resources are persistet as separate files and all of these files are archived along with the HAR file. Defaults to `embed`, which stores content inline the HAR file as per HAR specification.
|
||||
- `path` <[path]> Path on the filesystem to write the HAR file to. If the file name ends with `.zip`, `attach` mode is used by default.
|
||||
- `mode` ?<[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`.
|
||||
- `urlFilter` ?<[string]|[RegExp]> A glob or regex pattern to filter requests that are stored in the HAR. When a [`option: baseURL`] via the context options was provided and the passed URL is a path, it gets merged via the [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor.
|
||||
|
||||
Enables [HAR](http://www.softwareishard.com/blog/har-12-spec) recording for all pages into `recordHar.path` file. If not
|
||||
|
|
@ -616,6 +586,20 @@ call [`method: BrowserContext.close`] for the HAR to be saved.
|
|||
|
||||
Optional setting to control whether to omit request content from the HAR. Defaults to `false`.
|
||||
|
||||
## context-option-recordhar-content
|
||||
* langs: csharp, java, python
|
||||
- alias-python: record_har_content
|
||||
- `recordHarContent` ?<[HarContentPolicy]<"omit"|"embed"|"attach">>
|
||||
|
||||
Optional setting to control resource content management. If `omit` is specified, content is not persisted. If `attach` is specified, resources are persistet as separate files and all of these files are archived along with the HAR file. Defaults to `embed`, which stores content inline the HAR file as per HAR specification.
|
||||
|
||||
## context-option-recordhar-mode
|
||||
* langs: csharp, java, python
|
||||
- alias-python: record_har_mode
|
||||
- `recordHarMode` ?<[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`.
|
||||
|
||||
## context-option-recordhar-url-filter
|
||||
* langs: csharp, java, python
|
||||
- alias-python: record_har_url_filter
|
||||
|
|
@ -834,13 +818,11 @@ An acceptable perceived color difference in the [YIQ color space](https://en.wik
|
|||
- %%-context-option-logger-%%
|
||||
- %%-context-option-videospath-%%
|
||||
- %%-context-option-videosize-%%
|
||||
- %%-js-context-option-har-%%
|
||||
- %%-csharp-java-python-context-option-har-path-%%
|
||||
- %%-csharp-java-python-context-option-har-fallback-%%
|
||||
- %%-csharp-java-python-context-option-har-urlfilter-%%
|
||||
- %%-context-option-recordhar-%%
|
||||
- %%-context-option-recordhar-path-%%
|
||||
- %%-context-option-recordhar-omit-content-%%
|
||||
- %%-context-option-recordhar-content-%%
|
||||
- %%-context-option-recordhar-mode-%%
|
||||
- %%-context-option-recordhar-url-filter-%%
|
||||
- %%-context-option-recordvideo-%%
|
||||
- %%-context-option-recordvideo-dir-%%
|
||||
|
|
|
|||
|
|
@ -780,61 +780,43 @@ await context.CloseAsync();
|
|||
|
||||
### Replaying from HAR
|
||||
|
||||
Pass [`option: har`] option to the [`method: Browser.newContext`] method to use matching responses from the [HAR](http://www.softwareishard.com/blog/har-12-spec/) file.
|
||||
Use [`method: Page.routeFromHAR`] or [`method: BrowserContext.routeFromHAR`] to serve matching responses from the [HAR](http://www.softwareishard.com/blog/har-12-spec/) file.
|
||||
|
||||
```js
|
||||
// Replay API requests from HAR.
|
||||
// Either use a matching response from the HAR,
|
||||
// or abort the request if nothing matches.
|
||||
const context = await browser.newContext({ har: { path: 'example.har' } });
|
||||
await page.routeFromHAR('example.har');
|
||||
```
|
||||
|
||||
```java
|
||||
// Either use a matching response from the HAR,
|
||||
// or abort the request if nothing matches.
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setHarPath(Paths.get("example.har")));
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://example.com");
|
||||
page.routeFromHAR(Paths.get("example.har"));
|
||||
```
|
||||
|
||||
```python async
|
||||
# Either use a matching response from the HAR,
|
||||
# or abort the request if nothing matches.
|
||||
context = await browser.new_context(
|
||||
har_path = "example.har"
|
||||
)
|
||||
page = await context.new_page()
|
||||
await page.goto("https://example.com")
|
||||
await page.routeFromHAR("example.har")
|
||||
```
|
||||
|
||||
```python sync
|
||||
# Either use a matching response from the HAR,
|
||||
# or abort the request if nothing matches.
|
||||
context = browser.new_context(
|
||||
har_path="example.har"
|
||||
)
|
||||
page = context.new_page()
|
||||
page.goto("https://example.com")
|
||||
page.routeFromHAR("example.har")
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Either use a matching response from the HAR,
|
||||
// or abort the request if nothing matches.
|
||||
var context = await Browser.NewContextAsync(new () {
|
||||
HarPath = "example.har"
|
||||
});
|
||||
var page = await context.NewPageAsync();
|
||||
await page.GotoAsync("https://example.com");
|
||||
await context.RouteFromHARAsync("example.har");
|
||||
```
|
||||
|
||||
HAR replay matches URL and HTTP method strictly. For POST requests, it also matches POST payloads strictly. If multiple recordings match a request, the one with the most matching headers is picked. An entry resulting in a redirect will be followed automatically.
|
||||
|
||||
Similar to when recording, if given HAR file name ends with `.zip`, it is considered an archive containing the HAR file along with network payloads stored as separate entries. You can also extract this archive, edit payloads or HAR log manually and point to the extracted har file. All the payloads will be resolved relative to the extracted har file on the file system.
|
||||
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: Route.fulfill`]
|
||||
|
||||
<br/>
|
||||
|
||||
## WebSockets
|
||||
|
|
|
|||
|
|
@ -5,6 +5,118 @@ title: "Release notes"
|
|||
|
||||
<!-- TOC -->
|
||||
|
||||
## Version 1.23
|
||||
|
||||
### Network Replay
|
||||
|
||||
Now you can record network traffic into a HAR file and re-use this traffic in your tests.
|
||||
|
||||
To record network into HAR file:
|
||||
|
||||
```bash
|
||||
npx playwright open --save-har=github.har.zip https://github.com/microsoft
|
||||
```
|
||||
|
||||
Alternatively, you can record HAR programmatically:
|
||||
|
||||
```ts
|
||||
const context = await browser.newContext({
|
||||
recordHar: { path: 'github.har.zip' }
|
||||
});
|
||||
// ... do stuff ...
|
||||
await context.close();
|
||||
```
|
||||
|
||||
Use the new methods [`method: Page.routeFromHAR`] or [`method: BrowserContext.routeFromHAR`] to serve matching responses from the [HAR](http://www.softwareishard.com/blog/har-12-spec/) file:
|
||||
|
||||
|
||||
```ts
|
||||
await context.routeFromHAR('github.har.zip');
|
||||
```
|
||||
|
||||
Read more in [our documentation](./network#record-and-replay-requests).
|
||||
|
||||
|
||||
### Advanced Routing
|
||||
|
||||
You can now use [`method: Route.fallback`] to defer routing to other handlers.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
```ts
|
||||
// Remove a header from all requests.
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.route('**/*', async route => {
|
||||
const headers = await route.request().allHeaders();
|
||||
delete headers['if-none-match'];
|
||||
route.fallback({ headers });
|
||||
});
|
||||
});
|
||||
|
||||
test('should work', async ({ page }) => {
|
||||
await page.route('**/*', route => {
|
||||
if (route.request().resourceType() === 'image')
|
||||
route.abort();
|
||||
else
|
||||
route.fallback();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Note that the new methods [`method: Page.routeFromHAR`] and [`method: BrowserContext.routeFromHAR`] also participate in routing and could be deferred to.
|
||||
|
||||
### Web-First Assertions Update
|
||||
|
||||
* New method [`method: LocatorAssertions.toHaveValues`] that asserts all selected values of `<select multiple>` element.
|
||||
* Methods [`method: LocatorAssertions.toContainText`] and [`method: LocatorAssertions.toHaveText`] now accept `ignoreCase` option.
|
||||
|
||||
### Component Tests Update
|
||||
|
||||
* Support for Vue2 via the [`@playwright/experimental-ct-vue2`](https://www.npmjs.com/package/@playwright/experimental-ct-vue2) package.
|
||||
* Support for component tests for [create-react-app](https://www.npmjs.com/package/create-react-app) with components in `.js` files.
|
||||
|
||||
Read more about [component testing with Playwright](./test-components).
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
* If there's a service worker that's in your way, you can now easily disable it with a new context option `serviceWorkers`:
|
||||
```ts
|
||||
// playwright.config.ts
|
||||
export default {
|
||||
use: {
|
||||
serviceWorkers: 'block',
|
||||
}
|
||||
}
|
||||
```
|
||||
* Using `.zip` path for `recordHar` context option automatically zips the resulting HAR:
|
||||
```ts
|
||||
const context = await browser.newContext({
|
||||
recordHar: {
|
||||
path: 'github.har.zip',
|
||||
}
|
||||
});
|
||||
```
|
||||
* If you intend to edit HAR by hand, consider using the `"minimal"` HAR recording mode
|
||||
that only records information that is essential for replaying:
|
||||
```ts
|
||||
const context = await browser.newContext({
|
||||
recordHar: {
|
||||
path: 'github.har.zip',
|
||||
mode: 'minimal',
|
||||
}
|
||||
});
|
||||
```
|
||||
* Playwright now runs on Ubuntu 22 amd64 and Ubuntu 22 arm64. We also publish new docker image `mcr.microsoft.com/playwright:v1.23.0-focal`.
|
||||
|
||||
### ⚠️ Breaking Changes ⚠️
|
||||
|
||||
WebServer is now considered "ready" if request to the specified port has any of the following HTTP status codes:
|
||||
|
||||
* `200-299`
|
||||
* `300-399` (new)
|
||||
* `400`, `401`, `402`, `403` (new)
|
||||
|
||||
|
||||
## Version 1.22
|
||||
|
||||
### Highlights
|
||||
|
|
|
|||
|
|
@ -129,8 +129,6 @@ Options used to create the context, as passed to [`method: Browser.newContext`].
|
|||
|
||||
## property: TestOptions.geolocation = %%-context-option-geolocation-%%
|
||||
|
||||
## property: TestOptions.har = %%-js-context-option-har-%%
|
||||
|
||||
## property: TestOptions.hasTouch = %%-context-option-hastouch-%%
|
||||
|
||||
## property: TestOptions.headless = %%-browser-option-headless-%%
|
||||
|
|
|
|||
60
package-lock.json
generated
60
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "playwright-internal",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "playwright-internal",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"license": "Apache-2.0",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
|
|
@ -6459,11 +6459,11 @@
|
|||
"version": "0.0.0"
|
||||
},
|
||||
"packages/playwright": {
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
|
|
@ -6473,11 +6473,11 @@
|
|||
}
|
||||
},
|
||||
"packages/playwright-chromium": {
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
|
|
@ -6487,7 +6487,7 @@
|
|||
}
|
||||
},
|
||||
"packages/playwright-core": {
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
|
|
@ -6498,10 +6498,10 @@
|
|||
},
|
||||
"packages/playwright-ct-react": {
|
||||
"name": "@playwright/experimental-ct-react",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"@vitejs/plugin-react": "^1.0.7",
|
||||
"vite": "^2.9.5"
|
||||
},
|
||||
|
|
@ -6511,10 +6511,10 @@
|
|||
},
|
||||
"packages/playwright-ct-svelte": {
|
||||
"name": "@playwright/experimental-ct-svelte",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.30",
|
||||
"vite": "^2.9.5"
|
||||
},
|
||||
|
|
@ -6524,10 +6524,10 @@
|
|||
},
|
||||
"packages/playwright-ct-vue": {
|
||||
"name": "@playwright/experimental-ct-vue",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"@vitejs/plugin-vue": "^2.3.1",
|
||||
"vite": "^2.9.5"
|
||||
},
|
||||
|
|
@ -6575,10 +6575,10 @@
|
|||
},
|
||||
"packages/playwright-ct-vue2": {
|
||||
"name": "@playwright/experimental-ct-vue2",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"vite": "^2.9.5",
|
||||
"vite-plugin-vue2": "^2.0.1"
|
||||
},
|
||||
|
|
@ -6590,11 +6590,11 @@
|
|||
}
|
||||
},
|
||||
"packages/playwright-firefox": {
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
|
|
@ -6605,11 +6605,11 @@
|
|||
},
|
||||
"packages/playwright-test": {
|
||||
"name": "@playwright/test",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
|
|
@ -6619,11 +6619,11 @@
|
|||
}
|
||||
},
|
||||
"packages/playwright-webkit": {
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
|
|
@ -7437,7 +7437,7 @@
|
|||
"@playwright/experimental-ct-react": {
|
||||
"version": "file:packages/playwright-ct-react",
|
||||
"requires": {
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"@vitejs/plugin-react": "^1.0.7",
|
||||
"vite": "^2.9.5"
|
||||
}
|
||||
|
|
@ -7445,7 +7445,7 @@
|
|||
"@playwright/experimental-ct-svelte": {
|
||||
"version": "file:packages/playwright-ct-svelte",
|
||||
"requires": {
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.30",
|
||||
"vite": "^2.9.5"
|
||||
}
|
||||
|
|
@ -7453,7 +7453,7 @@
|
|||
"@playwright/experimental-ct-vue": {
|
||||
"version": "file:packages/playwright-ct-vue",
|
||||
"requires": {
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"@vitejs/plugin-vue": "^2.3.1",
|
||||
"vite": "^2.9.5"
|
||||
},
|
||||
|
|
@ -7492,7 +7492,7 @@
|
|||
"@playwright/experimental-ct-vue2": {
|
||||
"version": "file:packages/playwright-ct-vue2",
|
||||
"requires": {
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"vite": "^2.9.5",
|
||||
"vite-plugin-vue2": "^2.0.1",
|
||||
"vue": "^2.6.14"
|
||||
|
|
@ -7502,7 +7502,7 @@
|
|||
"version": "file:packages/playwright-test",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
}
|
||||
},
|
||||
"@rollup/pluginutils": {
|
||||
|
|
@ -10311,13 +10311,13 @@
|
|||
"playwright": {
|
||||
"version": "file:packages/playwright",
|
||||
"requires": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
}
|
||||
},
|
||||
"playwright-chromium": {
|
||||
"version": "file:packages/playwright-chromium",
|
||||
"requires": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
}
|
||||
},
|
||||
"playwright-core": {
|
||||
|
|
@ -10326,13 +10326,13 @@
|
|||
"playwright-firefox": {
|
||||
"version": "file:packages/playwright-firefox",
|
||||
"requires": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
}
|
||||
},
|
||||
"playwright-webkit": {
|
||||
"version": "file:packages/playwright-webkit",
|
||||
"requires": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
}
|
||||
},
|
||||
"postcss": {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "playwright-internal",
|
||||
"private": true,
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "A high-level API to automate web browsers",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "playwright-chromium",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "A high-level API to automate Chromium",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
@ -27,6 +27,6 @@
|
|||
"install": "node install.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
"browsers": [
|
||||
{
|
||||
"name": "chromium",
|
||||
"revision": "1011",
|
||||
"revision": "1012",
|
||||
"installByDefault": true,
|
||||
"browserVersion": "103.0.5060.53"
|
||||
"browserVersion": "104.0.5112.20"
|
||||
},
|
||||
{
|
||||
"name": "chromium-with-symbols",
|
||||
"revision": "1011",
|
||||
"revision": "1012",
|
||||
"installByDefault": false,
|
||||
"browserVersion": "103.0.5060.53"
|
||||
"browserVersion": "104.0.5112.20"
|
||||
},
|
||||
{
|
||||
"name": "chromium-tip-of-tree",
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
},
|
||||
{
|
||||
"name": "webkit",
|
||||
"revision": "1666",
|
||||
"revision": "1668",
|
||||
"installByDefault": true,
|
||||
"revisionOverrides": {
|
||||
"mac10.14": "1446",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "playwright-core",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "A high-level API to automate web browsers",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
@ -38,7 +38,6 @@
|
|||
"./lib/server": "./lib/server/index.js",
|
||||
"./lib/utilsBundle": "./lib/utilsBundle.js",
|
||||
"./lib/zipBundle": "./lib/zipBundle.js",
|
||||
"./types/har": "./types/har.d.ts",
|
||||
"./types/protocol": "./types/protocol.d.ts",
|
||||
"./types/structs": "./types/structs.d.ts"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -468,7 +468,7 @@ async function launchContext(options: Options, headless: boolean, executablePath
|
|||
// HAR
|
||||
|
||||
if (options.saveHar) {
|
||||
contextOptions.recordHar = { path: path.resolve(process.cwd(), options.saveHar) };
|
||||
contextOptions.recordHar = { path: path.resolve(process.cwd(), options.saveHar), mode: 'minimal' };
|
||||
if (options.saveHarGlob)
|
||||
contextOptions.recordHar.urlFilter = options.saveHarGlob;
|
||||
contextOptions.serviceWorkers = 'block';
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import { isSafeCloseError, kBrowserClosedError } from '../common/errors';
|
|||
import type * as api from '../../types/types';
|
||||
import { CDPSession } from './cdpSession';
|
||||
import type { BrowserType } from './browserType';
|
||||
import { HarRouter } from './harRouter';
|
||||
|
||||
export class Browser extends ChannelOwner<channels.BrowserChannel> implements api.Browser {
|
||||
readonly _contexts = new Set<BrowserContext>();
|
||||
|
|
@ -61,14 +60,12 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
|
|||
|
||||
async newContext(options: BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
options = { ...this._browserType._defaultContextOptions, ...options };
|
||||
const harRouter = options.har ? await HarRouter.create(this._connection.localUtils(), options.har) : null;
|
||||
const contextOptions = await prepareBrowserContextParams(options);
|
||||
const context = BrowserContext.from((await this._channel.newContext(contextOptions)).context);
|
||||
context._options = contextOptions;
|
||||
this._contexts.add(context);
|
||||
context._logger = options.logger || this._logger;
|
||||
context._setBrowserType(this._browserType);
|
||||
harRouter?.addRoute(context);
|
||||
await this._browserType._onDidCreateContext?.(context);
|
||||
return context;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import { Artifact } from './artifact';
|
|||
import { APIRequestContext } from './fetch';
|
||||
import { createInstrumentation } from './clientInstrumentation';
|
||||
import { rewriteErrorMessage } from '../utils/stackTrace';
|
||||
import { HarRouter } from './harRouter';
|
||||
|
||||
export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel> implements api.BrowserContext {
|
||||
_pages = new Set<Page>();
|
||||
|
|
@ -144,8 +145,10 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||
}
|
||||
|
||||
async _onRoute(route: network.Route, request: network.Request) {
|
||||
const routeHandlers = this._routes.filter(r => r.matches(request.url()));
|
||||
const routeHandlers = this._routes.slice();
|
||||
for (const routeHandler of routeHandlers) {
|
||||
if (!routeHandler.matches(request.url()))
|
||||
continue;
|
||||
if (routeHandler.willExpire())
|
||||
this._routes.splice(this._routes.indexOf(routeHandler), 1);
|
||||
const handled = await routeHandler.handle(route, request);
|
||||
|
|
@ -267,6 +270,11 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||
await this._channel.setNetworkInterceptionEnabled({ enabled: true });
|
||||
}
|
||||
|
||||
async routeFromHAR(har: string, options: { url?: URLMatch, notFound?: 'abort' | 'fallback' } = {}): Promise<void> {
|
||||
const harRouter = await HarRouter.create(this._connection.localUtils(), har, options.notFound || 'abort', { urlMatch: options.url });
|
||||
harRouter.addContextRoute(this);
|
||||
}
|
||||
|
||||
async unroute(url: URLMatch, handler?: network.RouteHandlerCallback): Promise<void> {
|
||||
this._routes = this._routes.filter(route => route.url !== url || (handler && route.handler !== handler));
|
||||
if (!this._routes.length)
|
||||
|
|
@ -387,6 +395,7 @@ function prepareRecordHarOptions(options: BrowserContextOptions['recordHar']): c
|
|||
urlGlob: isString(options.urlFilter) ? options.urlFilter : undefined,
|
||||
urlRegexSource: isRegExp(options.urlFilter) ? options.urlFilter.source : undefined,
|
||||
urlRegexFlags: isRegExp(options.urlFilter) ? options.urlFilter.flags : undefined,
|
||||
mode: options.mode
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import type * as api from '../../types/types';
|
|||
import { kBrowserClosedError } from '../common/errors';
|
||||
import { raceAgainstTimeout } from '../utils/timeoutRunner';
|
||||
import type { Playwright } from './playwright';
|
||||
import { HarRouter } from './harRouter';
|
||||
|
||||
export interface BrowserServerLauncher {
|
||||
launchServer(options?: LaunchServerOptions): Promise<api.BrowserServer>;
|
||||
|
|
@ -95,7 +94,6 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
|||
const logger = options.logger || this._defaultLaunchOptions?.logger;
|
||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||
options = { ...this._defaultLaunchOptions, ...this._defaultContextOptions, ...options };
|
||||
const harRouter = options.har ? await HarRouter.create(this._connection.localUtils(), options.har) : null;
|
||||
const contextParams = await prepareBrowserContextParams(options);
|
||||
const persistentParams: channels.BrowserTypeLaunchPersistentContextParams = {
|
||||
...contextParams,
|
||||
|
|
@ -110,7 +108,6 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
|||
context._options = contextParams;
|
||||
context._logger = logger;
|
||||
context._setBrowserType(this);
|
||||
harRouter?.addRoute(context);
|
||||
await this._onDidCreateContext?.(context);
|
||||
return context;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,12 +28,10 @@ import { JSHandle, parseResult, serializeArgument } from './jsHandle';
|
|||
import type { Page } from './page';
|
||||
import type { Env, WaitForEventOptions, Headers, BrowserContextOptions } from './types';
|
||||
import { Waiter } from './waiter';
|
||||
import { HarRouter } from './harRouter';
|
||||
|
||||
type ElectronOptions = Omit<channels.ElectronLaunchOptions, 'env'|'extraHTTPHeaders'|'recordHar'> & {
|
||||
env?: Env,
|
||||
extraHTTPHeaders?: Headers,
|
||||
har?: BrowserContextOptions['har'],
|
||||
recordHar?: BrowserContextOptions['recordHar'],
|
||||
};
|
||||
|
||||
|
|
@ -53,10 +51,8 @@ export class Electron extends ChannelOwner<channels.ElectronChannel> implements
|
|||
...await prepareBrowserContextParams(options),
|
||||
env: envObjectToArray(options.env ? options.env : process.env),
|
||||
};
|
||||
const harRouter = options.har ? await HarRouter.create(this._connection.localUtils(), options.har) : null;
|
||||
const app = ElectronApplication.from((await this._channel.launch(params)).electronApplication);
|
||||
app._context._options = params;
|
||||
harRouter?.addRoute(app._context);
|
||||
return app;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,32 +19,34 @@ import type { BrowserContext } from './browserContext';
|
|||
import { Events } from './events';
|
||||
import type { LocalUtils } from './localUtils';
|
||||
import type { Route } from './network';
|
||||
import type { BrowserContextOptions } from './types';
|
||||
import type { URLMatch } from './types';
|
||||
import type { Page } from './page';
|
||||
|
||||
type HarOptions = NonNullable<BrowserContextOptions['har']>;
|
||||
type HarNotFoundAction = 'abort' | 'fallback';
|
||||
|
||||
export class HarRouter {
|
||||
private _pattern: string | RegExp;
|
||||
private _options: HarOptions | undefined;
|
||||
private _localUtils: LocalUtils;
|
||||
private _harId: string;
|
||||
private _notFoundAction: HarNotFoundAction;
|
||||
private _options: { urlMatch?: URLMatch; baseURL?: string; };
|
||||
|
||||
static async create(localUtils: LocalUtils, options: HarOptions): Promise<HarRouter> {
|
||||
const { harId, error } = await localUtils._channel.harOpen({ file: options.path });
|
||||
static async create(localUtils: LocalUtils, file: string, notFoundAction: HarNotFoundAction, options: { urlMatch?: URLMatch }): Promise<HarRouter> {
|
||||
const { harId, error } = await localUtils._channel.harOpen({ file });
|
||||
if (error)
|
||||
throw new Error(error);
|
||||
return new HarRouter(localUtils, harId!, options);
|
||||
return new HarRouter(localUtils, harId!, notFoundAction, options);
|
||||
}
|
||||
|
||||
constructor(localUtils: LocalUtils, harId: string, options?: HarOptions) {
|
||||
constructor(localUtils: LocalUtils, harId: string, notFoundAction: HarNotFoundAction, options: { urlMatch?: URLMatch }) {
|
||||
this._localUtils = localUtils;
|
||||
this._harId = harId;
|
||||
this._pattern = options?.urlFilter ?? /.*/;
|
||||
this._options = options;
|
||||
this._notFoundAction = notFoundAction;
|
||||
}
|
||||
|
||||
private async _handle(route: Route) {
|
||||
const request = route.request();
|
||||
|
||||
const response = await this._localUtils._channel.harLookup({
|
||||
harId: this._harId,
|
||||
url: request.url(),
|
||||
|
|
@ -56,7 +58,7 @@ export class HarRouter {
|
|||
|
||||
if (response.action === 'redirect') {
|
||||
debugLogger.log('api', `HAR: ${route.request().url()} redirected to ${response.redirectURL}`);
|
||||
await route._abort(undefined, response.redirectURL);
|
||||
await route._redirectNavigationRequest(response.redirectURL!);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -73,20 +75,24 @@ export class HarRouter {
|
|||
debugLogger.log('api', 'HAR: ' + response.message!);
|
||||
// Report the error, but fall through to the default handler.
|
||||
|
||||
if (this._options?.fallback === 'continue') {
|
||||
await route.fallback();
|
||||
if (this._notFoundAction === 'abort') {
|
||||
await route.abort();
|
||||
return;
|
||||
}
|
||||
|
||||
debugLogger.log('api', `HAR: ${route.request().method()} ${route.request().url()} aborted - no such entry in HAR file`);
|
||||
await route.abort();
|
||||
await route.fallback();
|
||||
}
|
||||
|
||||
async addRoute(context: BrowserContext) {
|
||||
await context.route(this._pattern, route => this._handle(route));
|
||||
async addContextRoute(context: BrowserContext) {
|
||||
await context.route(this._options.urlMatch || '**/*', route => this._handle(route));
|
||||
context.once(Events.BrowserContext.Close, () => this.dispose());
|
||||
}
|
||||
|
||||
async addPageRoute(page: Page) {
|
||||
await page.route(this._options.urlMatch || '**/*', route => this._handle(route));
|
||||
page.once(Events.Page.Close, () => this.dispose());
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._localUtils._channel.harClose({ harId: this._harId }).catch(() => {});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,12 +282,14 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
|
|||
}
|
||||
|
||||
async abort(errorCode?: string) {
|
||||
await this._abort(errorCode);
|
||||
this._checkNotHandled();
|
||||
await this._raceWithPageClose(this._channel.abort({ errorCode }));
|
||||
this._reportHandled(true);
|
||||
}
|
||||
|
||||
async _abort(errorCode?: string, redirectAbortedNavigationToUrl?: string) {
|
||||
async _redirectNavigationRequest(url: string) {
|
||||
this._checkNotHandled();
|
||||
await this._raceWithPageClose(this._channel.abort({ errorCode, redirectAbortedNavigationToUrl }));
|
||||
await this._raceWithPageClose(this._channel.redirectNavigationRequest({ url }));
|
||||
this._reportHandled(true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import type { APIRequestContext } from './fetch';
|
|||
import { FileChooser } from './fileChooser';
|
||||
import type { WaitForNavigationOptions } from './frame';
|
||||
import { Frame, verifyLoadState } from './frame';
|
||||
import { HarRouter } from './harRouter';
|
||||
import { Keyboard, Mouse, Touchscreen } from './input';
|
||||
import { assertMaxArguments, JSHandle, parseResult, serializeArgument } from './jsHandle';
|
||||
import type { FrameLocator, Locator, LocatorOptions } from './locator';
|
||||
|
|
@ -178,8 +179,10 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||
}
|
||||
|
||||
private async _onRoute(route: Route, request: Request) {
|
||||
const routeHandlers = this._routes.filter(r => r.matches(request.url()));
|
||||
const routeHandlers = this._routes.slice();
|
||||
for (const routeHandler of routeHandlers) {
|
||||
if (!routeHandler.matches(request.url()))
|
||||
continue;
|
||||
if (routeHandler.willExpire())
|
||||
this._routes.splice(this._routes.indexOf(routeHandler), 1);
|
||||
const handled = await routeHandler.handle(route, request);
|
||||
|
|
@ -465,6 +468,11 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||
await this._channel.setNetworkInterceptionEnabled({ enabled: true });
|
||||
}
|
||||
|
||||
async routeFromHAR(har: string, options: { url?: URLMatch, notFound?: 'abort' | 'fallback' } = {}): Promise<void> {
|
||||
const harRouter = await HarRouter.create(this._connection.localUtils(), har, options.notFound || 'abort', { urlMatch: options.url });
|
||||
harRouter.addPageRoute(this);
|
||||
}
|
||||
|
||||
async unroute(url: URLMatch, handler?: RouteHandlerCallback): Promise<void> {
|
||||
this._routes = this._routes.filter(route => route.url !== url || (handler && route.handler !== handler));
|
||||
if (!this._routes.length)
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ export type BrowserContextOptions = Omit<channels.BrowserNewContextOptions, 'vie
|
|||
path: string,
|
||||
omitContent?: boolean,
|
||||
content?: 'omit' | 'embed' | 'attach',
|
||||
mode?: 'full' | 'minimal',
|
||||
urlFilter?: string | RegExp,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -266,6 +266,7 @@ export type SerializedError = {
|
|||
export type RecordHarOptions = {
|
||||
path: string,
|
||||
content?: 'embed' | 'attach' | 'omit',
|
||||
mode?: 'full' | 'minimal',
|
||||
urlGlob?: string,
|
||||
urlRegexSource?: string,
|
||||
urlRegexFlags?: string,
|
||||
|
|
@ -3158,17 +3159,23 @@ export interface RouteEventTarget {
|
|||
}
|
||||
export interface RouteChannel extends RouteEventTarget, Channel {
|
||||
_type_Route: boolean;
|
||||
redirectNavigationRequest(params: RouteRedirectNavigationRequestParams, metadata?: Metadata): Promise<RouteRedirectNavigationRequestResult>;
|
||||
abort(params: RouteAbortParams, metadata?: Metadata): Promise<RouteAbortResult>;
|
||||
continue(params: RouteContinueParams, metadata?: Metadata): Promise<RouteContinueResult>;
|
||||
fulfill(params: RouteFulfillParams, metadata?: Metadata): Promise<RouteFulfillResult>;
|
||||
}
|
||||
export type RouteRedirectNavigationRequestParams = {
|
||||
url: string,
|
||||
};
|
||||
export type RouteRedirectNavigationRequestOptions = {
|
||||
|
||||
};
|
||||
export type RouteRedirectNavigationRequestResult = void;
|
||||
export type RouteAbortParams = {
|
||||
errorCode?: string,
|
||||
redirectAbortedNavigationToUrl?: string,
|
||||
};
|
||||
export type RouteAbortOptions = {
|
||||
errorCode?: string,
|
||||
redirectAbortedNavigationToUrl?: string,
|
||||
};
|
||||
export type RouteAbortResult = void;
|
||||
export type RouteContinueParams = {
|
||||
|
|
|
|||
|
|
@ -231,6 +231,11 @@ RecordHarOptions:
|
|||
- embed
|
||||
- attach
|
||||
- omit
|
||||
mode:
|
||||
type: enum?
|
||||
literals:
|
||||
- full
|
||||
- minimal
|
||||
urlGlob: string?
|
||||
urlRegexSource: string?
|
||||
urlRegexFlags: string?
|
||||
|
|
@ -2491,10 +2496,13 @@ Route:
|
|||
|
||||
commands:
|
||||
|
||||
redirectNavigationRequest:
|
||||
parameters:
|
||||
url: string
|
||||
|
||||
abort:
|
||||
parameters:
|
||||
errorCode: string?
|
||||
redirectAbortedNavigationToUrl: string?
|
||||
|
||||
continue:
|
||||
parameters:
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||
scheme.RecordHarOptions = tObject({
|
||||
path: tString,
|
||||
content: tOptional(tEnum(['embed', 'attach', 'omit'])),
|
||||
mode: tOptional(tEnum(['full', 'minimal'])),
|
||||
urlGlob: tOptional(tString),
|
||||
urlRegexSource: tOptional(tString),
|
||||
urlRegexFlags: tOptional(tString),
|
||||
|
|
@ -1181,9 +1182,11 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||
});
|
||||
scheme.RequestResponseParams = tOptional(tObject({}));
|
||||
scheme.RequestRawRequestHeadersParams = tOptional(tObject({}));
|
||||
scheme.RouteRedirectNavigationRequestParams = tObject({
|
||||
url: tString,
|
||||
});
|
||||
scheme.RouteAbortParams = tObject({
|
||||
errorCode: tOptional(tString),
|
||||
redirectAbortedNavigationToUrl: tOptional(tString),
|
||||
});
|
||||
scheme.RouteContinueParams = tObject({
|
||||
url: tOptional(tString),
|
||||
|
|
|
|||
|
|
@ -810,7 +810,7 @@ CORS RFC1918 enforcement.
|
|||
export type AttributionReportingIssueType = "PermissionPolicyDisabled"|"AttributionSourceUntrustworthyOrigin"|"AttributionUntrustworthyOrigin"|"InvalidHeader";
|
||||
/**
|
||||
* Details for issues around "Attribution Reporting API" usage.
|
||||
Explainer: https://github.com/WICG/conversion-measurement-api
|
||||
Explainer: https://github.com/WICG/attribution-reporting-api
|
||||
*/
|
||||
export interface AttributionReportingIssueDetails {
|
||||
violationType: AttributionReportingIssueType;
|
||||
|
|
@ -849,7 +849,7 @@ instead of "limited-quirks".
|
|||
errorType: GenericIssueErrorType;
|
||||
frameId?: Page.FrameId;
|
||||
}
|
||||
export type DeprecationIssueType = "AuthorizationCoveredByWildcard"|"CanRequestURLHTTPContainingNewline"|"ChromeLoadTimesConnectionInfo"|"ChromeLoadTimesFirstPaintAfterLoadTime"|"ChromeLoadTimesWasAlternateProtocolAvailable"|"CookieWithTruncatingChar"|"CrossOriginAccessBasedOnDocumentDomain"|"CrossOriginWindowAlert"|"CrossOriginWindowConfirm"|"CSSSelectorInternalMediaControlsOverlayCastButton"|"CustomCursorIntersectsViewport"|"DeprecationExample"|"DocumentDomainSettingWithoutOriginAgentClusterHeader"|"EventPath"|"GeolocationInsecureOrigin"|"GeolocationInsecureOriginDeprecatedNotRemoved"|"GetUserMediaInsecureOrigin"|"HostCandidateAttributeGetter"|"InsecurePrivateNetworkSubresourceRequest"|"LegacyConstraintGoogIPv6"|"LocalCSSFileExtensionRejected"|"MediaElementAudioSourceNode"|"MediaSourceAbortRemove"|"MediaSourceDurationTruncatingBuffered"|"NoSysexWebMIDIWithoutPermission"|"NotificationInsecureOrigin"|"NotificationPermissionRequestedIframe"|"ObsoleteWebRtcCipherSuite"|"PaymentRequestBasicCard"|"PaymentRequestShowWithoutGesture"|"PictureSourceSrc"|"PrefixedCancelAnimationFrame"|"PrefixedRequestAnimationFrame"|"PrefixedStorageInfo"|"PrefixedVideoDisplayingFullscreen"|"PrefixedVideoEnterFullscreen"|"PrefixedVideoEnterFullScreen"|"PrefixedVideoExitFullscreen"|"PrefixedVideoExitFullScreen"|"PrefixedVideoSupportsFullscreen"|"RangeExpand"|"RequestedSubresourceWithEmbeddedCredentials"|"RTCConstraintEnableDtlsSrtpFalse"|"RTCConstraintEnableDtlsSrtpTrue"|"RTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics"|"RTCPeerConnectionSdpSemanticsPlanB"|"RtcpMuxPolicyNegotiate"|"RTPDataChannel"|"SharedArrayBufferConstructedWithoutIsolation"|"TextToSpeech_DisallowedByAutoplay"|"V8SharedArrayBufferConstructedInExtensionWithoutIsolation"|"XHRJSONEncodingDetection"|"XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload"|"XRSupportsSession";
|
||||
export type DeprecationIssueType = "AuthorizationCoveredByWildcard"|"CanRequestURLHTTPContainingNewline"|"ChromeLoadTimesConnectionInfo"|"ChromeLoadTimesFirstPaintAfterLoadTime"|"ChromeLoadTimesWasAlternateProtocolAvailable"|"CookieWithTruncatingChar"|"CrossOriginAccessBasedOnDocumentDomain"|"CrossOriginWindowAlert"|"CrossOriginWindowConfirm"|"CSSSelectorInternalMediaControlsOverlayCastButton"|"DeprecationExample"|"DocumentDomainSettingWithoutOriginAgentClusterHeader"|"EventPath"|"GeolocationInsecureOrigin"|"GeolocationInsecureOriginDeprecatedNotRemoved"|"GetUserMediaInsecureOrigin"|"HostCandidateAttributeGetter"|"IdentityInCanMakePaymentEvent"|"InsecurePrivateNetworkSubresourceRequest"|"LegacyConstraintGoogIPv6"|"LocalCSSFileExtensionRejected"|"MediaSourceAbortRemove"|"MediaSourceDurationTruncatingBuffered"|"NoSysexWebMIDIWithoutPermission"|"NotificationInsecureOrigin"|"NotificationPermissionRequestedIframe"|"ObsoleteWebRtcCipherSuite"|"OpenWebDatabaseInsecureContext"|"PictureSourceSrc"|"PrefixedCancelAnimationFrame"|"PrefixedRequestAnimationFrame"|"PrefixedStorageInfo"|"PrefixedVideoDisplayingFullscreen"|"PrefixedVideoEnterFullscreen"|"PrefixedVideoEnterFullScreen"|"PrefixedVideoExitFullscreen"|"PrefixedVideoExitFullScreen"|"PrefixedVideoSupportsFullscreen"|"RangeExpand"|"RequestedSubresourceWithEmbeddedCredentials"|"RTCConstraintEnableDtlsSrtpFalse"|"RTCConstraintEnableDtlsSrtpTrue"|"RTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics"|"RTCPeerConnectionSdpSemanticsPlanB"|"RtcpMuxPolicyNegotiate"|"SharedArrayBufferConstructedWithoutIsolation"|"TextToSpeech_DisallowedByAutoplay"|"V8SharedArrayBufferConstructedInExtensionWithoutIsolation"|"XHRJSONEncodingDetection"|"XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload"|"XRSupportsSession";
|
||||
/**
|
||||
* This issue tracks information needed to print a deprecation message.
|
||||
https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/frame/third_party/blink/renderer/core/frame/deprecation/README.md
|
||||
|
|
@ -1532,6 +1532,10 @@ inspector" rules), "regular" for regular stylesheets.
|
|||
* Pseudo element type.
|
||||
*/
|
||||
pseudoType: DOM.PseudoType;
|
||||
/**
|
||||
* Pseudo element custom ident.
|
||||
*/
|
||||
pseudoIdentifier?: string;
|
||||
/**
|
||||
* Matches of CSS rules applicable to the pseudo style.
|
||||
*/
|
||||
|
|
@ -2068,6 +2072,10 @@ and additional information such as platformFontFamily and fontVariationAxes.
|
|||
* The font-stretch.
|
||||
*/
|
||||
fontStretch: string;
|
||||
/**
|
||||
* The font-display.
|
||||
*/
|
||||
fontDisplay: string;
|
||||
/**
|
||||
* The unicode-range.
|
||||
*/
|
||||
|
|
@ -2958,6 +2966,11 @@ fire DOM events for nodes known to the client.
|
|||
* Pseudo element type for this node.
|
||||
*/
|
||||
pseudoType?: PseudoType;
|
||||
/**
|
||||
* Pseudo element identifier for this node. Only present if there is a
|
||||
valid pseudoType.
|
||||
*/
|
||||
pseudoIdentifier?: string;
|
||||
/**
|
||||
* Shadow root type.
|
||||
*/
|
||||
|
|
@ -2997,6 +3010,7 @@ The property is always undefined now.
|
|||
*/
|
||||
isSVG?: boolean;
|
||||
compatibilityMode?: CompatibilityMode;
|
||||
assignedSlot?: BackendNode;
|
||||
}
|
||||
/**
|
||||
* A structure holding an RGBA color.
|
||||
|
|
@ -4706,6 +4720,11 @@ getSnapshot was true.
|
|||
* Type of a pseudo element node.
|
||||
*/
|
||||
pseudoType?: RareStringData;
|
||||
/**
|
||||
* Pseudo element identifier for this node. Only present if there is a
|
||||
valid pseudoType.
|
||||
*/
|
||||
pseudoIdentifier?: RareStringData;
|
||||
/**
|
||||
* Whether this DOM node responds to mouse clicks. This includes nodes that have had click
|
||||
event listeners attached via JavaScript as well as anchor tags that naturally navigate when
|
||||
|
|
@ -4978,12 +4997,6 @@ The final text color opacity is computed based on the opacity of all overlapping
|
|||
}
|
||||
export type setDOMStorageItemReturnValue = {
|
||||
}
|
||||
export type getStorageKeyForFrameParameters = {
|
||||
frameId: Page.FrameId;
|
||||
}
|
||||
export type getStorageKeyForFrameReturnValue = {
|
||||
storageKey: SerializedStorageKey;
|
||||
}
|
||||
}
|
||||
|
||||
export module Database {
|
||||
|
|
@ -5533,6 +5546,14 @@ on Android.
|
|||
}
|
||||
export type setDisabledImageTypesReturnValue = {
|
||||
}
|
||||
export type setHardwareConcurrencyOverrideParameters = {
|
||||
/**
|
||||
* Hardware concurrency to report
|
||||
*/
|
||||
hardwareConcurrency: number;
|
||||
}
|
||||
export type setHardwareConcurrencyOverrideReturnValue = {
|
||||
}
|
||||
/**
|
||||
* Allows overriding user agent with the given string.
|
||||
*/
|
||||
|
|
@ -8063,7 +8084,7 @@ the same request (but not for redirected requests).
|
|||
initiatorIPAddressSpace: IPAddressSpace;
|
||||
privateNetworkRequestPolicy: PrivateNetworkRequestPolicy;
|
||||
}
|
||||
export type CrossOriginOpenerPolicyValue = "SameOrigin"|"SameOriginAllowPopups"|"UnsafeNone"|"SameOriginPlusCoep"|"SameOriginAllowPopupsPlusCoep";
|
||||
export type CrossOriginOpenerPolicyValue = "SameOrigin"|"SameOriginAllowPopups"|"RestrictProperties"|"UnsafeNone"|"SameOriginPlusCoep"|"RestrictPropertiesPlusCoep";
|
||||
export interface CrossOriginOpenerPolicyStatus {
|
||||
value: CrossOriginOpenerPolicyValue;
|
||||
reportOnlyValue: CrossOriginOpenerPolicyValue;
|
||||
|
|
@ -10166,6 +10187,21 @@ Backend then generates 'inspectNodeRequested' event upon element selection.
|
|||
adFrameType: AdFrameType;
|
||||
explanations?: AdFrameExplanation[];
|
||||
}
|
||||
/**
|
||||
* Identifies the bottom-most script which caused the frame to be labelled
|
||||
as an ad.
|
||||
*/
|
||||
export interface AdScriptId {
|
||||
/**
|
||||
* Script Id of the bottom-most script which caused the frame to be labelled
|
||||
as an ad.
|
||||
*/
|
||||
scriptId: Runtime.ScriptId;
|
||||
/**
|
||||
* Id of adScriptId's debugger.
|
||||
*/
|
||||
debuggerId: Runtime.UniqueDebuggerId;
|
||||
}
|
||||
/**
|
||||
* Indicates whether the frame is a secure context and why it is the case.
|
||||
*/
|
||||
|
|
@ -10179,7 +10215,7 @@ Backend then generates 'inspectNodeRequested' event upon element selection.
|
|||
* All Permissions Policy features. This enum should match the one defined
|
||||
in third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5.
|
||||
*/
|
||||
export type PermissionsPolicyFeature = "accelerometer"|"ambient-light-sensor"|"attribution-reporting"|"autoplay"|"browsing-topics"|"camera"|"ch-dpr"|"ch-device-memory"|"ch-downlink"|"ch-ect"|"ch-prefers-color-scheme"|"ch-rtt"|"ch-save-data"|"ch-ua"|"ch-ua-arch"|"ch-ua-bitness"|"ch-ua-platform"|"ch-ua-model"|"ch-ua-mobile"|"ch-ua-full"|"ch-ua-full-version"|"ch-ua-full-version-list"|"ch-ua-platform-version"|"ch-ua-reduced"|"ch-ua-wow64"|"ch-viewport-height"|"ch-viewport-width"|"ch-width"|"clipboard-read"|"clipboard-write"|"cross-origin-isolated"|"direct-sockets"|"display-capture"|"document-domain"|"encrypted-media"|"execution-while-out-of-viewport"|"execution-while-not-rendered"|"focus-without-user-activation"|"fullscreen"|"frobulate"|"gamepad"|"geolocation"|"gyroscope"|"hid"|"idle-detection"|"interest-cohort"|"join-ad-interest-group"|"keyboard-map"|"local-fonts"|"magnetometer"|"microphone"|"midi"|"otp-credentials"|"payment"|"picture-in-picture"|"publickey-credentials-get"|"run-ad-auction"|"screen-wake-lock"|"serial"|"shared-autofill"|"storage-access-api"|"sync-xhr"|"trust-token-redemption"|"usb"|"vertical-scroll"|"web-share"|"window-placement"|"xr-spatial-tracking";
|
||||
export type PermissionsPolicyFeature = "accelerometer"|"ambient-light-sensor"|"attribution-reporting"|"autoplay"|"bluetooth"|"browsing-topics"|"camera"|"ch-dpr"|"ch-device-memory"|"ch-downlink"|"ch-ect"|"ch-prefers-color-scheme"|"ch-rtt"|"ch-save-data"|"ch-ua"|"ch-ua-arch"|"ch-ua-bitness"|"ch-ua-platform"|"ch-ua-model"|"ch-ua-mobile"|"ch-ua-full"|"ch-ua-full-version"|"ch-ua-full-version-list"|"ch-ua-platform-version"|"ch-ua-reduced"|"ch-ua-wow64"|"ch-viewport-height"|"ch-viewport-width"|"ch-width"|"clipboard-read"|"clipboard-write"|"cross-origin-isolated"|"direct-sockets"|"display-capture"|"document-domain"|"encrypted-media"|"execution-while-out-of-viewport"|"execution-while-not-rendered"|"focus-without-user-activation"|"fullscreen"|"frobulate"|"gamepad"|"geolocation"|"gyroscope"|"hid"|"idle-detection"|"interest-cohort"|"join-ad-interest-group"|"keyboard-map"|"local-fonts"|"magnetometer"|"microphone"|"midi"|"otp-credentials"|"payment"|"picture-in-picture"|"publickey-credentials-get"|"run-ad-auction"|"screen-wake-lock"|"serial"|"shared-autofill"|"storage-access-api"|"sync-xhr"|"trust-token-redemption"|"usb"|"vertical-scroll"|"web-share"|"window-placement"|"xr-spatial-tracking";
|
||||
/**
|
||||
* Reason for a permissions policy feature to be disabled.
|
||||
*/
|
||||
|
|
@ -10644,7 +10680,7 @@ Example URLs: http://www.google.com/file.html -> "google.com"
|
|||
/**
|
||||
* List of not restored reasons for back-forward cache.
|
||||
*/
|
||||
export type BackForwardCacheNotRestoredReason = "NotPrimaryMainFrame"|"BackForwardCacheDisabled"|"RelatedActiveContentsExist"|"HTTPStatusNotOK"|"SchemeNotHTTPOrHTTPS"|"Loading"|"WasGrantedMediaAccess"|"DisableForRenderFrameHostCalled"|"DomainNotAllowed"|"HTTPMethodNotGET"|"SubframeIsNavigating"|"Timeout"|"CacheLimit"|"JavaScriptExecution"|"RendererProcessKilled"|"RendererProcessCrashed"|"SchedulerTrackedFeatureUsed"|"ConflictingBrowsingInstance"|"CacheFlushed"|"ServiceWorkerVersionActivation"|"SessionRestored"|"ServiceWorkerPostMessage"|"EnteredBackForwardCacheBeforeServiceWorkerHostAdded"|"RenderFrameHostReused_SameSite"|"RenderFrameHostReused_CrossSite"|"ServiceWorkerClaim"|"IgnoreEventAndEvict"|"HaveInnerContents"|"TimeoutPuttingInCache"|"BackForwardCacheDisabledByLowMemory"|"BackForwardCacheDisabledByCommandLine"|"NetworkRequestDatapipeDrainedAsBytesConsumer"|"NetworkRequestRedirected"|"NetworkRequestTimeout"|"NetworkExceedsBufferLimit"|"NavigationCancelledWhileRestoring"|"NotMostRecentNavigationEntry"|"BackForwardCacheDisabledForPrerender"|"UserAgentOverrideDiffers"|"ForegroundCacheLimit"|"BrowsingInstanceNotSwapped"|"BackForwardCacheDisabledForDelegate"|"UnloadHandlerExistsInMainFrame"|"UnloadHandlerExistsInSubFrame"|"ServiceWorkerUnregistration"|"CacheControlNoStore"|"CacheControlNoStoreCookieModified"|"CacheControlNoStoreHTTPOnlyCookieModified"|"NoResponseHead"|"Unknown"|"ActivationNavigationsDisallowedForBug1234857"|"ErrorDocument"|"FencedFramesEmbedder"|"WebSocket"|"WebTransport"|"WebRTC"|"MainResourceHasCacheControlNoStore"|"MainResourceHasCacheControlNoCache"|"SubresourceHasCacheControlNoStore"|"SubresourceHasCacheControlNoCache"|"ContainsPlugins"|"DocumentLoaded"|"DedicatedWorkerOrWorklet"|"OutstandingNetworkRequestOthers"|"OutstandingIndexedDBTransaction"|"RequestedNotificationsPermission"|"RequestedMIDIPermission"|"RequestedAudioCapturePermission"|"RequestedVideoCapturePermission"|"RequestedBackForwardCacheBlockedSensors"|"RequestedBackgroundWorkPermission"|"BroadcastChannel"|"IndexedDBConnection"|"WebXR"|"SharedWorker"|"WebLocks"|"WebHID"|"WebShare"|"RequestedStorageAccessGrant"|"WebNfc"|"OutstandingNetworkRequestFetch"|"OutstandingNetworkRequestXHR"|"AppBanner"|"Printing"|"WebDatabase"|"PictureInPicture"|"Portal"|"SpeechRecognizer"|"IdleManager"|"PaymentManager"|"SpeechSynthesis"|"KeyboardLock"|"WebOTPService"|"OutstandingNetworkRequestDirectSocket"|"InjectedJavascript"|"InjectedStyleSheet"|"Dummy"|"ContentSecurityHandler"|"ContentWebAuthenticationAPI"|"ContentFileChooser"|"ContentSerial"|"ContentFileSystemAccess"|"ContentMediaDevicesDispatcherHost"|"ContentWebBluetooth"|"ContentWebUSB"|"ContentMediaSession"|"ContentMediaSessionService"|"ContentScreenReader"|"EmbedderPopupBlockerTabHelper"|"EmbedderSafeBrowsingTriggeredPopupBlocker"|"EmbedderSafeBrowsingThreatDetails"|"EmbedderAppBannerManager"|"EmbedderDomDistillerViewerSource"|"EmbedderDomDistillerSelfDeletingRequestDelegate"|"EmbedderOomInterventionTabHelper"|"EmbedderOfflinePage"|"EmbedderChromePasswordManagerClientBindCredentialManager"|"EmbedderPermissionRequestManager"|"EmbedderModalDialog"|"EmbedderExtensions"|"EmbedderExtensionMessaging"|"EmbedderExtensionMessagingForOpenPort"|"EmbedderExtensionSentMessageToCachedFrame";
|
||||
export type BackForwardCacheNotRestoredReason = "NotPrimaryMainFrame"|"BackForwardCacheDisabled"|"RelatedActiveContentsExist"|"HTTPStatusNotOK"|"SchemeNotHTTPOrHTTPS"|"Loading"|"WasGrantedMediaAccess"|"DisableForRenderFrameHostCalled"|"DomainNotAllowed"|"HTTPMethodNotGET"|"SubframeIsNavigating"|"Timeout"|"CacheLimit"|"JavaScriptExecution"|"RendererProcessKilled"|"RendererProcessCrashed"|"SchedulerTrackedFeatureUsed"|"ConflictingBrowsingInstance"|"CacheFlushed"|"ServiceWorkerVersionActivation"|"SessionRestored"|"ServiceWorkerPostMessage"|"EnteredBackForwardCacheBeforeServiceWorkerHostAdded"|"RenderFrameHostReused_SameSite"|"RenderFrameHostReused_CrossSite"|"ServiceWorkerClaim"|"IgnoreEventAndEvict"|"HaveInnerContents"|"TimeoutPuttingInCache"|"BackForwardCacheDisabledByLowMemory"|"BackForwardCacheDisabledByCommandLine"|"NetworkRequestDatapipeDrainedAsBytesConsumer"|"NetworkRequestRedirected"|"NetworkRequestTimeout"|"NetworkExceedsBufferLimit"|"NavigationCancelledWhileRestoring"|"NotMostRecentNavigationEntry"|"BackForwardCacheDisabledForPrerender"|"UserAgentOverrideDiffers"|"ForegroundCacheLimit"|"BrowsingInstanceNotSwapped"|"BackForwardCacheDisabledForDelegate"|"UnloadHandlerExistsInMainFrame"|"UnloadHandlerExistsInSubFrame"|"ServiceWorkerUnregistration"|"CacheControlNoStore"|"CacheControlNoStoreCookieModified"|"CacheControlNoStoreHTTPOnlyCookieModified"|"NoResponseHead"|"Unknown"|"ActivationNavigationsDisallowedForBug1234857"|"ErrorDocument"|"FencedFramesEmbedder"|"WebSocket"|"WebTransport"|"WebRTC"|"MainResourceHasCacheControlNoStore"|"MainResourceHasCacheControlNoCache"|"SubresourceHasCacheControlNoStore"|"SubresourceHasCacheControlNoCache"|"ContainsPlugins"|"DocumentLoaded"|"DedicatedWorkerOrWorklet"|"OutstandingNetworkRequestOthers"|"OutstandingIndexedDBTransaction"|"RequestedNotificationsPermission"|"RequestedMIDIPermission"|"RequestedAudioCapturePermission"|"RequestedVideoCapturePermission"|"RequestedBackForwardCacheBlockedSensors"|"RequestedBackgroundWorkPermission"|"BroadcastChannel"|"IndexedDBConnection"|"WebXR"|"SharedWorker"|"WebLocks"|"WebHID"|"WebShare"|"RequestedStorageAccessGrant"|"WebNfc"|"OutstandingNetworkRequestFetch"|"OutstandingNetworkRequestXHR"|"AppBanner"|"Printing"|"WebDatabase"|"PictureInPicture"|"Portal"|"SpeechRecognizer"|"IdleManager"|"PaymentManager"|"SpeechSynthesis"|"KeyboardLock"|"WebOTPService"|"OutstandingNetworkRequestDirectSocket"|"InjectedJavascript"|"InjectedStyleSheet"|"Dummy"|"ContentSecurityHandler"|"ContentWebAuthenticationAPI"|"ContentFileChooser"|"ContentSerial"|"ContentFileSystemAccess"|"ContentMediaDevicesDispatcherHost"|"ContentWebBluetooth"|"ContentWebUSB"|"ContentMediaSessionService"|"ContentScreenReader"|"EmbedderPopupBlockerTabHelper"|"EmbedderSafeBrowsingTriggeredPopupBlocker"|"EmbedderSafeBrowsingThreatDetails"|"EmbedderAppBannerManager"|"EmbedderDomDistillerViewerSource"|"EmbedderDomDistillerSelfDeletingRequestDelegate"|"EmbedderOomInterventionTabHelper"|"EmbedderOfflinePage"|"EmbedderChromePasswordManagerClientBindCredentialManager"|"EmbedderPermissionRequestManager"|"EmbedderModalDialog"|"EmbedderExtensions"|"EmbedderExtensionMessaging"|"EmbedderExtensionMessagingForOpenPort"|"EmbedderExtensionSentMessageToCachedFrame";
|
||||
/**
|
||||
* Types of not restored reasons for back-forward cache.
|
||||
*/
|
||||
|
|
@ -10720,6 +10756,11 @@ dependent on the reason:
|
|||
* JavaScript stack trace of when frame was attached, only set if frame initiated from script.
|
||||
*/
|
||||
stack?: Runtime.StackTrace;
|
||||
/**
|
||||
* Identifies the bottom-most script which caused the frame to be labelled
|
||||
as an ad. Only sent if frame is labelled as an ad and id is available.
|
||||
*/
|
||||
adScriptId?: AdScriptId;
|
||||
}
|
||||
/**
|
||||
* Fired when frame no longer has a scheduled navigation.
|
||||
|
|
@ -12668,6 +12709,15 @@ Tokens from that issuer.
|
|||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a storage key given a frame id.
|
||||
*/
|
||||
export type getStorageKeyForFrameParameters = {
|
||||
frameId: Page.FrameId;
|
||||
}
|
||||
export type getStorageKeyForFrameReturnValue = {
|
||||
storageKey: SerializedStorageKey;
|
||||
}
|
||||
/**
|
||||
* Clears storage for origin.
|
||||
*/
|
||||
|
|
@ -15248,13 +15298,30 @@ of scripts is used as end of range.
|
|||
export type removeBreakpointReturnValue = {
|
||||
}
|
||||
/**
|
||||
* Restarts particular call frame from the beginning.
|
||||
* Restarts particular call frame from the beginning. The old, deprecated
|
||||
behavior of `restartFrame` is to stay paused and allow further CDP commands
|
||||
after a restart was scheduled. This can cause problems with restarting, so
|
||||
we now continue execution immediatly after it has been scheduled until we
|
||||
reach the beginning of the restarted frame.
|
||||
|
||||
To stay back-wards compatible, `restartFrame` now expects a `mode`
|
||||
parameter to be present. If the `mode` parameter is missing, `restartFrame`
|
||||
errors out.
|
||||
|
||||
The various return values are deprecated and `callFrames` is always empty.
|
||||
Use the call frames from the `Debugger#paused` events instead, that fires
|
||||
once V8 pauses at the beginning of the restarted function.
|
||||
*/
|
||||
export type restartFrameParameters = {
|
||||
/**
|
||||
* Call frame identifier to evaluate on.
|
||||
*/
|
||||
callFrameId: CallFrameId;
|
||||
/**
|
||||
* The `mode` parameter must be present and set to 'StepInto', otherwise
|
||||
`restartFrame` will error out.
|
||||
*/
|
||||
mode?: "StepInto";
|
||||
}
|
||||
export type restartFrameReturnValue = {
|
||||
/**
|
||||
|
|
@ -17514,7 +17581,6 @@ Error was thrown.
|
|||
"DOMStorage.getDOMStorageItems": DOMStorage.getDOMStorageItemsParameters;
|
||||
"DOMStorage.removeDOMStorageItem": DOMStorage.removeDOMStorageItemParameters;
|
||||
"DOMStorage.setDOMStorageItem": DOMStorage.setDOMStorageItemParameters;
|
||||
"DOMStorage.getStorageKeyForFrame": DOMStorage.getStorageKeyForFrameParameters;
|
||||
"Database.disable": Database.disableParameters;
|
||||
"Database.enable": Database.enableParameters;
|
||||
"Database.executeSQL": Database.executeSQLParameters;
|
||||
|
|
@ -17547,6 +17613,7 @@ Error was thrown.
|
|||
"Emulation.setTimezoneOverride": Emulation.setTimezoneOverrideParameters;
|
||||
"Emulation.setVisibleSize": Emulation.setVisibleSizeParameters;
|
||||
"Emulation.setDisabledImageTypes": Emulation.setDisabledImageTypesParameters;
|
||||
"Emulation.setHardwareConcurrencyOverride": Emulation.setHardwareConcurrencyOverrideParameters;
|
||||
"Emulation.setUserAgentOverride": Emulation.setUserAgentOverrideParameters;
|
||||
"Emulation.setAutomationOverride": Emulation.setAutomationOverrideParameters;
|
||||
"HeadlessExperimental.beginFrame": HeadlessExperimental.beginFrameParameters;
|
||||
|
|
@ -17744,6 +17811,7 @@ Error was thrown.
|
|||
"ServiceWorker.stopWorker": ServiceWorker.stopWorkerParameters;
|
||||
"ServiceWorker.unregister": ServiceWorker.unregisterParameters;
|
||||
"ServiceWorker.updateRegistration": ServiceWorker.updateRegistrationParameters;
|
||||
"Storage.getStorageKeyForFrame": Storage.getStorageKeyForFrameParameters;
|
||||
"Storage.clearDataForOrigin": Storage.clearDataForOriginParameters;
|
||||
"Storage.getCookies": Storage.getCookiesParameters;
|
||||
"Storage.setCookies": Storage.setCookiesParameters;
|
||||
|
|
@ -18044,7 +18112,6 @@ Error was thrown.
|
|||
"DOMStorage.getDOMStorageItems": DOMStorage.getDOMStorageItemsReturnValue;
|
||||
"DOMStorage.removeDOMStorageItem": DOMStorage.removeDOMStorageItemReturnValue;
|
||||
"DOMStorage.setDOMStorageItem": DOMStorage.setDOMStorageItemReturnValue;
|
||||
"DOMStorage.getStorageKeyForFrame": DOMStorage.getStorageKeyForFrameReturnValue;
|
||||
"Database.disable": Database.disableReturnValue;
|
||||
"Database.enable": Database.enableReturnValue;
|
||||
"Database.executeSQL": Database.executeSQLReturnValue;
|
||||
|
|
@ -18077,6 +18144,7 @@ Error was thrown.
|
|||
"Emulation.setTimezoneOverride": Emulation.setTimezoneOverrideReturnValue;
|
||||
"Emulation.setVisibleSize": Emulation.setVisibleSizeReturnValue;
|
||||
"Emulation.setDisabledImageTypes": Emulation.setDisabledImageTypesReturnValue;
|
||||
"Emulation.setHardwareConcurrencyOverride": Emulation.setHardwareConcurrencyOverrideReturnValue;
|
||||
"Emulation.setUserAgentOverride": Emulation.setUserAgentOverrideReturnValue;
|
||||
"Emulation.setAutomationOverride": Emulation.setAutomationOverrideReturnValue;
|
||||
"HeadlessExperimental.beginFrame": HeadlessExperimental.beginFrameReturnValue;
|
||||
|
|
@ -18274,6 +18342,7 @@ Error was thrown.
|
|||
"ServiceWorker.stopWorker": ServiceWorker.stopWorkerReturnValue;
|
||||
"ServiceWorker.unregister": ServiceWorker.unregisterReturnValue;
|
||||
"ServiceWorker.updateRegistration": ServiceWorker.updateRegistrationReturnValue;
|
||||
"Storage.getStorageKeyForFrame": Storage.getStorageKeyForFrameReturnValue;
|
||||
"Storage.clearDataForOrigin": Storage.clearDataForOriginReturnValue;
|
||||
"Storage.getCookies": Storage.getCookiesReturnValue;
|
||||
"Storage.setCookies": Storage.setCookiesReturnValue;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@
|
|||
"defaultBrowserType": "webkit"
|
||||
},
|
||||
"Galaxy S5": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 360,
|
||||
"height": 640
|
||||
|
|
@ -121,7 +121,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Galaxy S5 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 640,
|
||||
"height": 360
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Galaxy S8": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 360,
|
||||
"height": 740
|
||||
|
|
@ -143,7 +143,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Galaxy S8 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 740,
|
||||
"height": 360
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Galaxy S9+": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 320,
|
||||
"height": 658
|
||||
|
|
@ -165,7 +165,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Galaxy S9+ landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 658,
|
||||
"height": 320
|
||||
|
|
@ -176,7 +176,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Galaxy Tab S4": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 712,
|
||||
"height": 1138
|
||||
|
|
@ -187,7 +187,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Galaxy Tab S4 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 1138,
|
||||
"height": 712
|
||||
|
|
@ -858,7 +858,7 @@
|
|||
"defaultBrowserType": "webkit"
|
||||
},
|
||||
"LG Optimus L70": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 384,
|
||||
"height": 640
|
||||
|
|
@ -869,7 +869,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"LG Optimus L70 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 640,
|
||||
"height": 384
|
||||
|
|
@ -880,7 +880,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Microsoft Lumia 550": {
|
||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36 Edge/14.14263",
|
||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36 Edge/14.14263",
|
||||
"viewport": {
|
||||
"width": 640,
|
||||
"height": 360
|
||||
|
|
@ -891,7 +891,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Microsoft Lumia 550 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36 Edge/14.14263",
|
||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36 Edge/14.14263",
|
||||
"viewport": {
|
||||
"width": 360,
|
||||
"height": 640
|
||||
|
|
@ -902,7 +902,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Microsoft Lumia 950": {
|
||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36 Edge/14.14263",
|
||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36 Edge/14.14263",
|
||||
"viewport": {
|
||||
"width": 360,
|
||||
"height": 640
|
||||
|
|
@ -913,7 +913,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Microsoft Lumia 950 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36 Edge/14.14263",
|
||||
"userAgent": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36 Edge/14.14263",
|
||||
"viewport": {
|
||||
"width": 640,
|
||||
"height": 360
|
||||
|
|
@ -924,7 +924,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 10": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 800,
|
||||
"height": 1280
|
||||
|
|
@ -935,7 +935,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 10 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 1280,
|
||||
"height": 800
|
||||
|
|
@ -946,7 +946,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 4": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 384,
|
||||
"height": 640
|
||||
|
|
@ -957,7 +957,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 4 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 640,
|
||||
"height": 384
|
||||
|
|
@ -968,7 +968,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 5": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 360,
|
||||
"height": 640
|
||||
|
|
@ -979,7 +979,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 5 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 640,
|
||||
"height": 360
|
||||
|
|
@ -990,7 +990,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 5X": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 412,
|
||||
"height": 732
|
||||
|
|
@ -1001,7 +1001,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 5X landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 732,
|
||||
"height": 412
|
||||
|
|
@ -1012,7 +1012,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 6": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 412,
|
||||
"height": 732
|
||||
|
|
@ -1023,7 +1023,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 6 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 732,
|
||||
"height": 412
|
||||
|
|
@ -1034,7 +1034,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 6P": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 412,
|
||||
"height": 732
|
||||
|
|
@ -1045,7 +1045,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 6P landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 732,
|
||||
"height": 412
|
||||
|
|
@ -1056,7 +1056,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 7": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 600,
|
||||
"height": 960
|
||||
|
|
@ -1067,7 +1067,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Nexus 7 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 960,
|
||||
"height": 600
|
||||
|
|
@ -1122,7 +1122,7 @@
|
|||
"defaultBrowserType": "webkit"
|
||||
},
|
||||
"Pixel 2": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 411,
|
||||
"height": 731
|
||||
|
|
@ -1133,7 +1133,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 2 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 731,
|
||||
"height": 411
|
||||
|
|
@ -1144,7 +1144,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 2 XL": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 411,
|
||||
"height": 823
|
||||
|
|
@ -1155,7 +1155,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 2 XL landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 823,
|
||||
"height": 411
|
||||
|
|
@ -1166,7 +1166,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 3": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 393,
|
||||
"height": 786
|
||||
|
|
@ -1177,7 +1177,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 3 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 786,
|
||||
"height": 393
|
||||
|
|
@ -1188,7 +1188,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 4": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 353,
|
||||
"height": 745
|
||||
|
|
@ -1199,7 +1199,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 4 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 745,
|
||||
"height": 353
|
||||
|
|
@ -1210,7 +1210,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 4a (5G)": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"screen": {
|
||||
"width": 412,
|
||||
"height": 892
|
||||
|
|
@ -1225,7 +1225,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 4a (5G) landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"screen": {
|
||||
"height": 892,
|
||||
"width": 412
|
||||
|
|
@ -1240,7 +1240,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 5": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"screen": {
|
||||
"width": 393,
|
||||
"height": 851
|
||||
|
|
@ -1255,7 +1255,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Pixel 5 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"screen": {
|
||||
"width": 851,
|
||||
"height": 393
|
||||
|
|
@ -1270,7 +1270,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Moto G4": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 360,
|
||||
"height": 640
|
||||
|
|
@ -1281,7 +1281,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Moto G4 landscape": {
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Mobile Safari/537.36",
|
||||
"viewport": {
|
||||
"width": 640,
|
||||
"height": 360
|
||||
|
|
@ -1292,7 +1292,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Desktop Chrome HiDPI": {
|
||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Safari/537.36",
|
||||
"screen": {
|
||||
"width": 1792,
|
||||
"height": 1120
|
||||
|
|
@ -1307,7 +1307,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Desktop Edge HiDPI": {
|
||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36 Edg/103.0.5060.53",
|
||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Safari/537.36 Edg/104.0.5112.20",
|
||||
"screen": {
|
||||
"width": 1792,
|
||||
"height": 1120
|
||||
|
|
@ -1352,7 +1352,7 @@
|
|||
"defaultBrowserType": "webkit"
|
||||
},
|
||||
"Desktop Chrome": {
|
||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Safari/537.36",
|
||||
"screen": {
|
||||
"width": 1920,
|
||||
"height": 1080
|
||||
|
|
@ -1367,7 +1367,7 @@
|
|||
"defaultBrowserType": "chromium"
|
||||
},
|
||||
"Desktop Edge": {
|
||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36 Edg/103.0.5060.53",
|
||||
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.20 Safari/537.36 Edg/104.0.5112.20",
|
||||
"screen": {
|
||||
"width": 1920,
|
||||
"height": 1080
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import type { DispatcherScope } from './dispatcher';
|
|||
import { Dispatcher } from './dispatcher';
|
||||
import { yazl, yauzl } from '../../zipBundle';
|
||||
import { ZipFile } from '../../utils/zipFile';
|
||||
import type { HAREntry, HARFile, HARHeader } from '../../../types/har';
|
||||
import type * as har from '../har/har';
|
||||
import type { HeadersArray } from '../types';
|
||||
|
||||
export class LocalUtilsDispatcher extends Dispatcher<{ guid: string }, channels.LocalUtilsChannel> implements channels.LocalUtilsChannel {
|
||||
|
|
@ -100,10 +100,10 @@ export class LocalUtilsDispatcher extends Dispatcher<{ guid: string }, channels.
|
|||
if (!harEntryName)
|
||||
return { error: 'Specified archive does not have a .har file' };
|
||||
const har = await zipFile.read(harEntryName);
|
||||
const harFile = JSON.parse(har.toString()) as HARFile;
|
||||
const harFile = JSON.parse(har.toString()) as har.HARFile;
|
||||
harBackend = new HarBackend(harFile, null, zipFile);
|
||||
} else {
|
||||
const harFile = JSON.parse(await fs.promises.readFile(params.file, 'utf-8')) as HARFile;
|
||||
const harFile = JSON.parse(await fs.promises.readFile(params.file, 'utf-8')) as har.HARFile;
|
||||
harBackend = new HarBackend(harFile, path.dirname(params.file), null);
|
||||
}
|
||||
this._harBakends.set(harBackend.id, harBackend);
|
||||
|
|
@ -130,11 +130,11 @@ const redirectStatus = [301, 302, 303, 307, 308];
|
|||
|
||||
class HarBackend {
|
||||
readonly id = createGuid();
|
||||
private _harFile: HARFile;
|
||||
private _harFile: har.HARFile;
|
||||
private _zipFile: ZipFile | null;
|
||||
private _baseDir: string | null;
|
||||
|
||||
constructor(harFile: HARFile, baseDir: string | null, zipFile: ZipFile | null) {
|
||||
constructor(harFile: har.HARFile, baseDir: string | null, zipFile: ZipFile | null) {
|
||||
this._harFile = harFile;
|
||||
this._baseDir = baseDir;
|
||||
this._zipFile = zipFile;
|
||||
|
|
@ -176,25 +176,25 @@ class HarBackend {
|
|||
}
|
||||
}
|
||||
|
||||
private async _loadContent(content: { text?: string, encoding?: string, _sha1?: string }): Promise<Buffer> {
|
||||
const sha1 = content._sha1;
|
||||
private async _loadContent(content: { text?: string, encoding?: string, _file?: string }): Promise<Buffer> {
|
||||
const file = content._file;
|
||||
let buffer: Buffer;
|
||||
if (sha1) {
|
||||
if (file) {
|
||||
if (this._zipFile)
|
||||
buffer = await this._zipFile.read(sha1);
|
||||
buffer = await this._zipFile.read(file);
|
||||
else
|
||||
buffer = await fs.promises.readFile(path.resolve(this._baseDir!, sha1));
|
||||
buffer = await fs.promises.readFile(path.resolve(this._baseDir!, file));
|
||||
} else {
|
||||
buffer = Buffer.from(content.text || '', content.encoding === 'base64' ? 'base64' : 'utf-8');
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private async _harFindResponse(url: string, method: string, headers: HeadersArray, postData: Buffer | undefined): Promise<HAREntry | undefined> {
|
||||
private async _harFindResponse(url: string, method: string, headers: HeadersArray, postData: Buffer | undefined): Promise<har.Entry | undefined> {
|
||||
const harLog = this._harFile.log;
|
||||
const visited = new Set<HAREntry>();
|
||||
const visited = new Set<har.Entry>();
|
||||
while (true) {
|
||||
const entries: HAREntry[] = [];
|
||||
const entries: har.Entry[] = [];
|
||||
for (const candidate of harLog.entries) {
|
||||
if (candidate.request.url !== url || candidate.request.method !== method)
|
||||
continue;
|
||||
|
|
@ -213,7 +213,7 @@ class HarBackend {
|
|||
|
||||
// Disambiguate using headers - then one with most matching headers wins.
|
||||
if (entries.length > 1) {
|
||||
const list: { candidate: HAREntry, matchingHeaders: number }[] = [];
|
||||
const list: { candidate: har.Entry, matchingHeaders: number }[] = [];
|
||||
for (const candidate of entries) {
|
||||
const matchingHeaders = countMatchingHeaders(candidate.request.headers, headers);
|
||||
list.push({ candidate, matchingHeaders });
|
||||
|
|
@ -249,7 +249,7 @@ class HarBackend {
|
|||
}
|
||||
}
|
||||
|
||||
function countMatchingHeaders(harHeaders: HARHeader[], headers: HeadersArray): number {
|
||||
function countMatchingHeaders(harHeaders: har.Header[], headers: HeadersArray): number {
|
||||
const set = new Set(headers.map(h => h.name.toLowerCase() + ':' + h.value));
|
||||
let matches = 0;
|
||||
for (const h of harHeaders) {
|
||||
|
|
|
|||
|
|
@ -135,7 +135,11 @@ export class RouteDispatcher extends Dispatcher<Route, channels.RouteChannel> im
|
|||
}
|
||||
|
||||
async abort(params: channels.RouteAbortParams): Promise<void> {
|
||||
await this._object.abort(params.errorCode || 'failed', params.redirectAbortedNavigationToUrl);
|
||||
await this._object.abort(params.errorCode || 'failed');
|
||||
}
|
||||
|
||||
async redirectNavigationRequest(params: channels.RouteRedirectNavigationRequestParams): Promise<void> {
|
||||
await this._object.redirectNavigationRequest(params.url);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ export class FrameManager {
|
|||
name: frame._name,
|
||||
newDocument: frame.pendingDocument(),
|
||||
error: new NavigationAbortedError(documentId, errorText),
|
||||
isPublic: !frame._pendingNavigationRedirectAfterAbort
|
||||
isPublic: !(documentId && frame._redirectedNavigations.has(documentId)),
|
||||
};
|
||||
frame.setPendingDocument(undefined);
|
||||
frame.emit(Frame.Events.InternalNavigation, navigationEvent);
|
||||
|
|
@ -467,7 +467,7 @@ export class Frame extends SdkObject {
|
|||
readonly _detachedPromise: Promise<void>;
|
||||
private _detachedCallback = () => {};
|
||||
private _raceAgainstEvaluationStallingEventsPromises = new Set<ManualPromise<any>>();
|
||||
_pendingNavigationRedirectAfterAbort: { url: string, documentId: string } | undefined;
|
||||
readonly _redirectedNavigations = new Map<string, { url: string, gotoPromise: Promise<network.Response | null> }>(); // documentId -> data
|
||||
|
||||
constructor(page: Page, id: string, parentFrame: Frame | null) {
|
||||
super(page, 'frame');
|
||||
|
|
@ -604,12 +604,11 @@ export class Frame extends SdkObject {
|
|||
this._page._crashedPromise.then(() => { throw new Error('Navigation failed because page crashed!'); }),
|
||||
this._detachedPromise.then(() => { throw new Error('Navigating frame was detached!'); }),
|
||||
action().catch(e => {
|
||||
if (this._pendingNavigationRedirectAfterAbort && e instanceof NavigationAbortedError) {
|
||||
const { url, documentId } = this._pendingNavigationRedirectAfterAbort;
|
||||
this._pendingNavigationRedirectAfterAbort = undefined;
|
||||
if (e.documentId === documentId) {
|
||||
progress.log(`redirecting navigation to "${url}"`);
|
||||
return this._gotoAction(progress, url, options);
|
||||
if (e instanceof NavigationAbortedError && e.documentId) {
|
||||
const data = this._redirectedNavigations.get(e.documentId);
|
||||
if (data) {
|
||||
progress.log(`waiting for redirected navigation to "${data.url}"`);
|
||||
return data.gotoPromise;
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
|
|
@ -617,8 +616,14 @@ export class Frame extends SdkObject {
|
|||
]);
|
||||
}
|
||||
|
||||
redirectNavigationAfterAbort(url: string, documentId: string) {
|
||||
this._pendingNavigationRedirectAfterAbort = { url, documentId };
|
||||
redirectNavigation(url: string, documentId: string, referer: string | undefined) {
|
||||
const controller = new ProgressController(serverSideCallMetadata(), this);
|
||||
const data = {
|
||||
url,
|
||||
gotoPromise: controller.run(progress => this._gotoAction(progress, url, { referer }), 0),
|
||||
};
|
||||
this._redirectedNavigations.set(documentId, data);
|
||||
data.gotoPromise.finally(() => this._redirectedNavigations.delete(documentId));
|
||||
}
|
||||
|
||||
async goto(metadata: CallMetadata, url: string, options: types.GotoOptions = {}): Promise<network.Response | null> {
|
||||
|
|
@ -659,7 +664,7 @@ export class Frame extends SdkObject {
|
|||
if (event.newDocument!.documentId !== navigateResult.newDocumentId) {
|
||||
// This is just a sanity check. In practice, new navigation should
|
||||
// cancel the previous one and report "request cancelled"-like error.
|
||||
throw new Error('Navigation interrupted by another one');
|
||||
throw new NavigationAbortedError(navigateResult.newDocumentId, 'Navigation interrupted by another one');
|
||||
}
|
||||
if (event.error)
|
||||
throw event.error;
|
||||
|
|
|
|||
|
|
@ -22,19 +22,22 @@ export type HARFile = {
|
|||
export type Log = {
|
||||
version: string;
|
||||
creator: Creator;
|
||||
browser: Browser;
|
||||
pages: Page[];
|
||||
browser?: Browser;
|
||||
pages?: Page[];
|
||||
entries: Entry[];
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type Creator = {
|
||||
name: string;
|
||||
version: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type Browser = {
|
||||
name: string;
|
||||
version: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type Page = {
|
||||
|
|
@ -42,11 +45,13 @@ export type Page = {
|
|||
id: string;
|
||||
title: string;
|
||||
pageTimings: PageTimings;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type PageTimings = {
|
||||
onContentLoad: number;
|
||||
onLoad: number;
|
||||
onContentLoad?: number;
|
||||
onLoad?: number;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type Entry = {
|
||||
|
|
@ -59,9 +64,8 @@ export type Entry = {
|
|||
timings: Timings;
|
||||
serverIPAddress?: string;
|
||||
connection?: string;
|
||||
_requestref: string;
|
||||
_frameref: string;
|
||||
_monotonicTime: number;
|
||||
_frameref?: string;
|
||||
_monotonicTime?: number;
|
||||
_serverPort?: number;
|
||||
_securityDetails?: SecurityDetails;
|
||||
};
|
||||
|
|
@ -76,6 +80,7 @@ export type Request = {
|
|||
postData?: PostData;
|
||||
headersSize: number;
|
||||
bodySize: number;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type Response = {
|
||||
|
|
@ -88,7 +93,8 @@ export type Response = {
|
|||
redirectURL: string;
|
||||
headersSize: number;
|
||||
bodySize: number;
|
||||
_transferSize: number;
|
||||
comment?: string;
|
||||
_transferSize?: number;
|
||||
_failureText?: string
|
||||
};
|
||||
|
||||
|
|
@ -101,23 +107,28 @@ export type Cookie = {
|
|||
httpOnly?: boolean;
|
||||
secure?: boolean;
|
||||
sameSite?: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type Header = {
|
||||
name: string;
|
||||
value: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type QueryParameter = {
|
||||
name: string;
|
||||
value: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type PostData = {
|
||||
mimeType: string;
|
||||
params: Param[];
|
||||
text: string;
|
||||
comment?: string;
|
||||
_sha1?: string;
|
||||
_file?: string;
|
||||
};
|
||||
|
||||
export type Param = {
|
||||
|
|
@ -125,6 +136,7 @@ export type Param = {
|
|||
value?: string;
|
||||
fileName?: string;
|
||||
contentType?: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type Content = {
|
||||
|
|
@ -133,12 +145,15 @@ export type Content = {
|
|||
mimeType: string;
|
||||
text?: string;
|
||||
encoding?: string;
|
||||
comment?: string;
|
||||
_sha1?: string;
|
||||
_file?: string;
|
||||
};
|
||||
|
||||
export type Cache = {
|
||||
beforeRequest: CacheState | null;
|
||||
afterRequest: CacheState | null;
|
||||
beforeRequest?: CacheState | null;
|
||||
afterRequest?: CacheState | null;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type CacheState = {
|
||||
|
|
@ -146,6 +161,7 @@ export type CacheState = {
|
|||
lastAccess: string;
|
||||
eTag: string;
|
||||
hitCount: number;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type Timings = {
|
||||
|
|
@ -156,6 +172,7 @@ export type Timings = {
|
|||
wait: number;
|
||||
receive: number;
|
||||
ssl?: number;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type SecurityDetails = {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export class HarRecorder {
|
|||
private _tracer: HarTracer;
|
||||
private _entries: har.Entry[] = [];
|
||||
private _zipFile: ZipFile | null = null;
|
||||
private _writtenZipEntries = new Set<string>();
|
||||
|
||||
constructor(context: BrowserContext, options: channels.RecordHarOptions) {
|
||||
this._artifact = new Artifact(context, path.join(context._browser.options.artifactsDir, `${createGuid()}.har`));
|
||||
|
|
@ -41,6 +42,8 @@ export class HarRecorder {
|
|||
const content = options.content || (expectsZip ? 'attach' : 'embed');
|
||||
this._tracer = new HarTracer(context, this, {
|
||||
content,
|
||||
slimMode: options.mode === 'minimal',
|
||||
includeTraceInfo: false,
|
||||
waitForContentOnStop: true,
|
||||
skipScripts: false,
|
||||
urlFilter: urlFilterRe ?? options.urlGlob,
|
||||
|
|
@ -57,8 +60,10 @@ export class HarRecorder {
|
|||
}
|
||||
|
||||
onContentBlob(sha1: string, buffer: Buffer) {
|
||||
if (this._zipFile)
|
||||
this._zipFile!.addBuffer(buffer, sha1);
|
||||
if (!this._zipFile || this._writtenZipEntries.has(sha1))
|
||||
return;
|
||||
this._writtenZipEntries.add(sha1);
|
||||
this._zipFile!.addBuffer(buffer, sha1);
|
||||
}
|
||||
|
||||
async flush() {
|
||||
|
|
@ -70,7 +75,7 @@ export class HarRecorder {
|
|||
const log = this._tracer.stop();
|
||||
log.entries = this._entries;
|
||||
|
||||
const harFileContent = JSON.stringify({ log }, undefined, 2);
|
||||
const harFileContent = jsonStringify({ log });
|
||||
|
||||
if (this._zipFile) {
|
||||
const result = new ManualPromise<void>();
|
||||
|
|
@ -92,3 +97,50 @@ export class HarRecorder {
|
|||
return this._artifact;
|
||||
}
|
||||
}
|
||||
|
||||
function jsonStringify(object: any): string {
|
||||
const tokens: string[] = [];
|
||||
innerJsonStringify(object, tokens, '', false, undefined);
|
||||
return tokens.join('');
|
||||
}
|
||||
|
||||
function innerJsonStringify(object: any, tokens: string[], indent: string, flat: boolean, parentKey: string | undefined) {
|
||||
if (typeof object !== 'object' || object === null) {
|
||||
tokens.push(JSON.stringify(object));
|
||||
return;
|
||||
}
|
||||
|
||||
const isArray = Array.isArray(object);
|
||||
if (!isArray && object.constructor.name !== 'Object') {
|
||||
tokens.push(JSON.stringify(object));
|
||||
return;
|
||||
}
|
||||
|
||||
const entries = isArray ? object : Object.entries(object).filter(e => e[1] !== undefined);
|
||||
if (!entries.length) {
|
||||
tokens.push(isArray ? `[]` : `{}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const childIndent = `${indent} `;
|
||||
let brackets: { open: string, close: string };
|
||||
if (isArray)
|
||||
brackets = flat ? { open: '[', close: ']' } : { open: `[\n${childIndent}`, close: `\n${indent}]` };
|
||||
else
|
||||
brackets = flat ? { open: '{ ', close: ' }' } : { open: `{\n${childIndent}`, close: `\n${indent}}` };
|
||||
|
||||
tokens.push(brackets.open);
|
||||
|
||||
for (let i = 0; i < entries.length; ++i) {
|
||||
const entry = entries[i];
|
||||
if (i)
|
||||
tokens.push(flat ? `, ` : `,\n${childIndent}`);
|
||||
if (!isArray)
|
||||
tokens.push(`${JSON.stringify(entry[0])}: `);
|
||||
const key = isArray ? undefined : entry[0];
|
||||
const flatten = flat || key === 'timings' || parentKey === 'headers';
|
||||
innerJsonStringify(isArray ? entry : entry[1], tokens, childIndent, flatten, key);
|
||||
}
|
||||
|
||||
tokens.push(brackets.close);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,16 @@ export interface HarTracerDelegate {
|
|||
type HarTracerOptions = {
|
||||
content: 'omit' | 'attach' | 'embed';
|
||||
skipScripts: boolean;
|
||||
includeTraceInfo: boolean;
|
||||
waitForContentOnStop: boolean;
|
||||
urlFilter?: string | RegExp;
|
||||
slimMode?: boolean;
|
||||
omitSecurityDetails?: boolean;
|
||||
omitCookies?: boolean;
|
||||
omitTiming?: boolean;
|
||||
omitServerIP?: boolean;
|
||||
omitPages?: boolean;
|
||||
omitSizes?: boolean;
|
||||
};
|
||||
|
||||
export class HarTracer {
|
||||
|
|
@ -61,6 +69,14 @@ export class HarTracer {
|
|||
this._context = context;
|
||||
this._delegate = delegate;
|
||||
this._options = options;
|
||||
if (options.slimMode) {
|
||||
options.omitSecurityDetails = true;
|
||||
options.omitCookies = true;
|
||||
options.omitTiming = true;
|
||||
options.omitServerIP = true;
|
||||
options.omitSizes = true;
|
||||
options.omitPages = true;
|
||||
}
|
||||
this._entrySymbol = Symbol('requestHarEntry');
|
||||
this._baseURL = context instanceof APIRequestContext ? context._defaultOptions().baseURL : context._options.baseURL;
|
||||
}
|
||||
|
|
@ -92,32 +108,34 @@ export class HarTracer {
|
|||
return (request as any)[this._entrySymbol];
|
||||
}
|
||||
|
||||
private _ensurePageEntry(page: Page) {
|
||||
private _ensurePageEntry(page: Page): har.Page | undefined {
|
||||
if (this._options.omitPages)
|
||||
return;
|
||||
let pageEntry = this._pageEntries.get(page);
|
||||
if (!pageEntry) {
|
||||
page.mainFrame().on(Frame.Events.AddLifecycle, (event: LifecycleEvent) => {
|
||||
if (event === 'load')
|
||||
this._onLoad(page);
|
||||
if (event === 'domcontentloaded')
|
||||
this._onDOMContentLoaded(page);
|
||||
});
|
||||
|
||||
pageEntry = {
|
||||
startedDateTime: new Date(),
|
||||
id: page.guid,
|
||||
title: '',
|
||||
pageTimings: {
|
||||
pageTimings: this._options.omitTiming ? {} : {
|
||||
onContentLoad: -1,
|
||||
onLoad: -1,
|
||||
},
|
||||
};
|
||||
|
||||
page.mainFrame().on(Frame.Events.AddLifecycle, (event: LifecycleEvent) => {
|
||||
if (event === 'load')
|
||||
this._onLoad(page, pageEntry!);
|
||||
if (event === 'domcontentloaded')
|
||||
this._onDOMContentLoaded(page, pageEntry!);
|
||||
});
|
||||
|
||||
this._pageEntries.set(page, pageEntry);
|
||||
}
|
||||
return pageEntry;
|
||||
}
|
||||
|
||||
private _onDOMContentLoaded(page: Page) {
|
||||
const pageEntry = this._ensurePageEntry(page);
|
||||
private _onDOMContentLoaded(page: Page, pageEntry: har.Page) {
|
||||
const promise = page.mainFrame().evaluateExpression(String(() => {
|
||||
return {
|
||||
title: document.title,
|
||||
|
|
@ -125,13 +143,13 @@ export class HarTracer {
|
|||
};
|
||||
}), true, undefined, 'utility').then(result => {
|
||||
pageEntry.title = result.title;
|
||||
pageEntry.pageTimings.onContentLoad = result.domContentLoaded;
|
||||
if (!this._options.omitTiming)
|
||||
pageEntry.pageTimings.onContentLoad = result.domContentLoaded;
|
||||
}).catch(() => {});
|
||||
this._addBarrier(page, promise);
|
||||
}
|
||||
|
||||
private _onLoad(page: Page) {
|
||||
const pageEntry = this._ensurePageEntry(page);
|
||||
private _onLoad(page: Page, pageEntry: har.Page) {
|
||||
const promise = page.mainFrame().evaluateExpression(String(() => {
|
||||
return {
|
||||
title: document.title,
|
||||
|
|
@ -139,7 +157,8 @@ export class HarTracer {
|
|||
};
|
||||
}), true, undefined, 'utility').then(result => {
|
||||
pageEntry.title = result.title;
|
||||
pageEntry.pageTimings.onLoad = result.loaded;
|
||||
if (!this._options.omitTiming)
|
||||
pageEntry.pageTimings.onLoad = result.loaded;
|
||||
}).catch(() => {});
|
||||
this._addBarrier(page, promise);
|
||||
}
|
||||
|
|
@ -161,11 +180,13 @@ export class HarTracer {
|
|||
private _onAPIRequest(event: APIRequestEvent) {
|
||||
if (!this._shouldIncludeEntryWithUrl(event.url.toString()))
|
||||
return;
|
||||
const harEntry = createHarEntry(event.method, event.url, '', '');
|
||||
harEntry.request.cookies = event.cookies;
|
||||
const harEntry = createHarEntry(event.method, event.url, undefined, this._options);
|
||||
if (!this._options.omitCookies)
|
||||
harEntry.request.cookies = event.cookies;
|
||||
harEntry.request.headers = Object.entries(event.headers).map(([name, value]) => ({ name, value }));
|
||||
harEntry.request.postData = this._postDataForBuffer(event.postData || null, event.headers['content-type'], this._options.content);
|
||||
harEntry.request.bodySize = event.postData?.length || 0;
|
||||
if (!this._options.omitSizes)
|
||||
harEntry.request.bodySize = event.postData?.length || 0;
|
||||
(event as any)[this._entrySymbol] = harEntry;
|
||||
if (this._started)
|
||||
this._delegate.onEntryStarted(harEntry);
|
||||
|
|
@ -186,7 +207,7 @@ export class HarTracer {
|
|||
value: event.rawHeaders[i + 1]
|
||||
});
|
||||
}
|
||||
harEntry.response.cookies = event.cookies.map(c => {
|
||||
harEntry.response.cookies = this._options.omitCookies ? [] : event.cookies.map(c => {
|
||||
return {
|
||||
...c,
|
||||
expires: c.expires === -1 ? undefined : new Date(c.expires)
|
||||
|
|
@ -212,10 +233,12 @@ export class HarTracer {
|
|||
return;
|
||||
|
||||
const pageEntry = this._ensurePageEntry(page);
|
||||
const harEntry = createHarEntry(request.method(), url, request.guid, request.frame().guid);
|
||||
harEntry.pageref = pageEntry.id;
|
||||
const harEntry = createHarEntry(request.method(), url, request.frame().guid, this._options);
|
||||
if (pageEntry)
|
||||
harEntry.pageref = pageEntry.id;
|
||||
harEntry.request.postData = this._postDataForRequest(request, this._options.content);
|
||||
harEntry.request.bodySize = request.bodySize();
|
||||
if (!this._options.omitSizes)
|
||||
harEntry.request.bodySize = request.bodySize();
|
||||
if (request.redirectedFrom()) {
|
||||
const fromEntry = this._entryForRequest(request.redirectedFrom()!);
|
||||
if (fromEntry)
|
||||
|
|
@ -238,7 +261,7 @@ export class HarTracer {
|
|||
harEntry.request.httpVersion = httpVersion;
|
||||
harEntry.response.httpVersion = httpVersion;
|
||||
|
||||
const compressionCalculationBarrier = {
|
||||
const compressionCalculationBarrier = this._options.omitSizes ? undefined : {
|
||||
_encodedBodySize: -1,
|
||||
_decodedBodySize: -1,
|
||||
barrier: new ManualPromise<void>(),
|
||||
|
|
@ -257,32 +280,36 @@ export class HarTracer {
|
|||
this._check();
|
||||
}
|
||||
};
|
||||
this._addBarrier(page, compressionCalculationBarrier.barrier);
|
||||
if (compressionCalculationBarrier)
|
||||
this._addBarrier(page, compressionCalculationBarrier.barrier);
|
||||
|
||||
const promise = response.body().then(buffer => {
|
||||
if (this._options.skipScripts && request.resourceType() === 'script') {
|
||||
compressionCalculationBarrier.setDecodedBodySize(0);
|
||||
compressionCalculationBarrier?.setDecodedBodySize(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const content = harEntry.response.content;
|
||||
compressionCalculationBarrier.setDecodedBodySize(buffer.length);
|
||||
compressionCalculationBarrier?.setDecodedBodySize(buffer.length);
|
||||
this._storeResponseContent(buffer, content, request.resourceType());
|
||||
}).catch(() => {
|
||||
compressionCalculationBarrier.setDecodedBodySize(0);
|
||||
compressionCalculationBarrier?.setDecodedBodySize(0);
|
||||
}).then(() => {
|
||||
if (this._started)
|
||||
this._delegate.onEntryFinished(harEntry);
|
||||
});
|
||||
this._addBarrier(page, promise);
|
||||
this._addBarrier(page, response.sizes().then(sizes => {
|
||||
harEntry.response.bodySize = sizes.responseBodySize;
|
||||
harEntry.response.headersSize = sizes.responseHeadersSize;
|
||||
// Fallback for WebKit by calculating it manually
|
||||
harEntry.response._transferSize = response.request().responseSize.transferSize || (sizes.responseHeadersSize + sizes.responseBodySize);
|
||||
harEntry.request.headersSize = sizes.requestHeadersSize;
|
||||
compressionCalculationBarrier.setEncodedBodySize(sizes.responseBodySize);
|
||||
}));
|
||||
|
||||
if (!this._options.omitSizes) {
|
||||
this._addBarrier(page, response.sizes().then(sizes => {
|
||||
harEntry.response.bodySize = sizes.responseBodySize;
|
||||
harEntry.response.headersSize = sizes.responseHeadersSize;
|
||||
// Fallback for WebKit by calculating it manually
|
||||
harEntry.response._transferSize = response.request().responseSize.transferSize || (sizes.responseHeadersSize + sizes.responseBodySize);
|
||||
harEntry.request.headersSize = sizes.requestHeadersSize;
|
||||
compressionCalculationBarrier?.setEncodedBodySize(sizes.responseBodySize);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private async _onRequestFailed(request: network.Request) {
|
||||
|
|
@ -301,7 +328,10 @@ export class HarTracer {
|
|||
content.size = 0;
|
||||
return;
|
||||
}
|
||||
content.size = buffer.length;
|
||||
|
||||
if (!this._options.omitSizes)
|
||||
content.size = buffer.length;
|
||||
|
||||
if (this._options.content === 'embed') {
|
||||
// Sometimes, we can receive a font/media file with textual mime type. Browser
|
||||
// still interprets them correctly, but the 'content-type' header is obviously wrong.
|
||||
|
|
@ -312,9 +342,13 @@ export class HarTracer {
|
|||
content.encoding = 'base64';
|
||||
}
|
||||
} else if (this._options.content === 'attach') {
|
||||
content._sha1 = calculateSha1(buffer) + '.' + (mime.getExtension(content.mimeType) || 'dat');
|
||||
const sha1 = calculateSha1(buffer) + '.' + (mime.getExtension(content.mimeType) || 'dat');
|
||||
if (this._options.includeTraceInfo)
|
||||
content._sha1 = sha1;
|
||||
else
|
||||
content._file = sha1;
|
||||
if (this._started)
|
||||
this._delegate.onContentBlob(content._sha1, buffer);
|
||||
this._delegate.onContentBlob(sha1, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -340,43 +374,56 @@ export class HarTracer {
|
|||
headersSize: -1,
|
||||
bodySize: -1,
|
||||
redirectURL: '',
|
||||
_transferSize: -1
|
||||
_transferSize: this._options.omitSizes ? undefined : -1
|
||||
};
|
||||
const timing = response.timing();
|
||||
if (pageEntry.startedDateTime.valueOf() > timing.startTime)
|
||||
pageEntry.startedDateTime = new Date(timing.startTime);
|
||||
const dns = timing.domainLookupEnd !== -1 ? helper.millisToRoundishMillis(timing.domainLookupEnd - timing.domainLookupStart) : -1;
|
||||
const connect = timing.connectEnd !== -1 ? helper.millisToRoundishMillis(timing.connectEnd - timing.connectStart) : -1;
|
||||
const ssl = timing.connectEnd !== -1 ? helper.millisToRoundishMillis(timing.connectEnd - timing.secureConnectionStart) : -1;
|
||||
const wait = timing.responseStart !== -1 ? helper.millisToRoundishMillis(timing.responseStart - timing.requestStart) : -1;
|
||||
const receive = response.request()._responseEndTiming !== -1 ? helper.millisToRoundishMillis(response.request()._responseEndTiming - timing.responseStart) : -1;
|
||||
harEntry.timings = {
|
||||
dns,
|
||||
connect,
|
||||
ssl,
|
||||
send: 0,
|
||||
wait,
|
||||
receive,
|
||||
};
|
||||
harEntry.time = [dns, connect, ssl, wait, receive].reduce((pre, cur) => cur > 0 ? cur + pre : pre, 0);
|
||||
this._addBarrier(page, response.serverAddr().then(server => {
|
||||
if (server?.ipAddress)
|
||||
harEntry.serverIPAddress = server.ipAddress;
|
||||
if (server?.port)
|
||||
harEntry._serverPort = server.port;
|
||||
}));
|
||||
this._addBarrier(page, response.securityDetails().then(details => {
|
||||
if (details)
|
||||
harEntry._securityDetails = details;
|
||||
}));
|
||||
|
||||
if (!this._options.omitTiming) {
|
||||
const timing = response.timing();
|
||||
if (pageEntry && pageEntry.startedDateTime.valueOf() > timing.startTime)
|
||||
pageEntry.startedDateTime = new Date(timing.startTime);
|
||||
const dns = timing.domainLookupEnd !== -1 ? helper.millisToRoundishMillis(timing.domainLookupEnd - timing.domainLookupStart) : -1;
|
||||
const connect = timing.connectEnd !== -1 ? helper.millisToRoundishMillis(timing.connectEnd - timing.connectStart) : -1;
|
||||
const ssl = timing.connectEnd !== -1 ? helper.millisToRoundishMillis(timing.connectEnd - timing.secureConnectionStart) : -1;
|
||||
const wait = timing.responseStart !== -1 ? helper.millisToRoundishMillis(timing.responseStart - timing.requestStart) : -1;
|
||||
const receive = response.request()._responseEndTiming !== -1 ? helper.millisToRoundishMillis(response.request()._responseEndTiming - timing.responseStart) : -1;
|
||||
|
||||
harEntry.timings = {
|
||||
dns,
|
||||
connect,
|
||||
ssl,
|
||||
send: 0,
|
||||
wait,
|
||||
receive,
|
||||
};
|
||||
harEntry.time = [dns, connect, ssl, wait, receive].reduce((pre, cur) => cur > 0 ? cur + pre : pre, 0);
|
||||
}
|
||||
|
||||
if (!this._options.omitServerIP) {
|
||||
this._addBarrier(page, response.serverAddr().then(server => {
|
||||
if (server?.ipAddress)
|
||||
harEntry.serverIPAddress = server.ipAddress;
|
||||
if (server?.port)
|
||||
harEntry._serverPort = server.port;
|
||||
}));
|
||||
}
|
||||
if (!this._options.omitSecurityDetails) {
|
||||
this._addBarrier(page, response.securityDetails().then(details => {
|
||||
if (details)
|
||||
harEntry._securityDetails = details;
|
||||
}));
|
||||
}
|
||||
this._addBarrier(page, request.rawRequestHeaders().then(headers => {
|
||||
for (const header of headers.filter(header => header.name.toLowerCase() === 'cookie'))
|
||||
harEntry.request.cookies.push(...header.value.split(';').map(parseCookie));
|
||||
if (!this._options.omitCookies) {
|
||||
for (const header of headers.filter(header => header.name.toLowerCase() === 'cookie'))
|
||||
harEntry.request.cookies.push(...header.value.split(';').map(parseCookie));
|
||||
}
|
||||
harEntry.request.headers = headers;
|
||||
}));
|
||||
this._addBarrier(page, response.rawResponseHeaders().then(headers => {
|
||||
for (const header of headers.filter(header => header.name.toLowerCase() === 'set-cookie'))
|
||||
harEntry.response.cookies.push(parseCookie(header.value));
|
||||
if (!this._options.omitCookies) {
|
||||
for (const header of headers.filter(header => header.name.toLowerCase() === 'set-cookie'))
|
||||
harEntry.response.cookies.push(parseCookie(header.value));
|
||||
}
|
||||
harEntry.response.headers = headers;
|
||||
const contentType = headers.find(header => header.name.toLowerCase() === 'content-type');
|
||||
if (contentType)
|
||||
|
|
@ -404,18 +451,20 @@ export class HarTracer {
|
|||
name: context?._browser.options.name || '',
|
||||
version: context?._browser.version() || ''
|
||||
},
|
||||
pages: Array.from(this._pageEntries.values()),
|
||||
pages: this._pageEntries.size ? Array.from(this._pageEntries.values()) : undefined,
|
||||
entries: [],
|
||||
};
|
||||
for (const pageEntry of log.pages) {
|
||||
if (pageEntry.pageTimings.onContentLoad >= 0)
|
||||
pageEntry.pageTimings.onContentLoad -= pageEntry.startedDateTime.valueOf();
|
||||
else
|
||||
pageEntry.pageTimings.onContentLoad = -1;
|
||||
if (pageEntry.pageTimings.onLoad >= 0)
|
||||
pageEntry.pageTimings.onLoad -= pageEntry.startedDateTime.valueOf();
|
||||
else
|
||||
pageEntry.pageTimings.onLoad = -1;
|
||||
if (!this._options.omitTiming) {
|
||||
for (const pageEntry of log.pages || []) {
|
||||
if (typeof pageEntry.pageTimings.onContentLoad === 'number' && pageEntry.pageTimings.onContentLoad >= 0)
|
||||
pageEntry.pageTimings.onContentLoad -= pageEntry.startedDateTime.valueOf();
|
||||
else
|
||||
pageEntry.pageTimings.onContentLoad = -1;
|
||||
if (typeof pageEntry.pageTimings.onLoad === 'number' && pageEntry.pageTimings.onLoad >= 0)
|
||||
pageEntry.pageTimings.onLoad -= pageEntry.startedDateTime.valueOf();
|
||||
else
|
||||
pageEntry.pageTimings.onLoad = -1;
|
||||
}
|
||||
}
|
||||
this._pageEntries.clear();
|
||||
return log;
|
||||
|
|
@ -446,8 +495,12 @@ export class HarTracer {
|
|||
result.text = postData.toString();
|
||||
|
||||
if (content === 'attach') {
|
||||
result._sha1 = calculateSha1(postData) + '.' + (mime.getExtension(contentType) || 'dat');
|
||||
this._delegate.onContentBlob(result._sha1, postData);
|
||||
const sha1 = calculateSha1(postData) + '.' + (mime.getExtension(contentType) || 'dat');
|
||||
if (this._options.includeTraceInfo)
|
||||
result._sha1 = sha1;
|
||||
else
|
||||
result._file = sha1;
|
||||
this._delegate.onContentBlob(sha1, postData);
|
||||
}
|
||||
|
||||
if (contentType === 'application/x-www-form-urlencoded') {
|
||||
|
|
@ -461,11 +514,10 @@ export class HarTracer {
|
|||
|
||||
}
|
||||
|
||||
function createHarEntry(method: string, url: URL, requestref: string, frameref: string): har.Entry {
|
||||
function createHarEntry(method: string, url: URL, frameref: string | undefined, options: HarTracerOptions): har.Entry {
|
||||
const harEntry: har.Entry = {
|
||||
_requestref: requestref,
|
||||
_frameref: frameref,
|
||||
_monotonicTime: monotonicTime(),
|
||||
_frameref: options.includeTraceInfo ? frameref : undefined,
|
||||
_monotonicTime: options.includeTraceInfo ? monotonicTime() : undefined,
|
||||
startedDateTime: new Date(),
|
||||
time: -1,
|
||||
request: {
|
||||
|
|
@ -476,7 +528,7 @@ function createHarEntry(method: string, url: URL, requestref: string, frameref:
|
|||
headers: [],
|
||||
queryString: [...url.searchParams].map(e => ({ name: e[0], value: e[1] })),
|
||||
headersSize: -1,
|
||||
bodySize: 0,
|
||||
bodySize: -1,
|
||||
},
|
||||
response: {
|
||||
status: -1,
|
||||
|
|
@ -491,12 +543,9 @@ function createHarEntry(method: string, url: URL, requestref: string, frameref:
|
|||
headersSize: -1,
|
||||
bodySize: -1,
|
||||
redirectURL: '',
|
||||
_transferSize: -1
|
||||
},
|
||||
cache: {
|
||||
beforeRequest: null,
|
||||
afterRequest: null,
|
||||
_transferSize: options.omitSizes ? undefined : -1
|
||||
},
|
||||
cache: {},
|
||||
timings: {
|
||||
send: -1,
|
||||
wait: -1,
|
||||
|
|
|
|||
|
|
@ -244,13 +244,17 @@ export class Route extends SdkObject {
|
|||
return this._request;
|
||||
}
|
||||
|
||||
async abort(errorCode: string = 'failed', redirectAbortedNavigationToUrl?: string) {
|
||||
async abort(errorCode: string = 'failed') {
|
||||
this._startHandling();
|
||||
if (redirectAbortedNavigationToUrl)
|
||||
this._request.frame().redirectNavigationAfterAbort(redirectAbortedNavigationToUrl, this._request._documentId!);
|
||||
await this._delegate.abort(errorCode);
|
||||
}
|
||||
|
||||
async redirectNavigationRequest(url: string) {
|
||||
this._startHandling();
|
||||
assert(this._request.isNavigationRequest());
|
||||
this._request.frame().redirectNavigation(url, this._request._documentId!, this._request.headerValue('referer'));
|
||||
}
|
||||
|
||||
async fulfill(overrides: channels.RouteFulfillParams) {
|
||||
this._startHandling();
|
||||
let body = overrides.body;
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
|||
this._precreatedTracesDir = tracesDir;
|
||||
this._harTracer = new HarTracer(context, this, {
|
||||
content: 'attach',
|
||||
includeTraceInfo: true,
|
||||
waitForContentOnStop: false,
|
||||
skipScripts: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export class InMemorySnapshotter extends BaseSnapshotStorage implements Snapshot
|
|||
constructor(context: BrowserContext) {
|
||||
super();
|
||||
this._snapshotter = new Snapshotter(context, this);
|
||||
this._harTracer = new HarTracer(context, this, { content: 'attach', waitForContentOnStop: false, skipScripts: true });
|
||||
this._harTracer = new HarTracer(context, this, { content: 'attach', includeTraceInfo: true, waitForContentOnStop: false, skipScripts: true });
|
||||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
|
|
|
|||
167
packages/playwright-core/types/har.d.ts
vendored
167
packages/playwright-core/types/har.d.ts
vendored
|
|
@ -1,167 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// see http://www.softwareishard.com/blog/har-12-spec/
|
||||
export type HARFile = {
|
||||
log: HARLog;
|
||||
}
|
||||
|
||||
export type HARLog = {
|
||||
version: string;
|
||||
creator: HARCreator;
|
||||
browser?: HARBrowser;
|
||||
pages?: HARPage[];
|
||||
entries: HAREntry[];
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARCreator = {
|
||||
name: string;
|
||||
version: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARBrowser = {
|
||||
name: string;
|
||||
version: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARPage = {
|
||||
startedDateTime: string;
|
||||
id: string;
|
||||
title: string;
|
||||
pageTimings: HARPageTimings;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARPageTimings = {
|
||||
onContentLoad?: number;
|
||||
onLoad?: number;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HAREntry = {
|
||||
pageref?: string;
|
||||
startedDateTime: string;
|
||||
time: number;
|
||||
request: HARRequest;
|
||||
response: HARResponse;
|
||||
cache: HARCache;
|
||||
timings: HARTimings;
|
||||
serverIPAddress?: string;
|
||||
connection?: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARRequest = {
|
||||
method: string;
|
||||
url: string;
|
||||
httpVersion: string;
|
||||
cookies: HARCookie[];
|
||||
headers: HARHeader[];
|
||||
queryString: HARQueryParameter[];
|
||||
postData?: HARPostData;
|
||||
headersSize: number;
|
||||
bodySize: number;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARResponse = {
|
||||
status: number;
|
||||
statusText: string;
|
||||
httpVersion: string;
|
||||
cookies: HARCookie[];
|
||||
headers: HARHeader[];
|
||||
content: HARContent;
|
||||
redirectURL: string;
|
||||
headersSize: number;
|
||||
bodySize: number;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARCookie = {
|
||||
name: string;
|
||||
value: string;
|
||||
path?: string;
|
||||
domain?: string;
|
||||
expires?: string;
|
||||
httpOnly?: boolean;
|
||||
secure?: boolean;
|
||||
sameSite?: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARHeader = {
|
||||
name: string;
|
||||
value: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARQueryParameter = {
|
||||
name: string;
|
||||
value: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARPostData = {
|
||||
mimeType: string;
|
||||
params: HARParam[];
|
||||
text: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARParam = {
|
||||
name: string;
|
||||
value?: string;
|
||||
fileName?: string;
|
||||
contentType?: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARContent = {
|
||||
size: number;
|
||||
compression?: number;
|
||||
mimeType: string;
|
||||
text?: string;
|
||||
encoding?: string;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARCache = {
|
||||
beforeRequest?: HARCacheState;
|
||||
afterRequest?: HARCacheState;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARCacheState = {
|
||||
expires?: string;
|
||||
lastAccess: string;
|
||||
eTag: string;
|
||||
hitCount: number;
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export type HARTimings = {
|
||||
blocked?: number;
|
||||
dns?: number;
|
||||
connect?: number;
|
||||
send: number;
|
||||
wait: number;
|
||||
receive: number;
|
||||
ssl?: number;
|
||||
comment?: string;
|
||||
};
|
||||
97
packages/playwright-core/types/protocol.d.ts
vendored
97
packages/playwright-core/types/protocol.d.ts
vendored
|
|
@ -810,7 +810,7 @@ CORS RFC1918 enforcement.
|
|||
export type AttributionReportingIssueType = "PermissionPolicyDisabled"|"AttributionSourceUntrustworthyOrigin"|"AttributionUntrustworthyOrigin"|"InvalidHeader";
|
||||
/**
|
||||
* Details for issues around "Attribution Reporting API" usage.
|
||||
Explainer: https://github.com/WICG/conversion-measurement-api
|
||||
Explainer: https://github.com/WICG/attribution-reporting-api
|
||||
*/
|
||||
export interface AttributionReportingIssueDetails {
|
||||
violationType: AttributionReportingIssueType;
|
||||
|
|
@ -849,7 +849,7 @@ instead of "limited-quirks".
|
|||
errorType: GenericIssueErrorType;
|
||||
frameId?: Page.FrameId;
|
||||
}
|
||||
export type DeprecationIssueType = "AuthorizationCoveredByWildcard"|"CanRequestURLHTTPContainingNewline"|"ChromeLoadTimesConnectionInfo"|"ChromeLoadTimesFirstPaintAfterLoadTime"|"ChromeLoadTimesWasAlternateProtocolAvailable"|"CookieWithTruncatingChar"|"CrossOriginAccessBasedOnDocumentDomain"|"CrossOriginWindowAlert"|"CrossOriginWindowConfirm"|"CSSSelectorInternalMediaControlsOverlayCastButton"|"CustomCursorIntersectsViewport"|"DeprecationExample"|"DocumentDomainSettingWithoutOriginAgentClusterHeader"|"EventPath"|"GeolocationInsecureOrigin"|"GeolocationInsecureOriginDeprecatedNotRemoved"|"GetUserMediaInsecureOrigin"|"HostCandidateAttributeGetter"|"InsecurePrivateNetworkSubresourceRequest"|"LegacyConstraintGoogIPv6"|"LocalCSSFileExtensionRejected"|"MediaElementAudioSourceNode"|"MediaSourceAbortRemove"|"MediaSourceDurationTruncatingBuffered"|"NoSysexWebMIDIWithoutPermission"|"NotificationInsecureOrigin"|"NotificationPermissionRequestedIframe"|"ObsoleteWebRtcCipherSuite"|"PaymentRequestBasicCard"|"PaymentRequestShowWithoutGesture"|"PictureSourceSrc"|"PrefixedCancelAnimationFrame"|"PrefixedRequestAnimationFrame"|"PrefixedStorageInfo"|"PrefixedVideoDisplayingFullscreen"|"PrefixedVideoEnterFullscreen"|"PrefixedVideoEnterFullScreen"|"PrefixedVideoExitFullscreen"|"PrefixedVideoExitFullScreen"|"PrefixedVideoSupportsFullscreen"|"RangeExpand"|"RequestedSubresourceWithEmbeddedCredentials"|"RTCConstraintEnableDtlsSrtpFalse"|"RTCConstraintEnableDtlsSrtpTrue"|"RTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics"|"RTCPeerConnectionSdpSemanticsPlanB"|"RtcpMuxPolicyNegotiate"|"RTPDataChannel"|"SharedArrayBufferConstructedWithoutIsolation"|"TextToSpeech_DisallowedByAutoplay"|"V8SharedArrayBufferConstructedInExtensionWithoutIsolation"|"XHRJSONEncodingDetection"|"XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload"|"XRSupportsSession";
|
||||
export type DeprecationIssueType = "AuthorizationCoveredByWildcard"|"CanRequestURLHTTPContainingNewline"|"ChromeLoadTimesConnectionInfo"|"ChromeLoadTimesFirstPaintAfterLoadTime"|"ChromeLoadTimesWasAlternateProtocolAvailable"|"CookieWithTruncatingChar"|"CrossOriginAccessBasedOnDocumentDomain"|"CrossOriginWindowAlert"|"CrossOriginWindowConfirm"|"CSSSelectorInternalMediaControlsOverlayCastButton"|"DeprecationExample"|"DocumentDomainSettingWithoutOriginAgentClusterHeader"|"EventPath"|"GeolocationInsecureOrigin"|"GeolocationInsecureOriginDeprecatedNotRemoved"|"GetUserMediaInsecureOrigin"|"HostCandidateAttributeGetter"|"IdentityInCanMakePaymentEvent"|"InsecurePrivateNetworkSubresourceRequest"|"LegacyConstraintGoogIPv6"|"LocalCSSFileExtensionRejected"|"MediaSourceAbortRemove"|"MediaSourceDurationTruncatingBuffered"|"NoSysexWebMIDIWithoutPermission"|"NotificationInsecureOrigin"|"NotificationPermissionRequestedIframe"|"ObsoleteWebRtcCipherSuite"|"OpenWebDatabaseInsecureContext"|"PictureSourceSrc"|"PrefixedCancelAnimationFrame"|"PrefixedRequestAnimationFrame"|"PrefixedStorageInfo"|"PrefixedVideoDisplayingFullscreen"|"PrefixedVideoEnterFullscreen"|"PrefixedVideoEnterFullScreen"|"PrefixedVideoExitFullscreen"|"PrefixedVideoExitFullScreen"|"PrefixedVideoSupportsFullscreen"|"RangeExpand"|"RequestedSubresourceWithEmbeddedCredentials"|"RTCConstraintEnableDtlsSrtpFalse"|"RTCConstraintEnableDtlsSrtpTrue"|"RTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics"|"RTCPeerConnectionSdpSemanticsPlanB"|"RtcpMuxPolicyNegotiate"|"SharedArrayBufferConstructedWithoutIsolation"|"TextToSpeech_DisallowedByAutoplay"|"V8SharedArrayBufferConstructedInExtensionWithoutIsolation"|"XHRJSONEncodingDetection"|"XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload"|"XRSupportsSession";
|
||||
/**
|
||||
* This issue tracks information needed to print a deprecation message.
|
||||
https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/frame/third_party/blink/renderer/core/frame/deprecation/README.md
|
||||
|
|
@ -1532,6 +1532,10 @@ inspector" rules), "regular" for regular stylesheets.
|
|||
* Pseudo element type.
|
||||
*/
|
||||
pseudoType: DOM.PseudoType;
|
||||
/**
|
||||
* Pseudo element custom ident.
|
||||
*/
|
||||
pseudoIdentifier?: string;
|
||||
/**
|
||||
* Matches of CSS rules applicable to the pseudo style.
|
||||
*/
|
||||
|
|
@ -2068,6 +2072,10 @@ and additional information such as platformFontFamily and fontVariationAxes.
|
|||
* The font-stretch.
|
||||
*/
|
||||
fontStretch: string;
|
||||
/**
|
||||
* The font-display.
|
||||
*/
|
||||
fontDisplay: string;
|
||||
/**
|
||||
* The unicode-range.
|
||||
*/
|
||||
|
|
@ -2958,6 +2966,11 @@ fire DOM events for nodes known to the client.
|
|||
* Pseudo element type for this node.
|
||||
*/
|
||||
pseudoType?: PseudoType;
|
||||
/**
|
||||
* Pseudo element identifier for this node. Only present if there is a
|
||||
valid pseudoType.
|
||||
*/
|
||||
pseudoIdentifier?: string;
|
||||
/**
|
||||
* Shadow root type.
|
||||
*/
|
||||
|
|
@ -2997,6 +3010,7 @@ The property is always undefined now.
|
|||
*/
|
||||
isSVG?: boolean;
|
||||
compatibilityMode?: CompatibilityMode;
|
||||
assignedSlot?: BackendNode;
|
||||
}
|
||||
/**
|
||||
* A structure holding an RGBA color.
|
||||
|
|
@ -4706,6 +4720,11 @@ getSnapshot was true.
|
|||
* Type of a pseudo element node.
|
||||
*/
|
||||
pseudoType?: RareStringData;
|
||||
/**
|
||||
* Pseudo element identifier for this node. Only present if there is a
|
||||
valid pseudoType.
|
||||
*/
|
||||
pseudoIdentifier?: RareStringData;
|
||||
/**
|
||||
* Whether this DOM node responds to mouse clicks. This includes nodes that have had click
|
||||
event listeners attached via JavaScript as well as anchor tags that naturally navigate when
|
||||
|
|
@ -4978,12 +4997,6 @@ The final text color opacity is computed based on the opacity of all overlapping
|
|||
}
|
||||
export type setDOMStorageItemReturnValue = {
|
||||
}
|
||||
export type getStorageKeyForFrameParameters = {
|
||||
frameId: Page.FrameId;
|
||||
}
|
||||
export type getStorageKeyForFrameReturnValue = {
|
||||
storageKey: SerializedStorageKey;
|
||||
}
|
||||
}
|
||||
|
||||
export module Database {
|
||||
|
|
@ -5533,6 +5546,14 @@ on Android.
|
|||
}
|
||||
export type setDisabledImageTypesReturnValue = {
|
||||
}
|
||||
export type setHardwareConcurrencyOverrideParameters = {
|
||||
/**
|
||||
* Hardware concurrency to report
|
||||
*/
|
||||
hardwareConcurrency: number;
|
||||
}
|
||||
export type setHardwareConcurrencyOverrideReturnValue = {
|
||||
}
|
||||
/**
|
||||
* Allows overriding user agent with the given string.
|
||||
*/
|
||||
|
|
@ -8063,7 +8084,7 @@ the same request (but not for redirected requests).
|
|||
initiatorIPAddressSpace: IPAddressSpace;
|
||||
privateNetworkRequestPolicy: PrivateNetworkRequestPolicy;
|
||||
}
|
||||
export type CrossOriginOpenerPolicyValue = "SameOrigin"|"SameOriginAllowPopups"|"UnsafeNone"|"SameOriginPlusCoep"|"SameOriginAllowPopupsPlusCoep";
|
||||
export type CrossOriginOpenerPolicyValue = "SameOrigin"|"SameOriginAllowPopups"|"RestrictProperties"|"UnsafeNone"|"SameOriginPlusCoep"|"RestrictPropertiesPlusCoep";
|
||||
export interface CrossOriginOpenerPolicyStatus {
|
||||
value: CrossOriginOpenerPolicyValue;
|
||||
reportOnlyValue: CrossOriginOpenerPolicyValue;
|
||||
|
|
@ -10166,6 +10187,21 @@ Backend then generates 'inspectNodeRequested' event upon element selection.
|
|||
adFrameType: AdFrameType;
|
||||
explanations?: AdFrameExplanation[];
|
||||
}
|
||||
/**
|
||||
* Identifies the bottom-most script which caused the frame to be labelled
|
||||
as an ad.
|
||||
*/
|
||||
export interface AdScriptId {
|
||||
/**
|
||||
* Script Id of the bottom-most script which caused the frame to be labelled
|
||||
as an ad.
|
||||
*/
|
||||
scriptId: Runtime.ScriptId;
|
||||
/**
|
||||
* Id of adScriptId's debugger.
|
||||
*/
|
||||
debuggerId: Runtime.UniqueDebuggerId;
|
||||
}
|
||||
/**
|
||||
* Indicates whether the frame is a secure context and why it is the case.
|
||||
*/
|
||||
|
|
@ -10179,7 +10215,7 @@ Backend then generates 'inspectNodeRequested' event upon element selection.
|
|||
* All Permissions Policy features. This enum should match the one defined
|
||||
in third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5.
|
||||
*/
|
||||
export type PermissionsPolicyFeature = "accelerometer"|"ambient-light-sensor"|"attribution-reporting"|"autoplay"|"browsing-topics"|"camera"|"ch-dpr"|"ch-device-memory"|"ch-downlink"|"ch-ect"|"ch-prefers-color-scheme"|"ch-rtt"|"ch-save-data"|"ch-ua"|"ch-ua-arch"|"ch-ua-bitness"|"ch-ua-platform"|"ch-ua-model"|"ch-ua-mobile"|"ch-ua-full"|"ch-ua-full-version"|"ch-ua-full-version-list"|"ch-ua-platform-version"|"ch-ua-reduced"|"ch-ua-wow64"|"ch-viewport-height"|"ch-viewport-width"|"ch-width"|"clipboard-read"|"clipboard-write"|"cross-origin-isolated"|"direct-sockets"|"display-capture"|"document-domain"|"encrypted-media"|"execution-while-out-of-viewport"|"execution-while-not-rendered"|"focus-without-user-activation"|"fullscreen"|"frobulate"|"gamepad"|"geolocation"|"gyroscope"|"hid"|"idle-detection"|"interest-cohort"|"join-ad-interest-group"|"keyboard-map"|"local-fonts"|"magnetometer"|"microphone"|"midi"|"otp-credentials"|"payment"|"picture-in-picture"|"publickey-credentials-get"|"run-ad-auction"|"screen-wake-lock"|"serial"|"shared-autofill"|"storage-access-api"|"sync-xhr"|"trust-token-redemption"|"usb"|"vertical-scroll"|"web-share"|"window-placement"|"xr-spatial-tracking";
|
||||
export type PermissionsPolicyFeature = "accelerometer"|"ambient-light-sensor"|"attribution-reporting"|"autoplay"|"bluetooth"|"browsing-topics"|"camera"|"ch-dpr"|"ch-device-memory"|"ch-downlink"|"ch-ect"|"ch-prefers-color-scheme"|"ch-rtt"|"ch-save-data"|"ch-ua"|"ch-ua-arch"|"ch-ua-bitness"|"ch-ua-platform"|"ch-ua-model"|"ch-ua-mobile"|"ch-ua-full"|"ch-ua-full-version"|"ch-ua-full-version-list"|"ch-ua-platform-version"|"ch-ua-reduced"|"ch-ua-wow64"|"ch-viewport-height"|"ch-viewport-width"|"ch-width"|"clipboard-read"|"clipboard-write"|"cross-origin-isolated"|"direct-sockets"|"display-capture"|"document-domain"|"encrypted-media"|"execution-while-out-of-viewport"|"execution-while-not-rendered"|"focus-without-user-activation"|"fullscreen"|"frobulate"|"gamepad"|"geolocation"|"gyroscope"|"hid"|"idle-detection"|"interest-cohort"|"join-ad-interest-group"|"keyboard-map"|"local-fonts"|"magnetometer"|"microphone"|"midi"|"otp-credentials"|"payment"|"picture-in-picture"|"publickey-credentials-get"|"run-ad-auction"|"screen-wake-lock"|"serial"|"shared-autofill"|"storage-access-api"|"sync-xhr"|"trust-token-redemption"|"usb"|"vertical-scroll"|"web-share"|"window-placement"|"xr-spatial-tracking";
|
||||
/**
|
||||
* Reason for a permissions policy feature to be disabled.
|
||||
*/
|
||||
|
|
@ -10644,7 +10680,7 @@ Example URLs: http://www.google.com/file.html -> "google.com"
|
|||
/**
|
||||
* List of not restored reasons for back-forward cache.
|
||||
*/
|
||||
export type BackForwardCacheNotRestoredReason = "NotPrimaryMainFrame"|"BackForwardCacheDisabled"|"RelatedActiveContentsExist"|"HTTPStatusNotOK"|"SchemeNotHTTPOrHTTPS"|"Loading"|"WasGrantedMediaAccess"|"DisableForRenderFrameHostCalled"|"DomainNotAllowed"|"HTTPMethodNotGET"|"SubframeIsNavigating"|"Timeout"|"CacheLimit"|"JavaScriptExecution"|"RendererProcessKilled"|"RendererProcessCrashed"|"SchedulerTrackedFeatureUsed"|"ConflictingBrowsingInstance"|"CacheFlushed"|"ServiceWorkerVersionActivation"|"SessionRestored"|"ServiceWorkerPostMessage"|"EnteredBackForwardCacheBeforeServiceWorkerHostAdded"|"RenderFrameHostReused_SameSite"|"RenderFrameHostReused_CrossSite"|"ServiceWorkerClaim"|"IgnoreEventAndEvict"|"HaveInnerContents"|"TimeoutPuttingInCache"|"BackForwardCacheDisabledByLowMemory"|"BackForwardCacheDisabledByCommandLine"|"NetworkRequestDatapipeDrainedAsBytesConsumer"|"NetworkRequestRedirected"|"NetworkRequestTimeout"|"NetworkExceedsBufferLimit"|"NavigationCancelledWhileRestoring"|"NotMostRecentNavigationEntry"|"BackForwardCacheDisabledForPrerender"|"UserAgentOverrideDiffers"|"ForegroundCacheLimit"|"BrowsingInstanceNotSwapped"|"BackForwardCacheDisabledForDelegate"|"UnloadHandlerExistsInMainFrame"|"UnloadHandlerExistsInSubFrame"|"ServiceWorkerUnregistration"|"CacheControlNoStore"|"CacheControlNoStoreCookieModified"|"CacheControlNoStoreHTTPOnlyCookieModified"|"NoResponseHead"|"Unknown"|"ActivationNavigationsDisallowedForBug1234857"|"ErrorDocument"|"FencedFramesEmbedder"|"WebSocket"|"WebTransport"|"WebRTC"|"MainResourceHasCacheControlNoStore"|"MainResourceHasCacheControlNoCache"|"SubresourceHasCacheControlNoStore"|"SubresourceHasCacheControlNoCache"|"ContainsPlugins"|"DocumentLoaded"|"DedicatedWorkerOrWorklet"|"OutstandingNetworkRequestOthers"|"OutstandingIndexedDBTransaction"|"RequestedNotificationsPermission"|"RequestedMIDIPermission"|"RequestedAudioCapturePermission"|"RequestedVideoCapturePermission"|"RequestedBackForwardCacheBlockedSensors"|"RequestedBackgroundWorkPermission"|"BroadcastChannel"|"IndexedDBConnection"|"WebXR"|"SharedWorker"|"WebLocks"|"WebHID"|"WebShare"|"RequestedStorageAccessGrant"|"WebNfc"|"OutstandingNetworkRequestFetch"|"OutstandingNetworkRequestXHR"|"AppBanner"|"Printing"|"WebDatabase"|"PictureInPicture"|"Portal"|"SpeechRecognizer"|"IdleManager"|"PaymentManager"|"SpeechSynthesis"|"KeyboardLock"|"WebOTPService"|"OutstandingNetworkRequestDirectSocket"|"InjectedJavascript"|"InjectedStyleSheet"|"Dummy"|"ContentSecurityHandler"|"ContentWebAuthenticationAPI"|"ContentFileChooser"|"ContentSerial"|"ContentFileSystemAccess"|"ContentMediaDevicesDispatcherHost"|"ContentWebBluetooth"|"ContentWebUSB"|"ContentMediaSession"|"ContentMediaSessionService"|"ContentScreenReader"|"EmbedderPopupBlockerTabHelper"|"EmbedderSafeBrowsingTriggeredPopupBlocker"|"EmbedderSafeBrowsingThreatDetails"|"EmbedderAppBannerManager"|"EmbedderDomDistillerViewerSource"|"EmbedderDomDistillerSelfDeletingRequestDelegate"|"EmbedderOomInterventionTabHelper"|"EmbedderOfflinePage"|"EmbedderChromePasswordManagerClientBindCredentialManager"|"EmbedderPermissionRequestManager"|"EmbedderModalDialog"|"EmbedderExtensions"|"EmbedderExtensionMessaging"|"EmbedderExtensionMessagingForOpenPort"|"EmbedderExtensionSentMessageToCachedFrame";
|
||||
export type BackForwardCacheNotRestoredReason = "NotPrimaryMainFrame"|"BackForwardCacheDisabled"|"RelatedActiveContentsExist"|"HTTPStatusNotOK"|"SchemeNotHTTPOrHTTPS"|"Loading"|"WasGrantedMediaAccess"|"DisableForRenderFrameHostCalled"|"DomainNotAllowed"|"HTTPMethodNotGET"|"SubframeIsNavigating"|"Timeout"|"CacheLimit"|"JavaScriptExecution"|"RendererProcessKilled"|"RendererProcessCrashed"|"SchedulerTrackedFeatureUsed"|"ConflictingBrowsingInstance"|"CacheFlushed"|"ServiceWorkerVersionActivation"|"SessionRestored"|"ServiceWorkerPostMessage"|"EnteredBackForwardCacheBeforeServiceWorkerHostAdded"|"RenderFrameHostReused_SameSite"|"RenderFrameHostReused_CrossSite"|"ServiceWorkerClaim"|"IgnoreEventAndEvict"|"HaveInnerContents"|"TimeoutPuttingInCache"|"BackForwardCacheDisabledByLowMemory"|"BackForwardCacheDisabledByCommandLine"|"NetworkRequestDatapipeDrainedAsBytesConsumer"|"NetworkRequestRedirected"|"NetworkRequestTimeout"|"NetworkExceedsBufferLimit"|"NavigationCancelledWhileRestoring"|"NotMostRecentNavigationEntry"|"BackForwardCacheDisabledForPrerender"|"UserAgentOverrideDiffers"|"ForegroundCacheLimit"|"BrowsingInstanceNotSwapped"|"BackForwardCacheDisabledForDelegate"|"UnloadHandlerExistsInMainFrame"|"UnloadHandlerExistsInSubFrame"|"ServiceWorkerUnregistration"|"CacheControlNoStore"|"CacheControlNoStoreCookieModified"|"CacheControlNoStoreHTTPOnlyCookieModified"|"NoResponseHead"|"Unknown"|"ActivationNavigationsDisallowedForBug1234857"|"ErrorDocument"|"FencedFramesEmbedder"|"WebSocket"|"WebTransport"|"WebRTC"|"MainResourceHasCacheControlNoStore"|"MainResourceHasCacheControlNoCache"|"SubresourceHasCacheControlNoStore"|"SubresourceHasCacheControlNoCache"|"ContainsPlugins"|"DocumentLoaded"|"DedicatedWorkerOrWorklet"|"OutstandingNetworkRequestOthers"|"OutstandingIndexedDBTransaction"|"RequestedNotificationsPermission"|"RequestedMIDIPermission"|"RequestedAudioCapturePermission"|"RequestedVideoCapturePermission"|"RequestedBackForwardCacheBlockedSensors"|"RequestedBackgroundWorkPermission"|"BroadcastChannel"|"IndexedDBConnection"|"WebXR"|"SharedWorker"|"WebLocks"|"WebHID"|"WebShare"|"RequestedStorageAccessGrant"|"WebNfc"|"OutstandingNetworkRequestFetch"|"OutstandingNetworkRequestXHR"|"AppBanner"|"Printing"|"WebDatabase"|"PictureInPicture"|"Portal"|"SpeechRecognizer"|"IdleManager"|"PaymentManager"|"SpeechSynthesis"|"KeyboardLock"|"WebOTPService"|"OutstandingNetworkRequestDirectSocket"|"InjectedJavascript"|"InjectedStyleSheet"|"Dummy"|"ContentSecurityHandler"|"ContentWebAuthenticationAPI"|"ContentFileChooser"|"ContentSerial"|"ContentFileSystemAccess"|"ContentMediaDevicesDispatcherHost"|"ContentWebBluetooth"|"ContentWebUSB"|"ContentMediaSessionService"|"ContentScreenReader"|"EmbedderPopupBlockerTabHelper"|"EmbedderSafeBrowsingTriggeredPopupBlocker"|"EmbedderSafeBrowsingThreatDetails"|"EmbedderAppBannerManager"|"EmbedderDomDistillerViewerSource"|"EmbedderDomDistillerSelfDeletingRequestDelegate"|"EmbedderOomInterventionTabHelper"|"EmbedderOfflinePage"|"EmbedderChromePasswordManagerClientBindCredentialManager"|"EmbedderPermissionRequestManager"|"EmbedderModalDialog"|"EmbedderExtensions"|"EmbedderExtensionMessaging"|"EmbedderExtensionMessagingForOpenPort"|"EmbedderExtensionSentMessageToCachedFrame";
|
||||
/**
|
||||
* Types of not restored reasons for back-forward cache.
|
||||
*/
|
||||
|
|
@ -10720,6 +10756,11 @@ dependent on the reason:
|
|||
* JavaScript stack trace of when frame was attached, only set if frame initiated from script.
|
||||
*/
|
||||
stack?: Runtime.StackTrace;
|
||||
/**
|
||||
* Identifies the bottom-most script which caused the frame to be labelled
|
||||
as an ad. Only sent if frame is labelled as an ad and id is available.
|
||||
*/
|
||||
adScriptId?: AdScriptId;
|
||||
}
|
||||
/**
|
||||
* Fired when frame no longer has a scheduled navigation.
|
||||
|
|
@ -12668,6 +12709,15 @@ Tokens from that issuer.
|
|||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a storage key given a frame id.
|
||||
*/
|
||||
export type getStorageKeyForFrameParameters = {
|
||||
frameId: Page.FrameId;
|
||||
}
|
||||
export type getStorageKeyForFrameReturnValue = {
|
||||
storageKey: SerializedStorageKey;
|
||||
}
|
||||
/**
|
||||
* Clears storage for origin.
|
||||
*/
|
||||
|
|
@ -15248,13 +15298,30 @@ of scripts is used as end of range.
|
|||
export type removeBreakpointReturnValue = {
|
||||
}
|
||||
/**
|
||||
* Restarts particular call frame from the beginning.
|
||||
* Restarts particular call frame from the beginning. The old, deprecated
|
||||
behavior of `restartFrame` is to stay paused and allow further CDP commands
|
||||
after a restart was scheduled. This can cause problems with restarting, so
|
||||
we now continue execution immediatly after it has been scheduled until we
|
||||
reach the beginning of the restarted frame.
|
||||
|
||||
To stay back-wards compatible, `restartFrame` now expects a `mode`
|
||||
parameter to be present. If the `mode` parameter is missing, `restartFrame`
|
||||
errors out.
|
||||
|
||||
The various return values are deprecated and `callFrames` is always empty.
|
||||
Use the call frames from the `Debugger#paused` events instead, that fires
|
||||
once V8 pauses at the beginning of the restarted function.
|
||||
*/
|
||||
export type restartFrameParameters = {
|
||||
/**
|
||||
* Call frame identifier to evaluate on.
|
||||
*/
|
||||
callFrameId: CallFrameId;
|
||||
/**
|
||||
* The `mode` parameter must be present and set to 'StepInto', otherwise
|
||||
`restartFrame` will error out.
|
||||
*/
|
||||
mode?: "StepInto";
|
||||
}
|
||||
export type restartFrameReturnValue = {
|
||||
/**
|
||||
|
|
@ -17514,7 +17581,6 @@ Error was thrown.
|
|||
"DOMStorage.getDOMStorageItems": DOMStorage.getDOMStorageItemsParameters;
|
||||
"DOMStorage.removeDOMStorageItem": DOMStorage.removeDOMStorageItemParameters;
|
||||
"DOMStorage.setDOMStorageItem": DOMStorage.setDOMStorageItemParameters;
|
||||
"DOMStorage.getStorageKeyForFrame": DOMStorage.getStorageKeyForFrameParameters;
|
||||
"Database.disable": Database.disableParameters;
|
||||
"Database.enable": Database.enableParameters;
|
||||
"Database.executeSQL": Database.executeSQLParameters;
|
||||
|
|
@ -17547,6 +17613,7 @@ Error was thrown.
|
|||
"Emulation.setTimezoneOverride": Emulation.setTimezoneOverrideParameters;
|
||||
"Emulation.setVisibleSize": Emulation.setVisibleSizeParameters;
|
||||
"Emulation.setDisabledImageTypes": Emulation.setDisabledImageTypesParameters;
|
||||
"Emulation.setHardwareConcurrencyOverride": Emulation.setHardwareConcurrencyOverrideParameters;
|
||||
"Emulation.setUserAgentOverride": Emulation.setUserAgentOverrideParameters;
|
||||
"Emulation.setAutomationOverride": Emulation.setAutomationOverrideParameters;
|
||||
"HeadlessExperimental.beginFrame": HeadlessExperimental.beginFrameParameters;
|
||||
|
|
@ -17744,6 +17811,7 @@ Error was thrown.
|
|||
"ServiceWorker.stopWorker": ServiceWorker.stopWorkerParameters;
|
||||
"ServiceWorker.unregister": ServiceWorker.unregisterParameters;
|
||||
"ServiceWorker.updateRegistration": ServiceWorker.updateRegistrationParameters;
|
||||
"Storage.getStorageKeyForFrame": Storage.getStorageKeyForFrameParameters;
|
||||
"Storage.clearDataForOrigin": Storage.clearDataForOriginParameters;
|
||||
"Storage.getCookies": Storage.getCookiesParameters;
|
||||
"Storage.setCookies": Storage.setCookiesParameters;
|
||||
|
|
@ -18044,7 +18112,6 @@ Error was thrown.
|
|||
"DOMStorage.getDOMStorageItems": DOMStorage.getDOMStorageItemsReturnValue;
|
||||
"DOMStorage.removeDOMStorageItem": DOMStorage.removeDOMStorageItemReturnValue;
|
||||
"DOMStorage.setDOMStorageItem": DOMStorage.setDOMStorageItemReturnValue;
|
||||
"DOMStorage.getStorageKeyForFrame": DOMStorage.getStorageKeyForFrameReturnValue;
|
||||
"Database.disable": Database.disableReturnValue;
|
||||
"Database.enable": Database.enableReturnValue;
|
||||
"Database.executeSQL": Database.executeSQLReturnValue;
|
||||
|
|
@ -18077,6 +18144,7 @@ Error was thrown.
|
|||
"Emulation.setTimezoneOverride": Emulation.setTimezoneOverrideReturnValue;
|
||||
"Emulation.setVisibleSize": Emulation.setVisibleSizeReturnValue;
|
||||
"Emulation.setDisabledImageTypes": Emulation.setDisabledImageTypesReturnValue;
|
||||
"Emulation.setHardwareConcurrencyOverride": Emulation.setHardwareConcurrencyOverrideReturnValue;
|
||||
"Emulation.setUserAgentOverride": Emulation.setUserAgentOverrideReturnValue;
|
||||
"Emulation.setAutomationOverride": Emulation.setAutomationOverrideReturnValue;
|
||||
"HeadlessExperimental.beginFrame": HeadlessExperimental.beginFrameReturnValue;
|
||||
|
|
@ -18274,6 +18342,7 @@ Error was thrown.
|
|||
"ServiceWorker.stopWorker": ServiceWorker.stopWorkerReturnValue;
|
||||
"ServiceWorker.unregister": ServiceWorker.unregisterReturnValue;
|
||||
"ServiceWorker.updateRegistration": ServiceWorker.updateRegistrationReturnValue;
|
||||
"Storage.getStorageKeyForFrame": Storage.getStorageKeyForFrameReturnValue;
|
||||
"Storage.clearDataForOrigin": Storage.clearDataForOriginReturnValue;
|
||||
"Storage.getCookies": Storage.getCookiesReturnValue;
|
||||
"Storage.setCookies": Storage.setCookiesReturnValue;
|
||||
|
|
|
|||
237
packages/playwright-core/types/types.d.ts
vendored
237
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -17,7 +17,6 @@
|
|||
import { Protocol } from 'playwright-core/types/protocol';
|
||||
import { ChildProcess } from 'child_process';
|
||||
import { EventEmitter } from 'events';
|
||||
import { HARResponse } from 'playwright-core/types/har';
|
||||
import { Readable } from 'stream';
|
||||
import { ReadStream } from 'fs';
|
||||
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from 'playwright-core/types/structs';
|
||||
|
|
@ -3167,6 +3166,32 @@ export interface Page {
|
|||
times?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* If specified the network requests that are made in the page will be served from the HAR file. Read more about
|
||||
* [Replaying from HAR](https://playwright.dev/docs/network#replaying-from-har).
|
||||
*
|
||||
* Playwright will not serve requests intercepted by Service Worker from the HAR file. See
|
||||
* [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using
|
||||
* request interception by setting `Browser.newContext.serviceWorkers` to `'block'`.
|
||||
* @param har Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a relative path, then it is resolved relative to the current working directory.
|
||||
* @param options
|
||||
*/
|
||||
routeFromHAR(har: string, options?: {
|
||||
/**
|
||||
* - If set to 'abort' any request not found in the HAR file will be aborted.
|
||||
* - If set to 'fallback' missing requests will be sent to the network.
|
||||
*
|
||||
* Defaults to abort.
|
||||
*/
|
||||
notFound?: "abort"|"fallback";
|
||||
|
||||
/**
|
||||
* A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern
|
||||
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
*/
|
||||
url?: string|RegExp|((url: URL) => boolean);
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns the buffer with the captured screenshot.
|
||||
* @param options
|
||||
|
|
@ -7093,6 +7118,32 @@ export interface BrowserContext {
|
|||
times?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* If specified the network requests that are made in the context will be served from the HAR file. Read more about
|
||||
* [Replaying from HAR](https://playwright.dev/docs/network#replaying-from-har).
|
||||
*
|
||||
* Playwright will not serve requests intercepted by Service Worker from the HAR file. See
|
||||
* [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using
|
||||
* request interception by setting `Browser.newContext.serviceWorkers` to `'block'`.
|
||||
* @param har Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a relative path, then it is resolved relative to the current working directory.
|
||||
* @param options
|
||||
*/
|
||||
routeFromHAR(har: string, options?: {
|
||||
/**
|
||||
* - If set to 'abort' any request not found in the HAR file will be aborted.
|
||||
* - If set to 'fallback' falls through to the next route handler in the handler chain.
|
||||
*
|
||||
* Defaults to abort.
|
||||
*/
|
||||
notFound?: "abort"|"fallback";
|
||||
|
||||
/**
|
||||
* A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern
|
||||
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
*/
|
||||
url?: string|RegExp|((url: URL) => boolean);
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* > NOTE: Service workers are only supported on Chromium-based browsers.
|
||||
*
|
||||
|
|
@ -10507,34 +10558,6 @@ export interface BrowserType<Unused = {}> {
|
|||
*/
|
||||
handleSIGTERM?: boolean;
|
||||
|
||||
/**
|
||||
* If specified the network requests that are made in the context will be served from the HAR file. Read more about
|
||||
* [Replaying from HAR](https://playwright.dev/docs/network#replaying-from-har).
|
||||
*
|
||||
* > NOTE: Playwright will not serve requests intercepted by Service Worker from the HAR file. See
|
||||
* [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using
|
||||
* request interception by setting `Browser.newContext.serviceWorkers` to `'block'`.
|
||||
*/
|
||||
har?: {
|
||||
/**
|
||||
* Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a
|
||||
* relative path, then it is resolved relative to the current working directory.
|
||||
*/
|
||||
path: string;
|
||||
|
||||
/**
|
||||
* If set to 'abort' any request not found in the HAR file will be aborted. If set to'continue' missing requests will be
|
||||
* sent to the network. Defaults to 'abort'.
|
||||
*/
|
||||
fallback?: "abort"|"continue";
|
||||
|
||||
/**
|
||||
* A glob pattern or regular expression to match request URL while routing. Only requests with URL matching the pattern
|
||||
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
*/
|
||||
urlFilter?: string|RegExp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies if viewport supports touch events. Defaults to false.
|
||||
*/
|
||||
|
|
@ -10653,6 +10676,12 @@ export interface BrowserType<Unused = {}> {
|
|||
*/
|
||||
path: string;
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
mode?: "full"|"minimal";
|
||||
|
||||
/**
|
||||
* A glob or regex pattern to filter requests that are stored in the HAR. When a `baseURL` via the context options was
|
||||
* provided and the passed URL is a path, it gets merged via the
|
||||
|
|
@ -11762,34 +11791,6 @@ export interface AndroidDevice {
|
|||
accuracy?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* If specified the network requests that are made in the context will be served from the HAR file. Read more about
|
||||
* [Replaying from HAR](https://playwright.dev/docs/network#replaying-from-har).
|
||||
*
|
||||
* > NOTE: Playwright will not serve requests intercepted by Service Worker from the HAR file. See
|
||||
* [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using
|
||||
* request interception by setting `Browser.newContext.serviceWorkers` to `'block'`.
|
||||
*/
|
||||
har?: {
|
||||
/**
|
||||
* Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a
|
||||
* relative path, then it is resolved relative to the current working directory.
|
||||
*/
|
||||
path: string;
|
||||
|
||||
/**
|
||||
* If set to 'abort' any request not found in the HAR file will be aborted. If set to'continue' missing requests will be
|
||||
* sent to the network. Defaults to 'abort'.
|
||||
*/
|
||||
fallback?: "abort"|"continue";
|
||||
|
||||
/**
|
||||
* A glob pattern or regular expression to match request URL while routing. Only requests with URL matching the pattern
|
||||
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
*/
|
||||
urlFilter?: string|RegExp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies if viewport supports touch events. Defaults to false.
|
||||
*/
|
||||
|
|
@ -11868,6 +11869,12 @@ export interface AndroidDevice {
|
|||
*/
|
||||
path: string;
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
mode?: "full"|"minimal";
|
||||
|
||||
/**
|
||||
* A glob or regex pattern to filter requests that are stored in the HAR. When a `baseURL` via the context options was
|
||||
* provided and the passed URL is a path, it gets merged via the
|
||||
|
|
@ -13330,34 +13337,6 @@ export interface Browser extends EventEmitter {
|
|||
accuracy?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* If specified the network requests that are made in the context will be served from the HAR file. Read more about
|
||||
* [Replaying from HAR](https://playwright.dev/docs/network#replaying-from-har).
|
||||
*
|
||||
* > NOTE: Playwright will not serve requests intercepted by Service Worker from the HAR file. See
|
||||
* [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using
|
||||
* request interception by setting `Browser.newContext.serviceWorkers` to `'block'`.
|
||||
*/
|
||||
har?: {
|
||||
/**
|
||||
* Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a
|
||||
* relative path, then it is resolved relative to the current working directory.
|
||||
*/
|
||||
path: string;
|
||||
|
||||
/**
|
||||
* If set to 'abort' any request not found in the HAR file will be aborted. If set to'continue' missing requests will be
|
||||
* sent to the network. Defaults to 'abort'.
|
||||
*/
|
||||
fallback?: "abort"|"continue";
|
||||
|
||||
/**
|
||||
* A glob pattern or regular expression to match request URL while routing. Only requests with URL matching the pattern
|
||||
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
*/
|
||||
urlFilter?: string|RegExp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies if viewport supports touch events. Defaults to false.
|
||||
*/
|
||||
|
|
@ -13466,6 +13445,12 @@ export interface Browser extends EventEmitter {
|
|||
*/
|
||||
path: string;
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
mode?: "full"|"minimal";
|
||||
|
||||
/**
|
||||
* A glob or regex pattern to filter requests that are stored in the HAR. When a `baseURL` via the context options was
|
||||
* provided and the passed URL is a path, it gets merged via the
|
||||
|
|
@ -14202,34 +14187,6 @@ export interface Electron {
|
|||
accuracy?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* If specified the network requests that are made in the context will be served from the HAR file. Read more about
|
||||
* [Replaying from HAR](https://playwright.dev/docs/network#replaying-from-har).
|
||||
*
|
||||
* > NOTE: Playwright will not serve requests intercepted by Service Worker from the HAR file. See
|
||||
* [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using
|
||||
* request interception by setting `Browser.newContext.serviceWorkers` to `'block'`.
|
||||
*/
|
||||
har?: {
|
||||
/**
|
||||
* Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a
|
||||
* relative path, then it is resolved relative to the current working directory.
|
||||
*/
|
||||
path: string;
|
||||
|
||||
/**
|
||||
* If set to 'abort' any request not found in the HAR file will be aborted. If set to'continue' missing requests will be
|
||||
* sent to the network. Defaults to 'abort'.
|
||||
*/
|
||||
fallback?: "abort"|"continue";
|
||||
|
||||
/**
|
||||
* A glob pattern or regular expression to match request URL while routing. Only requests with URL matching the pattern
|
||||
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
*/
|
||||
urlFilter?: string|RegExp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication).
|
||||
*/
|
||||
|
|
@ -14280,6 +14237,12 @@ export interface Electron {
|
|||
*/
|
||||
path: string;
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
mode?: "full"|"minimal";
|
||||
|
||||
/**
|
||||
* A glob or regex pattern to filter requests that are stored in the HAR. When a `baseURL` via the context options was
|
||||
* provided and the passed URL is a path, it gets merged via the
|
||||
|
|
@ -14895,9 +14858,10 @@ export interface Request {
|
|||
frame(): Frame;
|
||||
|
||||
/**
|
||||
* **DEPRECATED** Incomplete list of headers as seen by the rendering engine. Use
|
||||
* [request.allHeaders()](https://playwright.dev/docs/api/class-request#request-all-headers) instead.
|
||||
* @deprecated
|
||||
* An object with the request HTTP headers. The header names are lower-cased. Note that this method does not return
|
||||
* security-related headers, including cookie-related ones. You can use
|
||||
* [request.allHeaders()](https://playwright.dev/docs/api/class-request#request-all-headers) for complete list of headers
|
||||
* that include `cookie` information.
|
||||
*/
|
||||
headers(): { [key: string]: string; };
|
||||
|
||||
|
|
@ -15132,9 +15096,10 @@ export interface Response {
|
|||
fromServiceWorker(): boolean;
|
||||
|
||||
/**
|
||||
* **DEPRECATED** Incomplete list of headers as seen by the rendering engine. Use
|
||||
* [response.allHeaders()](https://playwright.dev/docs/api/class-response#response-all-headers) instead.
|
||||
* @deprecated
|
||||
* An object with the response HTTP headers. The header names are lower-cased. Note that this method does not return
|
||||
* security-related headers, including cookie-related ones. You can use
|
||||
* [response.allHeaders()](https://playwright.dev/docs/api/class-response#response-all-headers) for complete list of
|
||||
* headers that include `cookie` information.
|
||||
*/
|
||||
headers(): { [key: string]: string; };
|
||||
|
||||
|
|
@ -15995,34 +15960,6 @@ export interface BrowserContextOptions {
|
|||
|
||||
geolocation?: Geolocation;
|
||||
|
||||
/**
|
||||
* If specified the network requests that are made in the context will be served from the HAR file. Read more about
|
||||
* [Replaying from HAR](https://playwright.dev/docs/network#replaying-from-har).
|
||||
*
|
||||
* > NOTE: Playwright will not serve requests intercepted by Service Worker from the HAR file. See
|
||||
* [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using
|
||||
* request interception by setting `Browser.newContext.serviceWorkers` to `'block'`.
|
||||
*/
|
||||
har?: {
|
||||
/**
|
||||
* Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a
|
||||
* relative path, then it is resolved relative to the current working directory.
|
||||
*/
|
||||
path: string;
|
||||
|
||||
/**
|
||||
* If set to 'abort' any request not found in the HAR file will be aborted. If set to'continue' missing requests will be
|
||||
* sent to the network. Defaults to 'abort'.
|
||||
*/
|
||||
fallback?: "abort"|"continue";
|
||||
|
||||
/**
|
||||
* A glob pattern or regular expression to match request URL while routing. Only requests with URL matching the pattern
|
||||
* will be surved from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
*/
|
||||
urlFilter?: string|RegExp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies if viewport supports touch events. Defaults to false.
|
||||
*/
|
||||
|
|
@ -16127,6 +16064,12 @@ export interface BrowserContextOptions {
|
|||
*/
|
||||
path: string;
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
mode?: "full"|"minimal";
|
||||
|
||||
/**
|
||||
* A glob or regex pattern to filter requests that are stored in the HAR. When a `baseURL` via the context options was
|
||||
* provided and the passed URL is a path, it gets merged via the
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@playwright/experimental-ct-react",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "Playwright Component Testing for React",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-react": "^1.0.7",
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"vite": "^2.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@playwright/experimental-ct-svelte",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "Playwright Component Testing for Svelte",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.30",
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"vite": "^2.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@playwright/experimental-ct-vue",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "Playwright Component Testing for Vue",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-vue": "^2.3.1",
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"vite": "^2.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@playwright/experimental-ct-vue2",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "Playwright Component Testing for Vue2",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@playwright/test": "1.23.0-next",
|
||||
"@playwright/test": "1.23.0",
|
||||
"vite": "^2.9.5",
|
||||
"vite-plugin-vue2": "^2.0.1"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "playwright-firefox",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "A high-level API to automate Firefox",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
@ -27,6 +27,6 @@
|
|||
"install": "node install.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@playwright/test",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "A high-level API to automate web browsers",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
@ -33,6 +33,6 @@
|
|||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,6 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
|||
deviceScaleFactor: [ undefined, { option: true } ],
|
||||
extraHTTPHeaders: [ undefined, { option: true } ],
|
||||
geolocation: [ undefined, { option: true } ],
|
||||
har: [undefined, { option: true }],
|
||||
hasTouch: [ undefined, { option: true } ],
|
||||
httpCredentials: [ undefined, { option: true } ],
|
||||
ignoreHTTPSErrors: [ undefined, { option: true } ],
|
||||
|
|
@ -169,7 +168,6 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
|||
colorScheme,
|
||||
deviceScaleFactor,
|
||||
extraHTTPHeaders,
|
||||
har,
|
||||
hasTouch,
|
||||
geolocation,
|
||||
httpCredentials,
|
||||
|
|
@ -201,8 +199,6 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
|||
options.extraHTTPHeaders = extraHTTPHeaders;
|
||||
if (geolocation !== undefined)
|
||||
options.geolocation = geolocation;
|
||||
if (har !== undefined)
|
||||
options.har = har;
|
||||
if (hasTouch !== undefined)
|
||||
options.hasTouch = hasTouch;
|
||||
if (httpCredentials !== undefined)
|
||||
|
|
|
|||
10
packages/playwright-test/types/test.d.ts
vendored
10
packages/playwright-test/types/test.d.ts
vendored
|
|
@ -2492,7 +2492,6 @@ type BrowserName = 'chromium' | 'firefox' | 'webkit';
|
|||
type BrowserChannel = Exclude<LaunchOptions['channel'], undefined>;
|
||||
type ColorScheme = Exclude<BrowserContextOptions['colorScheme'], undefined>;
|
||||
type ExtraHTTPHeaders = Exclude<BrowserContextOptions['extraHTTPHeaders'], undefined>;
|
||||
type HAROptions = Exclude<BrowserContextOptions['har'], undefined>;
|
||||
type Proxy = Exclude<BrowserContextOptions['proxy'], undefined>;
|
||||
type StorageState = Exclude<BrowserContextOptions['storageState'], undefined>;
|
||||
type ServiceWorkerPolicy = Exclude<BrowserContextOptions['serviceWorkers'], undefined>;
|
||||
|
|
@ -2700,15 +2699,6 @@ export interface PlaywrightTestOptions {
|
|||
*/
|
||||
extraHTTPHeaders: ExtraHTTPHeaders | undefined;
|
||||
geolocation: Geolocation | undefined;
|
||||
/**
|
||||
* If specified the network requests that are made in the context will be served from the HAR file. Read more about
|
||||
* [Replaying from HAR](https://playwright.dev/docs/network#replaying-from-har).
|
||||
*
|
||||
* > NOTE: Playwright will not serve requests intercepted by Service Worker from the HAR file. See
|
||||
* [this](https://github.com/microsoft/playwright/issues/1090) issue. We recommend disabling Service Workers when using
|
||||
* request interception by setting `Browser.newContext.serviceWorkers` to `'block'`.
|
||||
*/
|
||||
har: HAROptions | undefined;
|
||||
/**
|
||||
* Specifies if viewport supports touch events. Defaults to false.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "playwright-webkit",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "A high-level API to automate WebKit",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
@ -27,6 +27,6 @@
|
|||
"install": "node install.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "playwright",
|
||||
"version": "1.23.0-next",
|
||||
"version": "1.23.0",
|
||||
"description": "A high-level API to automate web browsers",
|
||||
"repository": "github:Microsoft/playwright",
|
||||
"homepage": "https://playwright.dev",
|
||||
|
|
@ -27,6 +27,6 @@
|
|||
"install": "node install.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"playwright-core": "1.23.0-next"
|
||||
"playwright-core": "1.23.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ export class SnapshotRenderer {
|
|||
|
||||
// First try locating exact resource belonging to this frame.
|
||||
for (const resource of this._resources) {
|
||||
if (resource._monotonicTime >= snapshot.timestamp)
|
||||
if (typeof resource._monotonicTime === 'number' && resource._monotonicTime >= snapshot.timestamp)
|
||||
break;
|
||||
if (resource._frameref !== snapshot.frameId)
|
||||
continue;
|
||||
|
|
@ -121,7 +121,7 @@ export class SnapshotRenderer {
|
|||
if (!result) {
|
||||
// Then fall back to resource with this URL to account for memory cache.
|
||||
for (const resource of this._resources) {
|
||||
if (resource._monotonicTime >= snapshot.timestamp)
|
||||
if (typeof resource._monotonicTime === 'number' && resource._monotonicTime >= snapshot.timestamp)
|
||||
break;
|
||||
if (resource.request.url === url)
|
||||
return resource;
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ export function resourcesForAction(action: ActionTraceEvent): ResourceSnapshot[]
|
|||
|
||||
const nextAction = next(action);
|
||||
result = context(action).resources.filter(resource => {
|
||||
return resource._monotonicTime > action.metadata.startTime && (!nextAction || resource._monotonicTime < nextAction.metadata.startTime);
|
||||
return typeof resource._monotonicTime === 'number' && resource._monotonicTime > action.metadata.startTime && (!nextAction || resource._monotonicTime < nextAction.metadata.startTime);
|
||||
});
|
||||
(action as any)[resourcesSymbol] = result;
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
],
|
||||
"entries": [
|
||||
{
|
||||
"_requestref": "request@ee2a0dc164935fcd4d9432d37b245f3c",
|
||||
"_frameref": "frame@c7467fc0f1f86f09fc3b0d727a3862ea",
|
||||
"_monotonicTime": 270572145.898,
|
||||
"startedDateTime": "2022-06-10T04:27:32.146Z",
|
||||
|
|
@ -92,7 +91,6 @@
|
|||
"_securityDetails": {}
|
||||
},
|
||||
{
|
||||
"_requestref": "request@f2ff0fd79321ff90d0bc1b5d6fc13bad",
|
||||
"_frameref": "frame@c7467fc0f1f86f09fc3b0d727a3862ea",
|
||||
"_monotonicTime": 270572174.683,
|
||||
"startedDateTime": "2022-06-10T04:27:32.172Z",
|
||||
|
|
@ -162,7 +160,6 @@
|
|||
"_securityDetails": {}
|
||||
},
|
||||
{
|
||||
"_requestref": "request@f2ff0fd79321ff90d0bc1b5d6fc13bac",
|
||||
"_frameref": "frame@c7467fc0f1f86f09fc3b0d727a3862ea",
|
||||
"_monotonicTime": 270572174.683,
|
||||
"startedDateTime": "2022-06-10T04:27:32.174Z",
|
||||
|
|
@ -232,7 +229,6 @@
|
|||
"_securityDetails": {}
|
||||
},
|
||||
{
|
||||
"_requestref": "request@9626f59acb1f4a95f25112d32e9f7f60",
|
||||
"_frameref": "frame@c7467fc0f1f86f09fc3b0d727a3862ea",
|
||||
"_monotonicTime": 270572175.042,
|
||||
"startedDateTime": "2022-06-10T04:27:32.175Z",
|
||||
|
|
@ -297,7 +293,6 @@
|
|||
"_securityDetails": {}
|
||||
},
|
||||
{
|
||||
"_requestref": "request@d7ee53396148a663b819c348c53b03fb",
|
||||
"_frameref": "frame@c7467fc0f1f86f09fc3b0d727a3862ea",
|
||||
"_monotonicTime": 270572181.822,
|
||||
"startedDateTime": "2022-06-10T04:27:32.182Z",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
],
|
||||
"entries": [
|
||||
{
|
||||
"_requestref": "request@7d6e0ddb1e1e25f6e5c4a7c943c0bae1",
|
||||
"_frameref": "frame@3767e074ecde4cb8372abba2f6f9bb4f",
|
||||
"_monotonicTime": 110928357.437,
|
||||
"startedDateTime": "2022-06-16T21:41:23.951Z",
|
||||
|
|
@ -201,7 +200,6 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"_requestref": "request@5c7a316ee46a095bda80c23ddc8c740d",
|
||||
"_frameref": "frame@3767e074ecde4cb8372abba2f6f9bb4f",
|
||||
"_monotonicTime": 110928427.603,
|
||||
"startedDateTime": "2022-06-16T21:41:24.022Z",
|
||||
|
|
@ -358,7 +356,6 @@
|
|||
"_securityDetails": {}
|
||||
},
|
||||
{
|
||||
"_requestref": "request@17664a6093c12c97d41efbff3a502adb",
|
||||
"_frameref": "frame@3767e074ecde4cb8372abba2f6f9bb4f",
|
||||
"_monotonicTime": 110928455.901,
|
||||
"startedDateTime": "2022-06-16T21:41:24.050Z",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
],
|
||||
"entries": [
|
||||
{
|
||||
"_requestref": "request@ee2a0dc164935fcd4d9432d37b245f3c",
|
||||
"_frameref": "frame@c7467fc0f1f86f09fc3b0d727a3862ea",
|
||||
"_monotonicTime": 270572145.898,
|
||||
"startedDateTime": "2022-06-10T04:27:32.146Z",
|
||||
|
|
@ -69,7 +68,7 @@
|
|||
"size": 12,
|
||||
"mimeType": "text/html",
|
||||
"compression": 0,
|
||||
"_sha1": "har-sha1-main-response.txt"
|
||||
"_file": "har-sha1-main-response.txt"
|
||||
},
|
||||
"headersSize": 64,
|
||||
"bodySize": 71,
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@
|
|||
"cssresize": true,
|
||||
"scrollsnappoints": true,
|
||||
"shapes": true,
|
||||
"textalignlast": false,
|
||||
"textalignlast": true,
|
||||
"csstransforms": true,
|
||||
"csstransforms3d": true,
|
||||
"csstransformslevel2": true,
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@
|
|||
"cssresize": true,
|
||||
"scrollsnappoints": true,
|
||||
"shapes": true,
|
||||
"textalignlast": false,
|
||||
"textalignlast": true,
|
||||
"csstransforms": true,
|
||||
"csstransforms3d": true,
|
||||
"csstransformslevel2": true,
|
||||
|
|
|
|||
|
|
@ -196,8 +196,8 @@ test('should serve from HAR', async ({ playwright, asset }) => {
|
|||
const harPath = asset('har-fulfill.har');
|
||||
const app = await playwright._electron.launch({
|
||||
args: [path.join(__dirname, 'electron-window-app.js')],
|
||||
har: { path: harPath },
|
||||
});
|
||||
app.context().routeFromHAR(harPath);
|
||||
const page = await app.firstWindow();
|
||||
// await page.goto('https://playwright.dev/');
|
||||
await page.goto('http://no.playwright/');
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ import fs from 'fs';
|
|||
import path from 'path';
|
||||
import extractZip from '../../packages/playwright-core/bundles/zip/node_modules/extract-zip';
|
||||
|
||||
it('should fulfill from har, matching the method and following redirects', async ({ contextFactory, isAndroid, asset }) => {
|
||||
it('should context.routeFromHAR, matching the method and following redirects', async ({ context, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-fulfill.har');
|
||||
const context = await contextFactory({ har: { path } });
|
||||
await context.routeFromHAR(path);
|
||||
const page = await context.newPage();
|
||||
await page.goto('http://no.playwright/');
|
||||
// HAR contains a redirect for the script that should be followed automatically.
|
||||
|
|
@ -32,42 +32,55 @@ it('should fulfill from har, matching the method and following redirects', async
|
|||
await expect(page.locator('body')).toHaveCSS('background-color', 'rgb(255, 0, 0)');
|
||||
});
|
||||
|
||||
it('fallback:continue should continue when not found in har', async ({ contextFactory, server, isAndroid, asset }) => {
|
||||
it('should page.routeFromHAR, matching the method and following redirects', async ({ context, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-fulfill.har');
|
||||
const context = await contextFactory({ har: { path, fallback: 'continue' } });
|
||||
const page = await context.newPage();
|
||||
await page.routeFromHAR(path);
|
||||
await page.goto('http://no.playwright/');
|
||||
// HAR contains a redirect for the script that should be followed automatically.
|
||||
expect(await page.evaluate('window.value')).toBe('foo');
|
||||
// HAR contains a POST for the css file that should not be used.
|
||||
await expect(page.locator('body')).toHaveCSS('background-color', 'rgb(255, 0, 0)');
|
||||
});
|
||||
|
||||
it('fallback:continue should continue when not found in har', async ({ context, server, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-fulfill.har');
|
||||
await context.routeFromHAR(path, { notFound: 'fallback' });
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.PREFIX + '/one-style.html');
|
||||
await expect(page.locator('body')).toHaveCSS('background-color', 'rgb(255, 192, 203)');
|
||||
});
|
||||
|
||||
it('by default should abort requests not found in har', async ({ contextFactory, server, isAndroid, asset }) => {
|
||||
it('by default should abort requests not found in har', async ({ context, server, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-fulfill.har');
|
||||
const context = await contextFactory({ har: { path } });
|
||||
await context.routeFromHAR(path);
|
||||
const page = await context.newPage();
|
||||
const error = await page.goto(server.EMPTY_PAGE).catch(e => e);
|
||||
expect(error instanceof Error).toBe(true);
|
||||
});
|
||||
|
||||
it('fallback:continue should continue requests on bad har', async ({ contextFactory, server, isAndroid }, testInfo) => {
|
||||
it('fallback:continue should continue requests on bad har', async ({ context, server, isAndroid }, testInfo) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = testInfo.outputPath('test.har');
|
||||
fs.writeFileSync(path, JSON.stringify({ log: {} }), 'utf-8');
|
||||
const context = await contextFactory({ har: { path, fallback: 'continue' } });
|
||||
await context.routeFromHAR(path, { notFound: 'fallback' });
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.PREFIX + '/one-style.html');
|
||||
await expect(page.locator('body')).toHaveCSS('background-color', 'rgb(255, 192, 203)');
|
||||
});
|
||||
|
||||
it('should only handle requests matching url filter', async ({ contextFactory, isAndroid, asset }) => {
|
||||
it('should only handle requests matching url filter', async ({ context, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-fulfill.har');
|
||||
const context = await contextFactory({ har: { path, urlFilter: '**/*.js' } });
|
||||
await context.routeFromHAR(path, { notFound: 'fallback', url: '**/*.js' });
|
||||
const page = await context.newPage();
|
||||
await context.route('http://no.playwright/', async route => {
|
||||
expect(route.request().url()).toBe('http://no.playwright/');
|
||||
|
|
@ -83,11 +96,51 @@ it('should only handle requests matching url filter', async ({ contextFactory, i
|
|||
await expect(page.locator('body')).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it('should support regex filter', async ({ contextFactory, isAndroid, asset }) => {
|
||||
it('should only context.routeFromHAR requests matching url filter', async ({ context, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-fulfill.har');
|
||||
const context = await contextFactory({ har: { path, urlFilter: /.*(\.js|.*\.css|no.playwright\/)$/ } });
|
||||
await context.routeFromHAR(path, { url: '**/*.js' });
|
||||
const page = await context.newPage();
|
||||
await context.route('http://no.playwright/', async route => {
|
||||
expect(route.request().url()).toBe('http://no.playwright/');
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'text/html',
|
||||
body: '<script src="./script.js"></script><div>hello</div>',
|
||||
});
|
||||
});
|
||||
await page.goto('http://no.playwright/');
|
||||
// HAR contains a redirect for the script that should be followed automatically.
|
||||
expect(await page.evaluate('window.value')).toBe('foo');
|
||||
await expect(page.locator('body')).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it('should only page.routeFromHAR requests matching url filter', async ({ context, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-fulfill.har');
|
||||
const page = await context.newPage();
|
||||
await page.routeFromHAR(path, { url: '**/*.js' });
|
||||
await context.route('http://no.playwright/', async route => {
|
||||
expect(route.request().url()).toBe('http://no.playwright/');
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'text/html',
|
||||
body: '<script src="./script.js"></script><div>hello</div>',
|
||||
});
|
||||
});
|
||||
await page.goto('http://no.playwright/');
|
||||
// HAR contains a redirect for the script that should be followed automatically.
|
||||
expect(await page.evaluate('window.value')).toBe('foo');
|
||||
await expect(page.locator('body')).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
|
||||
});
|
||||
|
||||
it('should support regex filter', async ({ context, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-fulfill.har');
|
||||
await context.routeFromHAR(path, { url: /.*(\.js|.*\.css|no.playwright\/)$/ });
|
||||
const page = await context.newPage();
|
||||
await page.goto('http://no.playwright/');
|
||||
expect(await page.evaluate('window.value')).toBe('foo');
|
||||
|
|
@ -98,7 +151,8 @@ it('newPage should fulfill from har, matching the method and following redirects
|
|||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-fulfill.har');
|
||||
const page = await browser.newPage({ har: { path } });
|
||||
const page = await browser.newPage();
|
||||
await page.routeFromHAR(path);
|
||||
await page.goto('http://no.playwright/');
|
||||
// HAR contains a redirect for the script that should be followed automatically.
|
||||
expect(await page.evaluate('window.value')).toBe('foo');
|
||||
|
|
@ -107,14 +161,15 @@ it('newPage should fulfill from har, matching the method and following redirects
|
|||
await page.close();
|
||||
});
|
||||
|
||||
it('should change document URL after redirected navigation', async ({ contextFactory, isAndroid, asset }) => {
|
||||
it('should change document URL after redirected navigation', async ({ context, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-redirect.har');
|
||||
const context = await contextFactory({ har: { path } });
|
||||
await context.routeFromHAR(path);
|
||||
const page = await context.newPage();
|
||||
const [response] = await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.waitForURL('https://www.theverge.com/'),
|
||||
page.goto('https://theverge.com/')
|
||||
]);
|
||||
await expect(page).toHaveURL('https://www.theverge.com/');
|
||||
|
|
@ -122,11 +177,28 @@ it('should change document URL after redirected navigation', async ({ contextFac
|
|||
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
|
||||
});
|
||||
|
||||
it('should goBack to redirected navigation', async ({ contextFactory, isAndroid, asset, server }) => {
|
||||
it('should change document URL after redirected navigation on click', async ({ server, context, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-redirect.har');
|
||||
const context = await contextFactory({ har: { path, urlFilter: /.*theverge.*/ } });
|
||||
await context.routeFromHAR(path, { url: /.*theverge.*/ });
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent(`<a href="https://theverge.com/">click me</a>`);
|
||||
const [response] = await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.click('text=click me'),
|
||||
]);
|
||||
await expect(page).toHaveURL('https://www.theverge.com/');
|
||||
expect(response.request().url()).toBe('https://www.theverge.com/');
|
||||
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
|
||||
});
|
||||
|
||||
it('should goBack to redirected navigation', async ({ context, isAndroid, asset, server }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-redirect.har');
|
||||
await context.routeFromHAR(path, { url: /.*theverge.*/ });
|
||||
const page = await context.newPage();
|
||||
await page.goto('https://theverge.com/');
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
|
|
@ -137,11 +209,11 @@ it('should goBack to redirected navigation', async ({ contextFactory, isAndroid,
|
|||
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
|
||||
});
|
||||
|
||||
it('should goForward to redirected navigation', async ({ contextFactory, isAndroid, asset, server }) => {
|
||||
it('should goForward to redirected navigation', async ({ context, isAndroid, asset, server }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-redirect.har');
|
||||
const context = await contextFactory({ har: { path, urlFilter: /.*theverge.*/ } });
|
||||
await context.routeFromHAR(path, { url: /.*theverge.*/ });
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await expect(page).toHaveURL(server.EMPTY_PAGE);
|
||||
|
|
@ -155,11 +227,11 @@ it('should goForward to redirected navigation', async ({ contextFactory, isAndro
|
|||
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
|
||||
});
|
||||
|
||||
it('should reload redirected navigation', async ({ contextFactory, isAndroid, asset, server }) => {
|
||||
it('should reload redirected navigation', async ({ context, isAndroid, asset, server }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-redirect.har');
|
||||
const context = await contextFactory({ har: { path, urlFilter: /.*theverge.*/ } });
|
||||
await context.routeFromHAR(path, { url: /.*theverge.*/ });
|
||||
const page = await context.newPage();
|
||||
await page.goto('https://theverge.com/');
|
||||
await expect(page).toHaveURL('https://www.theverge.com/');
|
||||
|
|
@ -169,11 +241,11 @@ it('should reload redirected navigation', async ({ contextFactory, isAndroid, as
|
|||
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
|
||||
});
|
||||
|
||||
it('should fulfill from har with content in a file', async ({ contextFactory, isAndroid, asset }) => {
|
||||
it('should fulfill from har with content in a file', async ({ context, isAndroid, asset }) => {
|
||||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-sha1.har');
|
||||
const context = await contextFactory({ har: { path } });
|
||||
await context.routeFromHAR(path);
|
||||
const page = await context.newPage();
|
||||
await page.goto('http://no.playwright/');
|
||||
expect(await page.content()).toBe('<html><head></head><body>Hello, world</body></html>');
|
||||
|
|
@ -183,12 +255,13 @@ it('should round-trip har.zip', async ({ contextFactory, isAndroid, server }, te
|
|||
it.fixme(isAndroid);
|
||||
|
||||
const harPath = testInfo.outputPath('har.zip');
|
||||
const context1 = await contextFactory({ recordHar: { path: harPath } });
|
||||
const context1 = await contextFactory({ recordHar: { mode: 'minimal', path: harPath } });
|
||||
const page1 = await context1.newPage();
|
||||
await page1.goto(server.PREFIX + '/one-style.html');
|
||||
await context1.close();
|
||||
|
||||
const context2 = await contextFactory({ har: { path: harPath, fallback: 'abort' } });
|
||||
const context2 = await contextFactory();
|
||||
await context2.routeFromHAR(harPath, { notFound: 'abort' });
|
||||
const page2 = await context2.newPage();
|
||||
await page2.goto(server.PREFIX + '/one-style.html');
|
||||
expect(await page2.content()).toContain('hello, world!');
|
||||
|
|
@ -199,7 +272,7 @@ it('should round-trip extracted har.zip', async ({ contextFactory, isAndroid, se
|
|||
it.fixme(isAndroid);
|
||||
|
||||
const harPath = testInfo.outputPath('har.zip');
|
||||
const context1 = await contextFactory({ recordHar: { path: harPath } });
|
||||
const context1 = await contextFactory({ recordHar: { mode: 'minimal', path: harPath } });
|
||||
const page1 = await context1.newPage();
|
||||
await page1.goto(server.PREFIX + '/one-style.html');
|
||||
await context1.close();
|
||||
|
|
@ -207,7 +280,8 @@ it('should round-trip extracted har.zip', async ({ contextFactory, isAndroid, se
|
|||
const harDir = testInfo.outputPath('hardir');
|
||||
await extractZip(harPath, { dir: harDir });
|
||||
|
||||
const context2 = await contextFactory({ har: { path: path.join(harDir, 'har.har') } });
|
||||
const context2 = await contextFactory();
|
||||
await context2.routeFromHAR(path.join(harDir, 'har.har'));
|
||||
const page2 = await context2.newPage();
|
||||
await page2.goto(server.PREFIX + '/one-style.html');
|
||||
expect(await page2.content()).toContain('hello, world!');
|
||||
|
|
@ -222,7 +296,7 @@ it('should round-trip har with postData', async ({ contextFactory, isAndroid, se
|
|||
});
|
||||
|
||||
const harPath = testInfo.outputPath('har.zip');
|
||||
const context1 = await contextFactory({ recordHar: { path: harPath } });
|
||||
const context1 = await contextFactory({ recordHar: { mode: 'minimal', path: harPath } });
|
||||
const page1 = await context1.newPage();
|
||||
await page1.goto(server.EMPTY_PAGE);
|
||||
const fetchFunction = async (body: string) => {
|
||||
|
|
@ -235,7 +309,8 @@ it('should round-trip har with postData', async ({ contextFactory, isAndroid, se
|
|||
expect(await page1.evaluate(fetchFunction, '3')).toBe('3');
|
||||
await context1.close();
|
||||
|
||||
const context2 = await contextFactory({ har: { path: harPath } });
|
||||
const context2 = await contextFactory();
|
||||
await context2.routeFromHAR(harPath);
|
||||
const page2 = await context2.newPage();
|
||||
await page2.goto(server.EMPTY_PAGE);
|
||||
expect(await page2.evaluate(fetchFunction, '1')).toBe('1');
|
||||
|
|
@ -252,7 +327,7 @@ it('should disambiguate by header', async ({ contextFactory, isAndroid, server }
|
|||
});
|
||||
|
||||
const harPath = testInfo.outputPath('har.zip');
|
||||
const context1 = await contextFactory({ recordHar: { path: harPath } });
|
||||
const context1 = await contextFactory({ recordHar: { mode: 'minimal', path: harPath } });
|
||||
const page1 = await context1.newPage();
|
||||
await page1.goto(server.EMPTY_PAGE);
|
||||
|
||||
|
|
@ -274,7 +349,8 @@ it('should disambiguate by header', async ({ contextFactory, isAndroid, server }
|
|||
expect(await page1.evaluate(fetchFunction, 'baz3')).toBe('baz3');
|
||||
await context1.close();
|
||||
|
||||
const context2 = await contextFactory({ har: { path: harPath } });
|
||||
const context2 = await contextFactory();
|
||||
await context2.routeFromHAR(harPath);
|
||||
const page2 = await context2.newPage();
|
||||
await page2.goto(server.EMPTY_PAGE);
|
||||
expect(await page2.evaluate(fetchFunction, 'baz1')).toBe('baz1');
|
||||
|
|
|
|||
|
|
@ -268,6 +268,26 @@ it('should chain fallback', async ({ context, page, server }) => {
|
|||
expect(intercepted).toEqual([3, 2, 1]);
|
||||
});
|
||||
|
||||
it('should chain fallback w/ dynamic URL', async ({ context, page, server }) => {
|
||||
const intercepted = [];
|
||||
await context.route('**/bar', route => {
|
||||
intercepted.push(1);
|
||||
route.fallback({ url: server.EMPTY_PAGE });
|
||||
});
|
||||
await context.route('**/foo', route => {
|
||||
intercepted.push(2);
|
||||
route.fallback({ url: 'http://localhost/bar' });
|
||||
});
|
||||
|
||||
await context.route('**/empty.html', route => {
|
||||
intercepted.push(3);
|
||||
route.fallback({ url: 'http://localhost/foo' });
|
||||
});
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(intercepted).toEqual([3, 2, 1]);
|
||||
});
|
||||
|
||||
it('should not chain fulfill', async ({ context, page, server }) => {
|
||||
let failed = false;
|
||||
await context.route('**/empty.html', route => {
|
||||
|
|
|
|||
|
|
@ -228,7 +228,8 @@ it('should support har option', async ({ isAndroid, launchPersistent, asset }) =
|
|||
it.fixme(isAndroid);
|
||||
|
||||
const path = asset('har-fulfill.har');
|
||||
const { page } = await launchPersistent({ har: { path } });
|
||||
const { page } = await launchPersistent();
|
||||
await page.routeFromHAR(path);
|
||||
await page.goto('http://no.playwright/');
|
||||
// HAR contains a redirect for the script that should be followed automatically.
|
||||
expect(await page.evaluate('window.value')).toBe('foo');
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ it('should omit content', async ({ contextFactory, server }, testInfo) => {
|
|||
await page.evaluate(() => fetch('/pptr.png').then(r => r.arrayBuffer()));
|
||||
const log = await getLog();
|
||||
expect(log.entries[0].response.content.text).toBe(undefined);
|
||||
expect(log.entries[0].response.content._sha1).toBe(undefined);
|
||||
expect(log.entries[0].response.content._file).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should omit content legacy', async ({ contextFactory, server }, testInfo) => {
|
||||
|
|
@ -300,7 +300,7 @@ it('should omit content legacy', async ({ contextFactory, server }, testInfo) =>
|
|||
await page.evaluate(() => fetch('/pptr.png').then(r => r.arrayBuffer()));
|
||||
const log = await getLog();
|
||||
expect(log.entries[0].response.content.text).toBe(undefined);
|
||||
expect(log.entries[0].response.content._sha1).toBe(undefined);
|
||||
expect(log.entries[0].response.content._file).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should attach content', async ({ contextFactory, server }, testInfo) => {
|
||||
|
|
@ -312,19 +312,19 @@ it('should attach content', async ({ contextFactory, server }, testInfo) => {
|
|||
|
||||
expect(log.entries[0].response.content.encoding).toBe(undefined);
|
||||
expect(log.entries[0].response.content.mimeType).toBe('text/html; charset=utf-8');
|
||||
expect(log.entries[0].response.content._sha1).toContain('75841480e2606c03389077304342fac2c58ccb1b');
|
||||
expect(log.entries[0].response.content._file).toContain('75841480e2606c03389077304342fac2c58ccb1b');
|
||||
expect(log.entries[0].response.content.size).toBeGreaterThanOrEqual(96);
|
||||
expect(log.entries[0].response.content.compression).toBe(0);
|
||||
|
||||
expect(log.entries[1].response.content.encoding).toBe(undefined);
|
||||
expect(log.entries[1].response.content.mimeType).toBe('text/css; charset=utf-8');
|
||||
expect(log.entries[1].response.content._sha1).toContain('79f739d7bc88e80f55b9891a22bf13a2b4e18adb');
|
||||
expect(log.entries[1].response.content._file).toContain('79f739d7bc88e80f55b9891a22bf13a2b4e18adb');
|
||||
expect(log.entries[1].response.content.size).toBeGreaterThanOrEqual(37);
|
||||
expect(log.entries[1].response.content.compression).toBe(0);
|
||||
|
||||
expect(log.entries[2].response.content.encoding).toBe(undefined);
|
||||
expect(log.entries[2].response.content.mimeType).toBe('image/png');
|
||||
expect(log.entries[2].response.content._sha1).toContain('a4c3a18f0bb83f5d9fe7ce561e065c36205762fa');
|
||||
expect(log.entries[2].response.content._file).toContain('a4c3a18f0bb83f5d9fe7ce561e065c36205762fa');
|
||||
expect(log.entries[2].response.content.size).toBeGreaterThanOrEqual(6000);
|
||||
expect(log.entries[2].response.content.compression).toBe(0);
|
||||
|
||||
|
|
@ -689,45 +689,6 @@ it('should have different hars for concurrent contexts', async ({ contextFactory
|
|||
}
|
||||
});
|
||||
|
||||
it('should include _requestref', async ({ contextFactory, server }, testInfo) => {
|
||||
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
||||
const resp = await page.goto(server.EMPTY_PAGE);
|
||||
const log = await getLog();
|
||||
expect(log.entries.length).toBe(1);
|
||||
const entry = log.entries[0];
|
||||
expect(entry._requestref).toMatch(/^request@[a-f0-9]{32}$/);
|
||||
expect(entry._requestref).toBe((resp.request() as any)._guid);
|
||||
});
|
||||
|
||||
it('should include _requestref for redirects', async ({ contextFactory, server }, testInfo) => {
|
||||
server.setRedirect('/start', '/one-more');
|
||||
server.setRedirect('/one-more', server.EMPTY_PAGE);
|
||||
|
||||
const { page, getLog, context } = await pageWithHar(contextFactory, testInfo);
|
||||
|
||||
const requests = new Map<string, string>();
|
||||
context.on('request', request => {
|
||||
requests.set(request.url(), (request as any)._guid);
|
||||
});
|
||||
|
||||
await page.goto(server.PREFIX + '/start');
|
||||
|
||||
const log = await getLog();
|
||||
expect(log.entries.length).toBe(3);
|
||||
|
||||
const entryStart = log.entries[0];
|
||||
expect(entryStart.request.url).toBe(server.PREFIX + '/start');
|
||||
expect(entryStart._requestref).toBe(requests.get(entryStart.request.url));
|
||||
|
||||
const entryOneMore = log.entries[1];
|
||||
expect(entryOneMore.request.url).toBe(server.PREFIX + '/one-more');
|
||||
expect(entryOneMore._requestref).toBe(requests.get(entryOneMore.request.url));
|
||||
|
||||
const entryEmptyPage = log.entries[2];
|
||||
expect(entryEmptyPage.request.url).toBe(server.EMPTY_PAGE);
|
||||
expect(entryEmptyPage._requestref).toBe(requests.get(entryEmptyPage.request.url));
|
||||
});
|
||||
|
||||
it('should include API request', async ({ contextFactory, server }, testInfo) => {
|
||||
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
||||
const url = server.PREFIX + '/simple.json';
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
import { browserTest as it, expect } from '../config/browserTest';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
|
||||
async function checkFeatures(name: string, context: any, server: any) {
|
||||
try {
|
||||
|
|
@ -31,6 +32,7 @@ async function checkFeatures(name: string, context: any, server: any) {
|
|||
|
||||
it('safari-14-1', async ({ browser, browserName, platform, server, headless }) => {
|
||||
it.skip(browserName !== 'webkit');
|
||||
it.skip(browserName === 'webkit' && parseInt(os.release(), 10) < 20, 'WebKit for macOS 10.15 is frozen.');
|
||||
const context = await browser.newContext({
|
||||
deviceScaleFactor: 2
|
||||
});
|
||||
|
|
@ -73,6 +75,7 @@ it('safari-14-1', async ({ browser, browserName, platform, server, headless }) =
|
|||
|
||||
it('mobile-safari-14-1', async ({ playwright, browser, browserName, platform, server, headless }) => {
|
||||
it.skip(browserName !== 'webkit');
|
||||
it.skip(browserName === 'webkit' && parseInt(os.release(), 10) < 20, 'WebKit for macOS 10.15 is frozen.');
|
||||
const iPhone = playwright.devices['iPhone 12'];
|
||||
const context = await browser.newContext(iPhone);
|
||||
const { actual, expected } = await checkFeatures('mobile-safari-14-1', context, server);
|
||||
|
|
|
|||
|
|
@ -126,8 +126,8 @@ it('should inherit viewport size from browser context', async function({ browser
|
|||
expect(size).toEqual({ width: 400, height: 500 });
|
||||
});
|
||||
|
||||
it('should use viewport size from window features', async function({ browser, server, channel }) {
|
||||
it.fixme(channel === 'chromium-tip-of-tree', 'https://github.com/microsoft/playwright/issues/14787');
|
||||
it('should use viewport size from window features', async function({ browser, server, browserName }) {
|
||||
it.fixme(browserName === 'chromium', 'https://github.com/microsoft/playwright/issues/14787');
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 700, height: 700 }
|
||||
});
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ it('should override request url', async ({ page, server }) => {
|
|||
const request = server.waitForRequest('/global-var.html');
|
||||
|
||||
let url: string;
|
||||
await page.route('**/foo', route => {
|
||||
await page.route('**/global-var.html', route => {
|
||||
url = route.request().url();
|
||||
route.continue();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import { test as base, expect } from './pageTest';
|
||||
import fs from 'fs';
|
||||
import type { HARFile, HARResponse } from 'playwright-core/types/har';
|
||||
import type * as har from 'playwright-core/lib/server/har/har';
|
||||
|
||||
const it = base.extend<{
|
||||
// We access test servers at 10.0.2.2 from inside the browser on Android,
|
||||
|
|
@ -327,7 +327,7 @@ it('should fulfill with har response', async ({ page, isAndroid, asset }) => {
|
|||
it.fixme(isAndroid);
|
||||
|
||||
const harPath = asset('har-fulfill.har');
|
||||
const har = JSON.parse(await fs.promises.readFile(harPath, 'utf-8')) as HARFile;
|
||||
const har = JSON.parse(await fs.promises.readFile(harPath, 'utf-8')) as har.HARFile;
|
||||
await page.route('**/*', async route => {
|
||||
const response = findResponse(har, route.request().url());
|
||||
const headers = {};
|
||||
|
|
@ -346,7 +346,7 @@ it('should fulfill with har response', async ({ page, isAndroid, asset }) => {
|
|||
await expect(page.locator('body')).toHaveCSS('background-color', 'rgb(0, 255, 255)');
|
||||
});
|
||||
|
||||
function findResponse(har: HARFile, url: string): HARResponse {
|
||||
function findResponse(har: har.HARFile, url: string): har.Response {
|
||||
let entry;
|
||||
const originalUrl = url;
|
||||
while (url.trim()) {
|
||||
|
|
|
|||
|
|
@ -321,6 +321,26 @@ it('should not work with redirects', async ({ page, server }) => {
|
|||
expect(chain[i].redirectedTo()).toBe(i ? chain[i - 1] : null);
|
||||
});
|
||||
|
||||
it('should chain fallback w/ dynamic URL', async ({ page, server }) => {
|
||||
const intercepted = [];
|
||||
await page.route('**/bar', route => {
|
||||
intercepted.push(1);
|
||||
route.fallback({ url: server.EMPTY_PAGE });
|
||||
});
|
||||
await page.route('**/foo', route => {
|
||||
intercepted.push(2);
|
||||
route.fallback({ url: 'http://localhost/bar' });
|
||||
});
|
||||
|
||||
await page.route('**/empty.html', route => {
|
||||
intercepted.push(3);
|
||||
route.fallback({ url: 'http://localhost/foo' });
|
||||
});
|
||||
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(intercepted).toEqual([3, 2, 1]);
|
||||
});
|
||||
|
||||
it('should work with redirects for subresources', async ({ page, server }) => {
|
||||
const intercepted = [];
|
||||
await page.route('**/*', route => {
|
||||
|
|
|
|||
|
|
@ -602,18 +602,3 @@ test('should pass fixture defaults to tests', async ({ runInlineTest }) => {
|
|||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(1);
|
||||
});
|
||||
|
||||
test('should support har option', async ({ runInlineTest, asset }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
test.use({ har: { path: ${JSON.stringify(asset('har-fulfill.har'))} }});
|
||||
test('pass', async ({ page }) => {
|
||||
await page.goto('http://no.playwright/');
|
||||
expect(await page.evaluate('window.value')).toBe('foo');
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(1);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ echo "Building playwright-core package"
|
|||
node ../../utils/pack_package.js playwright-core ./output/playwright-core.tgz
|
||||
|
||||
echo "Building api.json and protocol.yml"
|
||||
node ../../utils/doclint/generateApiJson.js > ./output/api.json
|
||||
API_JSON_MODE=1 node ../../utils/doclint/generateApiJson.js > ./output/api.json
|
||||
cp ../../packages/playwright-core/src/protocol/protocol.yml ./output/
|
||||
|
||||
function build {
|
||||
|
|
|
|||
2
utils/generate_types/overrides-test.d.ts
vendored
2
utils/generate_types/overrides-test.d.ts
vendored
|
|
@ -173,7 +173,6 @@ type BrowserName = 'chromium' | 'firefox' | 'webkit';
|
|||
type BrowserChannel = Exclude<LaunchOptions['channel'], undefined>;
|
||||
type ColorScheme = Exclude<BrowserContextOptions['colorScheme'], undefined>;
|
||||
type ExtraHTTPHeaders = Exclude<BrowserContextOptions['extraHTTPHeaders'], undefined>;
|
||||
type HAROptions = Exclude<BrowserContextOptions['har'], undefined>;
|
||||
type Proxy = Exclude<BrowserContextOptions['proxy'], undefined>;
|
||||
type StorageState = Exclude<BrowserContextOptions['storageState'], undefined>;
|
||||
type ServiceWorkerPolicy = Exclude<BrowserContextOptions['serviceWorkers'], undefined>;
|
||||
|
|
@ -216,7 +215,6 @@ export interface PlaywrightTestOptions {
|
|||
deviceScaleFactor: number | undefined;
|
||||
extraHTTPHeaders: ExtraHTTPHeaders | undefined;
|
||||
geolocation: Geolocation | undefined;
|
||||
har: HAROptions | undefined;
|
||||
hasTouch: boolean | undefined;
|
||||
httpCredentials: HTTPCredentials | undefined;
|
||||
ignoreHTTPSErrors: boolean | undefined;
|
||||
|
|
|
|||
1
utils/generate_types/overrides.d.ts
vendored
1
utils/generate_types/overrides.d.ts
vendored
|
|
@ -16,7 +16,6 @@
|
|||
import { Protocol } from 'playwright-core/types/protocol';
|
||||
import { ChildProcess } from 'child_process';
|
||||
import { EventEmitter } from 'events';
|
||||
import { HARResponse } from 'playwright-core/types/har';
|
||||
import { Readable } from 'stream';
|
||||
import { ReadStream } from 'fs';
|
||||
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from 'playwright-core/types/structs';
|
||||
|
|
|
|||
|
|
@ -264,7 +264,10 @@ function innerRenderMdNode(indent, node, lastNode, result, maxColumns) {
|
|||
|
||||
if (node.type === 'code') {
|
||||
newLine();
|
||||
result.push(`${indent}\`\`\`${codeLangToHighlighter(node.codeLang)}`);
|
||||
if (process.env.API_JSON_MODE)
|
||||
result.push(`${indent}\`\`\`${node.codeLang}`);
|
||||
else
|
||||
result.push(`${indent}\`\`\`${codeLangToHighlighter(node.codeLang)}`);
|
||||
for (const line of node.lines)
|
||||
result.push(indent + line);
|
||||
result.push(`${indent}\`\`\``);
|
||||
|
|
|
|||
Loading…
Reference in a new issue