fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

202
node_modules/puppeteer-core/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017 Google Inc.
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
https://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.

473
node_modules/puppeteer-core/README.md generated vendored Normal file
View File

@@ -0,0 +1,473 @@
# Puppeteer
<!-- [START badges] -->
[![Build status](https://github.com/puppeteer/puppeteer/workflows/run-checks/badge.svg)](https://github.com/puppeteer/puppeteer/actions?query=workflow%3Arun-checks) [![npm puppeteer package](https://img.shields.io/npm/v/puppeteer.svg)](https://npmjs.org/package/puppeteer)
<!-- [END badges] -->
<img src="https://user-images.githubusercontent.com/10379601/29446482-04f7036a-841f-11e7-9872-91d1fc2ea683.png" height="200" align="right">
###### [API](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md) | [Troubleshooting](https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md)
> Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). Puppeteer runs [headless](https://developers.google.com/web/updates/2017/04/headless-chrome) by default, but can be configured to run full (non-headless) Chrome or Chromium.
<!-- [START usecases] -->
###### What can I do?
Most things that you can do manually in the browser can be done using Puppeteer! Here are a few examples to get you started:
- Generate screenshots and PDFs of pages.
- Crawl a SPA (Single-Page Application) and generate pre-rendered content (i.e. "SSR" (Server-Side Rendering)).
- Automate form submission, UI testing, keyboard input, etc.
- Create an up-to-date, automated testing environment. Run your tests directly in the latest version of Chrome using the latest JavaScript and browser features.
- Capture a [timeline trace](https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/reference) of your site to help diagnose performance issues.
- Test Chrome Extensions.
<!-- [END usecases] -->
<!-- [START getstarted] -->
## Getting Started
### Installation
To use Puppeteer in your project, run:
```bash
npm i puppeteer
# or "yarn add puppeteer"
```
Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, download into another path, or download a different browser, see [Environment variables](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md#environment-variables).
### puppeteer-core
Since version 1.7.0 we publish the [`puppeteer-core`](https://www.npmjs.com/package/puppeteer-core) package,
a version of Puppeteer that doesn't download any browser by default.
```bash
npm i puppeteer-core
# or "yarn add puppeteer-core"
```
`puppeteer-core` is intended to be a lightweight version of Puppeteer for launching an existing browser installation or for connecting to a remote one. Be sure that the version of puppeteer-core you install is compatible with the browser you intend to connect to.
See [puppeteer vs puppeteer-core](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#puppeteer-vs-puppeteer-core).
### Usage
Puppeteer follows the latest [maintenance LTS](https://github.com/nodejs/Release#release-schedule) version of Node.
Note: Prior to v1.18.1, Puppeteer required at least Node v6.4.0. Versions from v1.18.1 to v2.1.0 rely on
Node 8.9.0+. Starting from v3.0.0 Puppeteer starts to rely on Node 10.18.1+. All examples below use async/await which is only supported in Node v7.6.0 or greater.
Puppeteer will be familiar to people using other browser testing frameworks. You create an instance
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md#).
**Example** - navigating to https://example.com and saving a screenshot as _example.png_:
Save file as **example.js**
```js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'example.png' });
await browser.close();
})();
```
Execute script on the command line
```bash
node example.js
```
Puppeteer sets an initial page size to 800×600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md#pagesetviewportviewport).
**Example** - create a PDF.
Save file as **hn.js**
```js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://news.ycombinator.com', {
waitUntil: 'networkidle2',
});
await page.pdf({ path: 'hn.pdf', format: 'a4' });
await browser.close();
})();
```
Execute script on the command line
```bash
node hn.js
```
See [`Page.pdf()`](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md#pagepdfoptions) for more information about creating pdfs.
**Example** - evaluate script in the context of the page
Save file as **get-dimensions.js**
```js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
// Get the "viewport" of the page, as reported by the page.
const dimensions = await page.evaluate(() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio,
};
});
console.log('Dimensions:', dimensions);
await browser.close();
})();
```
Execute script on the command line
```bash
node get-dimensions.js
```
See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`.
<!-- [END getstarted] -->
<!-- [START runtimesettings] -->
## Default runtime settings
**1. Uses Headless mode**
Puppeteer launches Chromium in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). To launch a full version of Chromium, set the [`headless` option](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md#puppeteerlaunchoptions) when launching a browser:
```js
const browser = await puppeteer.launch({ headless: false }); // default is true
```
**2. Runs a bundled version of Chromium**
By default, Puppeteer downloads and uses a specific version of Chromium so its API
is guaranteed to work out of the box. To use Puppeteer with a different version of Chrome or Chromium,
pass in the executable's path when creating a `Browser` instance:
```js
const browser = await puppeteer.launch({ executablePath: '/path/to/Chrome' });
```
You can also use Puppeteer with Firefox Nightly (experimental support). See [`Puppeteer.launch()`](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md#puppeteerlaunchoptions) for more information.
See [`this article`](https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/) for a description of the differences between Chromium and Chrome. [`This article`](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users.
**3. Creates a fresh user profile**
Puppeteer creates its own browser user profile which it **cleans up on every run**.
<!-- [END runtimesettings] -->
## Resources
- [API Documentation](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md)
- [Examples](https://github.com/puppeteer/puppeteer/tree/main/examples/)
- [Community list of Puppeteer resources](https://github.com/transitive-bullshit/awesome-puppeteer)
<!-- [START debugging] -->
## Debugging tips
1. Turn off headless mode - sometimes it's useful to see what the browser is
displaying. Instead of launching in headless mode, launch a full version of
the browser using `headless: false`:
```js
const browser = await puppeteer.launch({ headless: false });
```
2. Slow it down - the `slowMo` option slows down Puppeteer operations by the
specified amount of milliseconds. It's another way to help see what's going on.
```js
const browser = await puppeteer.launch({
headless: false,
slowMo: 250, // slow down by 250ms
});
```
3. Capture console output - You can listen for the `console` event.
This is also handy when debugging code in `page.evaluate()`:
```js
page.on('console', (msg) => console.log('PAGE LOG:', msg.text()));
await page.evaluate(() => console.log(`url is ${location.href}`));
```
4. Use debugger in application code browser
There are two execution context: node.js that is running test code, and the browser
running application code being tested. This lets you debug code in the
application code browser; ie code inside `evaluate()`.
- Use `{devtools: true}` when launching Puppeteer:
```js
const browser = await puppeteer.launch({ devtools: true });
```
- Change default test timeout:
jest: `jest.setTimeout(100000);`
jasmine: `jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;`
mocha: `this.timeout(100000);` (don't forget to change test to use [function and not '=>'](https://stackoverflow.com/a/23492442))
- Add an evaluate statement with `debugger` inside / add `debugger` to an existing evaluate statement:
```js
await page.evaluate(() => {
debugger;
});
```
The test will now stop executing in the above evaluate statement, and chromium will stop in debug mode.
5. Use debugger in node.js
This will let you debug test code. For example, you can step over `await page.click()` in the node.js script and see the click happen in the application code browser.
Note that you won't be able to run `await page.click()` in
DevTools console due to this [Chromium bug](https://bugs.chromium.org/p/chromium/issues/detail?id=833928). So if
you want to try something out, you have to add it to your test file.
- Add `debugger;` to your test, eg:
```js
debugger;
await page.click('a[target=_blank]');
```
- Set `headless` to `false`
- Run `node --inspect-brk`, eg `node --inspect-brk node_modules/.bin/jest tests`
- In Chrome open `chrome://inspect/#devices` and click `inspect`
- In the newly opened test browser, type `F8` to resume test execution
- Now your `debugger` will be hit and you can debug in the test browser
6. Enable verbose logging - internal DevTools protocol traffic
will be logged via the [`debug`](https://github.com/visionmedia/debug) module under the `puppeteer` namespace.
# Basic verbose logging
env DEBUG="puppeteer:*" node script.js
# Protocol traffic can be rather noisy. This example filters out all Network domain messages
env DEBUG="puppeteer:*" env DEBUG_COLORS=true node script.js 2>&1 | grep -v '"Network'
7. Debug your Puppeteer (node) code easily, using [ndb](https://github.com/GoogleChromeLabs/ndb)
- `npm install -g ndb` (or even better, use [npx](https://github.com/zkat/npx)!)
- add a `debugger` to your Puppeteer (node) code
- add `ndb` (or `npx ndb`) before your test command. For example:
`ndb jest` or `ndb mocha` (or `npx ndb jest` / `npx ndb mocha`)
- debug your test inside chromium like a boss!
<!-- [END debugging] -->
<!-- [START typescript] -->
## Usage with TypeScript
We have recently completed a migration to move the Puppeteer source code from JavaScript to TypeScript and as of version 7.0.1 we ship our own built-in type definitions.
If you are on a version older than 7, we recommend installing the Puppeteer type definitions from the [DefinitelyTyped](https://definitelytyped.org/) repository:
```bash
npm install --save-dev @types/puppeteer
```
The types that you'll see appearing in the Puppeteer source code are based off the great work of those who have contributed to the `@types/puppeteer` package. We really appreciate the hard work those people put in to providing high quality TypeScript definitions for Puppeteer's users.
<!-- [END typescript] -->
## Contributing to Puppeteer
Check out [contributing guide](https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md) to get an overview of Puppeteer development.
<!-- [START faq] -->
# FAQ
#### Q: Who maintains Puppeteer?
The Chrome DevTools team maintains the library, but we'd love your help and expertise on the project!
See [Contributing](https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md).
#### Q: What is the status of cross-browser support?
Official Firefox support is currently experimental. The ongoing collaboration with Mozilla aims to support common end-to-end testing use cases, for which developers expect cross-browser coverage. The Puppeteer team needs input from users to stabilize Firefox support and to bring missing APIs to our attention.
From Puppeteer v2.1.0 onwards you can specify [`puppeteer.launch({product: 'firefox'})`](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md#puppeteerlaunchoptions) to run your Puppeteer scripts in Firefox Nightly, without any additional custom patches. While [an older experiment](https://www.npmjs.com/package/puppeteer-firefox) required a patched version of Firefox, [the current approach](https://wiki.mozilla.org/Remote) works with “stock” Firefox.
We will continue to collaborate with other browser vendors to bring Puppeteer support to browsers such as Safari.
This effort includes exploration of a standard for executing cross-browser commands (instead of relying on the non-standard DevTools Protocol used by Chrome).
#### Q: What are Puppeteers goals and principles?
The goals of the project are:
- Provide a slim, canonical library that highlights the capabilities of the [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/).
- Provide a reference implementation for similar testing libraries. Eventually, these other frameworks could adopt Puppeteer as their foundational layer.
- Grow the adoption of headless/automated browser testing.
- Help dogfood new DevTools Protocol features...and catch bugs!
- Learn more about the pain points of automated browser testing and help fill those gaps.
We adapt [Chromium principles](https://www.chromium.org/developers/core-principles) to help us drive product decisions:
- **Speed**: Puppeteer has almost zero performance overhead over an automated page.
- **Security**: Puppeteer operates off-process with respect to Chromium, making it safe to automate potentially malicious pages.
- **Stability**: Puppeteer should not be flaky and should not leak memory.
- **Simplicity**: Puppeteer provides a high-level API thats easy to use, understand, and debug.
#### Q: Is Puppeteer replacing Selenium/WebDriver?
**No**. Both projects are valuable for very different reasons:
- Selenium/WebDriver focuses on cross-browser automation; its value proposition is a single standard API that works across all major browsers.
- Puppeteer focuses on Chromium; its value proposition is richer functionality and higher reliability.
That said, you **can** use Puppeteer to run tests against Chromium, e.g. using the community-driven [jest-puppeteer](https://github.com/smooth-code/jest-puppeteer). While this probably shouldnt be your only testing solution, it does have a few good points compared to WebDriver:
- Puppeteer requires zero setup and comes bundled with the Chromium version it works best with, making it [very easy to start with](https://github.com/puppeteer/puppeteer/#getting-started). At the end of the day, its better to have a few tests running chromium-only, than no tests at all.
- Puppeteer has event-driven architecture, which removes a lot of potential flakiness. Theres no need for evil “sleep(1000)” calls in puppeteer scripts.
- Puppeteer runs headless by default, which makes it fast to run. Puppeteer v1.5.0 also exposes browser contexts, making it possible to efficiently parallelize test execution.
- Puppeteer shines when it comes to debugging: flip the “headless” bit to false, add “slowMo”, and youll see what the browser is doing. You can even open Chrome DevTools to inspect the test environment.
#### Q: Why doesnt Puppeteer v.XXX work with Chromium v.YYY?
We see Puppeteer as an **indivisible entity** with Chromium. Each version of Puppeteer bundles a specific version of Chromium **the only** version it is guaranteed to work with.
This is not an artificial constraint: A lot of work on Puppeteer is actually taking place in the Chromium repository. Heres a typical story:
- A Puppeteer bug is reported: https://github.com/puppeteer/puppeteer/issues/2709
- It turned out this is an issue with the DevTools protocol, so were fixing it in Chromium: https://chromium-review.googlesource.com/c/chromium/src/+/1102154
- Once the upstream fix is landed, we roll updated Chromium into Puppeteer: https://github.com/puppeteer/puppeteer/pull/2769
However, oftentimes it is desirable to use Puppeteer with the official Google Chrome rather than Chromium. For this to work, you should install a `puppeteer-core` version that corresponds to the Chrome version.
For example, in order to drive Chrome 71 with puppeteer-core, use `chrome-71` npm tag:
```bash
npm install puppeteer-core@chrome-71
```
#### Q: Which Chromium version does Puppeteer use?
Find the version using one of the following ways:
- Look for the `chromium` entry in [revisions.ts](https://github.com/puppeteer/puppeteer/blob/main/src/revisions.ts). To find the corresponding Chromium commit and version number, search for the revision prefixed by an `r` in [OmahaProxy](https://omahaproxy.appspot.com/)'s "Find Releases" section.
- Look for the `versionsPerRelease` map in [versions.js](https://github.com/puppeteer/puppeteer/blob/main/versions.js) which contains mapping between Chromium and Puppeteer versions. Note: The file contains only Puppeteer versions where Chromium is updated. Not all Puppeteer versions are listed.
#### Q: Which Firefox version does Puppeteer use?
Since Firefox support is experimental, Puppeteer downloads the latest [Firefox Nightly](https://wiki.mozilla.org/Nightly) when the `PUPPETEER_PRODUCT` environment variable is set to `firefox`. That's also why the value of `firefox` in [revisions.ts](https://github.com/puppeteer/puppeteer/blob/main/src/revisions.ts) is `latest` -- Puppeteer isn't tied to a particular Firefox version.
To fetch Firefox Nightly as part of Puppeteer installation:
```bash
PUPPETEER_PRODUCT=firefox npm i puppeteer
# or "yarn add puppeteer"
```
#### Q: Whats considered a “Navigation”?
From Puppeteers standpoint, **“navigation” is anything that changes a pages URL**.
Aside from regular navigation where the browser hits the network to fetch a new document from the web server, this includes [anchor navigations](https://www.w3.org/TR/html5/single-page.html#scroll-to-fragid) and [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) usage.
With this definition of “navigation,” **Puppeteer works seamlessly with single-page applications.**
#### Q: Whats the difference between a “trusted" and "untrusted" input event?
In browsers, input events could be divided into two big groups: trusted vs. untrusted.
- **Trusted events**: events generated by users interacting with the page, e.g. using a mouse or keyboard.
- **Untrusted event**: events generated by Web APIs, e.g. `document.createEvent` or `element.click()` methods.
Websites can distinguish between these two groups:
- using an [`Event.isTrusted`](https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted) event flag
- sniffing for accompanying events. For example, every trusted `'click'` event is preceded by `'mousedown'` and `'mouseup'` events.
For automation purposes its important to generate trusted events. **All input events generated with Puppeteer are trusted and fire proper accompanying events.** If, for some reason, one needs an untrusted event, its always possible to hop into a page context with `page.evaluate` and generate a fake event:
```js
await page.evaluate(() => {
document.querySelector('button[type=submit]').click();
});
```
#### Q: What features does Puppeteer not support?
You may find that Puppeteer does not behave as expected when controlling pages that incorporate audio and video. (For example, [video playback/screenshots is likely to fail](https://github.com/puppeteer/puppeteer/issues/291).) There are two reasons for this:
- Puppeteer is bundled with Chromium — not Chrome — and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/puppeteer/puppeteer/blob/v13.7.0/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.)
- Since Puppeteer (in all configurations) controls a desktop version of Chromium/Chrome, features that are only supported by the mobile version of Chrome are not supported. This means that Puppeteer [does not support HTTP Live Streaming (HLS)](https://caniuse.com/#feat=http-live-streaming).
#### Q: I am having trouble installing / running Puppeteer in my test environment. Where should I look for help?
We have a [troubleshooting](https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md) guide for various operating systems that lists the required dependencies.
#### Q: Chromium gets downloaded on every `npm ci` run. How can I cache the download?
The default download path is `node_modules/puppeteer/.local-chromium`. However, you can change that path with the `PUPPETEER_DOWNLOAD_PATH` environment variable.
Puppeteer uses that variable to resolve the Chromium executable location during launch, so you dont need to specify `PUPPETEER_EXECUTABLE_PATH` as well.
For example, if you wish to keep the Chromium download in `~/.npm/chromium`:
```sh
export PUPPETEER_DOWNLOAD_PATH=~/.npm/chromium
npm ci
# by default the Chromium executable path is inferred
# from the download path
npm test
# a new run of npm ci will check for the existence of
# Chromium in ~/.npm/chromium
npm ci
```
#### Q: I have more questions! Where do I ask?
There are many ways to get help on Puppeteer:
- [bugtracker](https://github.com/puppeteer/puppeteer/issues)
- [Stack Overflow](https://stackoverflow.com/questions/tagged/puppeteer)
Make sure to search these channels before posting your question.
<!-- [END faq] -->

29
node_modules/puppeteer-core/cjs-entry-core.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
/**
* We use `export default puppeteer` in `src/index.ts` to expose the library But
* TypeScript in CJS mode compiles that to `exports.default = `. This means that
* our CJS Node users would have to use `require('puppeteer').default` which
* isn't very nice.
*
* So instead we expose this file as our entry point. This requires the compiled
* Puppeteer output and re-exports the `default` export via `module.exports.`
* This means that we can publish to CJS and ESM whilst maintaining the expected
* import behaviour for CJS and ESM users.
*/
const puppeteerExport = require('./lib/cjs/puppeteer/node-puppeteer-core.js');
module.exports = puppeteerExport.default;

29
node_modules/puppeteer-core/cjs-entry.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
/**
* We use `export default puppeteer` in `src/index.ts` to expose the library But
* TypeScript in CJS mode compiles that to `exports.default = `. This means that
* our CJS Node users would have to use `require('puppeteer').default` which
* isn't very nice.
*
* So instead we expose this file as our entry point. This requires the compiled
* Puppeteer output and re-exports the `default` export via `module.exports.`
* This means that we can publish to CJS and ESM whilst maintaining the expected
* import behaviour for CJS and ESM users.
*/
const puppeteerExport = require('./lib/cjs/puppeteer/node.js');
module.exports = puppeteerExport.default;

89
node_modules/puppeteer-core/install.js generated vendored Normal file
View File

@@ -0,0 +1,89 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/
/**
* This file is part of public API.
*
* By default, the `puppeteer` package runs this script during the installation
* process unless one of the env flags is provided.
* `puppeteer-core` package doesn't include this step at all. However, it's
* still possible to install a supported browser using this script when
* necessary.
*/
const compileTypeScriptIfRequired = require('./typescript-if-required.js');
async function download() {
await compileTypeScriptIfRequired();
// need to ensure TS is compiled before loading the installer
const {
downloadBrowser,
logPolitely,
} = require('./lib/cjs/puppeteer/node/install.js');
if (process.env.PUPPETEER_SKIP_DOWNLOAD) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_DOWNLOAD" environment variable was found.'
);
return;
}
if (
process.env.NPM_CONFIG_PUPPETEER_SKIP_DOWNLOAD ||
process.env.npm_config_puppeteer_skip_download
) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_DOWNLOAD" was set in npm config.'
);
return;
}
if (
process.env.NPM_PACKAGE_CONFIG_PUPPETEER_SKIP_DOWNLOAD ||
process.env.npm_package_config_puppeteer_skip_download
) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_DOWNLOAD" was set in project config.'
);
return;
}
if (process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" environment variable was found.'
);
return;
}
if (
process.env.NPM_CONFIG_PUPPETEER_SKIP_CHROMIUM_DOWNLOAD ||
process.env.npm_config_puppeteer_skip_chromium_download
) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" was set in npm config.'
);
return;
}
if (
process.env.NPM_PACKAGE_CONFIG_PUPPETEER_SKIP_CHROMIUM_DOWNLOAD ||
process.env.npm_package_config_puppeteer_skip_chromium_download
) {
logPolitely(
'**INFO** Skipping browser download. "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" was set in project config.'
);
return;
}
downloadBrowser();
}
download();

View File

@@ -0,0 +1,111 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { LaunchOptions, BrowserLaunchArgumentOptions } from './node/LaunchOptions.js';
import { BrowserConnectOptions } from './common/BrowserConnector.js';
import { Product } from './common/Product.js';
import { Browser } from './common/Browser.js';
import { ConnectOptions } from './common/Puppeteer.js';
import { DevicesMap } from './common/DeviceDescriptors.js';
import { PuppeteerErrors } from './common/Errors.js';
import { PredefinedNetworkConditions } from './common/NetworkConditions.js';
import { CustomQueryHandler } from './common/QueryHandler.js';
export * from './common/Accessibility.js';
export * from './common/Browser.js';
export * from './node/BrowserFetcher.js';
export * from './node/Puppeteer.js';
export * from './common/Coverage.js';
export * from './common/Connection.js';
export * from './common/ConsoleMessage.js';
export * from './common/Coverage.js';
export * from './common/DeviceDescriptors.js';
export * from './common/Dialog.js';
export * from './common/DOMWorld.js';
export * from './common/JSHandle.js';
export * from './common/ExecutionContext.js';
export * from './common/EventEmitter.js';
export * from './common/FileChooser.js';
export * from './common/FrameManager.js';
export * from './common/PuppeteerViewport.js';
export * from './common/Input.js';
export * from './common/Page.js';
export * from './common/Product.js';
export * from './common/Puppeteer.js';
export * from './common/BrowserConnector.js';
export * from './node/Launcher.js';
export * from './node/LaunchOptions.js';
export * from './common/HTTPRequest.js';
export * from './common/HTTPResponse.js';
export * from './common/SecurityDetails.js';
export * from './common/Target.js';
export * from './common/Errors.js';
export * from './common/Tracing.js';
export * from './common/NetworkManager.js';
export * from './common/WebWorker.js';
export * from './common/USKeyboardLayout.js';
export * from './common/EvalTypes.js';
export * from './common/PDFOptions.js';
export * from './common/TimeoutSettings.js';
export * from './common/LifecycleWatcher.js';
export * from './common/QueryHandler.js';
export * from './common/NetworkConditions.js';
export * from 'devtools-protocol/types/protocol';
/**
* @public
* {@inheritDoc PuppeteerNode.launch}
*/
export declare function launch(options?: LaunchOptions & BrowserLaunchArgumentOptions & BrowserConnectOptions & {
product?: Product;
extraPrefsFirefox?: Record<string, unknown>;
}): Promise<Browser>;
/**
* @public
* {@inheritDoc PuppeteerNode.connect}
*/
export declare function connect(options: ConnectOptions): Promise<Browser>;
/**
* @public
* {@inheritDoc Puppeteer.devices}
*/
export declare let devices: DevicesMap;
/**
* @public
*/
export declare let errors: PuppeteerErrors;
/**
* @public
*/
export declare let networkConditions: PredefinedNetworkConditions;
/**
* @public
* {@inheritDoc Puppeteer.registerCustomQueryHandler}
*/
export declare function registerCustomQueryHandler(name: string, queryHandler: CustomQueryHandler): void;
/**
* @public
* {@inheritDoc Puppeteer.unregisterCustomQueryHandler}
*/
export declare function unregisterCustomQueryHandler(name: string): void;
/**
* @public
* {@inheritDoc Puppeteer.customQueryHandlerNames}
*/
export declare function customQueryHandlerNames(): string[];
/**
* @public
* {@inheritDoc Puppeteer.clearCustomQueryHandlers}
*/
export declare function clearCustomQueryHandlers(): void;
//# sourceMappingURL=api-docs-entry.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"api-docs-entry.d.ts","sourceRoot":"","sources":["../../../src/api-docs-entry.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,85 @@
"use strict";
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.networkConditions = exports.errors = exports.devices = void 0;
/*
* This file re-exports any APIs that we want to have documentation generated
* for. It is used by API Extractor to determine what parts of the system to
* document.
*
* The legacy DocLint system and the unit test coverage system use the list of
* modules defined in coverage-utils.js. src/api-docs-entry.ts is ONLY used by
* API Extractor.
*
* Once we have migrated to API Extractor and removed DocLint we can remove the
* duplication and use this file.
*/
__exportStar(require("./common/Accessibility.js"), exports);
__exportStar(require("./common/Browser.js"), exports);
__exportStar(require("./node/BrowserFetcher.js"), exports);
__exportStar(require("./node/Puppeteer.js"), exports);
__exportStar(require("./common/Coverage.js"), exports);
__exportStar(require("./common/Connection.js"), exports);
__exportStar(require("./common/ConsoleMessage.js"), exports);
__exportStar(require("./common/Coverage.js"), exports);
__exportStar(require("./common/DeviceDescriptors.js"), exports);
__exportStar(require("./common/Dialog.js"), exports);
__exportStar(require("./common/DOMWorld.js"), exports);
__exportStar(require("./common/JSHandle.js"), exports);
__exportStar(require("./common/ExecutionContext.js"), exports);
__exportStar(require("./common/EventEmitter.js"), exports);
__exportStar(require("./common/FileChooser.js"), exports);
__exportStar(require("./common/FrameManager.js"), exports);
__exportStar(require("./common/PuppeteerViewport.js"), exports);
__exportStar(require("./common/Input.js"), exports);
__exportStar(require("./common/Page.js"), exports);
__exportStar(require("./common/Product.js"), exports);
__exportStar(require("./common/Puppeteer.js"), exports);
__exportStar(require("./common/BrowserConnector.js"), exports);
__exportStar(require("./node/Launcher.js"), exports);
__exportStar(require("./node/LaunchOptions.js"), exports);
__exportStar(require("./common/HTTPRequest.js"), exports);
__exportStar(require("./common/HTTPResponse.js"), exports);
__exportStar(require("./common/SecurityDetails.js"), exports);
__exportStar(require("./common/Target.js"), exports);
__exportStar(require("./common/Errors.js"), exports);
__exportStar(require("./common/Tracing.js"), exports);
__exportStar(require("./common/NetworkManager.js"), exports);
__exportStar(require("./common/WebWorker.js"), exports);
__exportStar(require("./common/USKeyboardLayout.js"), exports);
__exportStar(require("./common/EvalTypes.js"), exports);
__exportStar(require("./common/PDFOptions.js"), exports);
__exportStar(require("./common/TimeoutSettings.js"), exports);
__exportStar(require("./common/LifecycleWatcher.js"), exports);
__exportStar(require("./common/QueryHandler.js"), exports);
__exportStar(require("./common/NetworkConditions.js"), exports);
__exportStar(require("devtools-protocol/types/protocol"), exports);
//# sourceMappingURL=api-docs-entry.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"api-docs-entry.js","sourceRoot":"","sources":["../../../src/api-docs-entry.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;;;;;;;;;;;;;;;AAeH;;;;;;;;;;;GAWG;AACH,4DAA0C;AAC1C,sDAAoC;AACpC,2DAAyC;AACzC,sDAAoC;AACpC,uDAAqC;AACrC,yDAAuC;AACvC,6DAA2C;AAC3C,uDAAqC;AACrC,gEAA8C;AAC9C,qDAAmC;AACnC,uDAAqC;AACrC,uDAAqC;AACrC,+DAA6C;AAC7C,2DAAyC;AACzC,0DAAwC;AACxC,2DAAyC;AACzC,gEAA8C;AAC9C,oDAAkC;AAClC,mDAAiC;AACjC,sDAAoC;AACpC,wDAAsC;AACtC,+DAA6C;AAC7C,qDAAmC;AACnC,0DAAwC;AACxC,0DAAwC;AACxC,2DAAyC;AACzC,8DAA4C;AAC5C,qDAAmC;AACnC,qDAAmC;AACnC,sDAAoC;AACpC,6DAA2C;AAC3C,wDAAsC;AACtC,+DAA6C;AAC7C,wDAAsC;AACtC,yDAAuC;AACvC,8DAA4C;AAC5C,+DAA6C;AAC7C,2DAAyC;AACzC,gEAA8C;AAC9C,mEAAiD"}

View File

@@ -0,0 +1,176 @@
/**
* Copyright 2018 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CDPSession } from './Connection.js';
import { ElementHandle } from './JSHandle.js';
/**
* Represents a Node and the properties of it that are relevant to Accessibility.
* @public
*/
export interface SerializedAXNode {
/**
* The {@link https://www.w3.org/TR/wai-aria/#usage_intro | role} of the node.
*/
role: string;
/**
* A human readable name for the node.
*/
name?: string;
/**
* The current value of the node.
*/
value?: string | number;
/**
* An additional human readable description of the node.
*/
description?: string;
/**
* Any keyboard shortcuts associated with this node.
*/
keyshortcuts?: string;
/**
* A human readable alternative to the role.
*/
roledescription?: string;
/**
* A description of the current value.
*/
valuetext?: string;
disabled?: boolean;
expanded?: boolean;
focused?: boolean;
modal?: boolean;
multiline?: boolean;
/**
* Whether more than one child can be selected.
*/
multiselectable?: boolean;
readonly?: boolean;
required?: boolean;
selected?: boolean;
/**
* Whether the checkbox is checked, or in a
* {@link https://www.w3.org/TR/wai-aria-practices/examples/checkbox/checkbox-2/checkbox-2.html | mixed state}.
*/
checked?: boolean | 'mixed';
/**
* Whether the node is checked or in a mixed state.
*/
pressed?: boolean | 'mixed';
/**
* The level of a heading.
*/
level?: number;
valuemin?: number;
valuemax?: number;
autocomplete?: string;
haspopup?: string;
/**
* Whether and in what way this node's value is invalid.
*/
invalid?: string;
orientation?: string;
/**
* Children of this node, if there are any.
*/
children?: SerializedAXNode[];
}
/**
* @public
*/
export interface SnapshotOptions {
/**
* Prune uninteresting nodes from the tree.
* @defaultValue true
*/
interestingOnly?: boolean;
/**
* Root node to get the accessibility tree for
* @defaultValue The root node of the entire page.
*/
root?: ElementHandle;
}
/**
* The Accessibility class provides methods for inspecting Chromium's
* accessibility tree. The accessibility tree is used by assistive technology
* such as {@link https://en.wikipedia.org/wiki/Screen_reader | screen readers} or
* {@link https://en.wikipedia.org/wiki/Switch_access | switches}.
*
* @remarks
*
* Accessibility is a very platform-specific thing. On different platforms,
* there are different screen readers that might have wildly different output.
*
* Blink - Chrome's rendering engine - has a concept of "accessibility tree",
* which is then translated into different platform-specific APIs. Accessibility
* namespace gives users access to the Blink Accessibility Tree.
*
* Most of the accessibility tree gets filtered out when converting from Blink
* AX Tree to Platform-specific AX-Tree or by assistive technologies themselves.
* By default, Puppeteer tries to approximate this filtering, exposing only
* the "interesting" nodes of the tree.
*
* @public
*/
export declare class Accessibility {
private _client;
/**
* @internal
*/
constructor(client: CDPSession);
/**
* Captures the current state of the accessibility tree.
* The returned object represents the root accessible node of the page.
*
* @remarks
*
* **NOTE** The Chromium accessibility tree contains nodes that go unused on
* most platforms and by most screen readers. Puppeteer will discard them as
* well for an easier to process tree, unless `interestingOnly` is set to
* `false`.
*
* @example
* An example of dumping the entire accessibility tree:
* ```js
* const snapshot = await page.accessibility.snapshot();
* console.log(snapshot);
* ```
*
* @example
* An example of logging the focused node's name:
* ```js
* const snapshot = await page.accessibility.snapshot();
* const node = findFocusedNode(snapshot);
* console.log(node && node.name);
*
* function findFocusedNode(node) {
* if (node.focused)
* return node;
* for (const child of node.children || []) {
* const foundNode = findFocusedNode(child);
* return foundNode;
* }
* return null;
* }
* ```
*
* @returns An AXNode object representing the snapshot.
*
*/
snapshot(options?: SnapshotOptions): Promise<SerializedAXNode>;
private serializeTree;
private collectInterestingNodes;
}
//# sourceMappingURL=Accessibility.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Accessibility.d.ts","sourceRoot":"","sources":["../../../../src/common/Accessibility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAC5B;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAa;IAE5B;;OAEG;gBACS,MAAM,EAAE,UAAU;IAI9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsCG;IACU,QAAQ,CACnB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,gBAAgB,CAAC;IA0B5B,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,uBAAuB;CAWhC"}

View File

@@ -0,0 +1,361 @@
"use strict";
/**
* Copyright 2018 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Accessibility = void 0;
/**
* The Accessibility class provides methods for inspecting Chromium's
* accessibility tree. The accessibility tree is used by assistive technology
* such as {@link https://en.wikipedia.org/wiki/Screen_reader | screen readers} or
* {@link https://en.wikipedia.org/wiki/Switch_access | switches}.
*
* @remarks
*
* Accessibility is a very platform-specific thing. On different platforms,
* there are different screen readers that might have wildly different output.
*
* Blink - Chrome's rendering engine - has a concept of "accessibility tree",
* which is then translated into different platform-specific APIs. Accessibility
* namespace gives users access to the Blink Accessibility Tree.
*
* Most of the accessibility tree gets filtered out when converting from Blink
* AX Tree to Platform-specific AX-Tree or by assistive technologies themselves.
* By default, Puppeteer tries to approximate this filtering, exposing only
* the "interesting" nodes of the tree.
*
* @public
*/
class Accessibility {
/**
* @internal
*/
constructor(client) {
this._client = client;
}
/**
* Captures the current state of the accessibility tree.
* The returned object represents the root accessible node of the page.
*
* @remarks
*
* **NOTE** The Chromium accessibility tree contains nodes that go unused on
* most platforms and by most screen readers. Puppeteer will discard them as
* well for an easier to process tree, unless `interestingOnly` is set to
* `false`.
*
* @example
* An example of dumping the entire accessibility tree:
* ```js
* const snapshot = await page.accessibility.snapshot();
* console.log(snapshot);
* ```
*
* @example
* An example of logging the focused node's name:
* ```js
* const snapshot = await page.accessibility.snapshot();
* const node = findFocusedNode(snapshot);
* console.log(node && node.name);
*
* function findFocusedNode(node) {
* if (node.focused)
* return node;
* for (const child of node.children || []) {
* const foundNode = findFocusedNode(child);
* return foundNode;
* }
* return null;
* }
* ```
*
* @returns An AXNode object representing the snapshot.
*
*/
async snapshot(options = {}) {
const { interestingOnly = true, root = null } = options;
const { nodes } = await this._client.send('Accessibility.getFullAXTree');
let backendNodeId = null;
if (root) {
const { node } = await this._client.send('DOM.describeNode', {
objectId: root._remoteObject.objectId,
});
backendNodeId = node.backendNodeId;
}
const defaultRoot = AXNode.createTree(nodes);
let needle = defaultRoot;
if (backendNodeId) {
needle = defaultRoot.find((node) => node.payload.backendDOMNodeId === backendNodeId);
if (!needle)
return null;
}
if (!interestingOnly)
return this.serializeTree(needle)[0];
const interestingNodes = new Set();
this.collectInterestingNodes(interestingNodes, defaultRoot, false);
if (!interestingNodes.has(needle))
return null;
return this.serializeTree(needle, interestingNodes)[0];
}
serializeTree(node, interestingNodes) {
const children = [];
for (const child of node.children)
children.push(...this.serializeTree(child, interestingNodes));
if (interestingNodes && !interestingNodes.has(node))
return children;
const serializedNode = node.serialize();
if (children.length)
serializedNode.children = children;
return [serializedNode];
}
collectInterestingNodes(collection, node, insideControl) {
if (node.isInteresting(insideControl))
collection.add(node);
if (node.isLeafNode())
return;
insideControl = insideControl || node.isControl();
for (const child of node.children)
this.collectInterestingNodes(collection, child, insideControl);
}
}
exports.Accessibility = Accessibility;
class AXNode {
constructor(payload) {
this.children = [];
this._richlyEditable = false;
this._editable = false;
this._focusable = false;
this._hidden = false;
this.payload = payload;
this._name = this.payload.name ? this.payload.name.value : '';
this._role = this.payload.role ? this.payload.role.value : 'Unknown';
this._ignored = this.payload.ignored;
for (const property of this.payload.properties || []) {
if (property.name === 'editable') {
this._richlyEditable = property.value.value === 'richtext';
this._editable = true;
}
if (property.name === 'focusable')
this._focusable = property.value.value;
if (property.name === 'hidden')
this._hidden = property.value.value;
}
}
_isPlainTextField() {
if (this._richlyEditable)
return false;
if (this._editable)
return true;
return this._role === 'textbox' || this._role === 'searchbox';
}
_isTextOnlyObject() {
const role = this._role;
return role === 'LineBreak' || role === 'text' || role === 'InlineTextBox';
}
_hasFocusableChild() {
if (this._cachedHasFocusableChild === undefined) {
this._cachedHasFocusableChild = false;
for (const child of this.children) {
if (child._focusable || child._hasFocusableChild()) {
this._cachedHasFocusableChild = true;
break;
}
}
}
return this._cachedHasFocusableChild;
}
find(predicate) {
if (predicate(this))
return this;
for (const child of this.children) {
const result = child.find(predicate);
if (result)
return result;
}
return null;
}
isLeafNode() {
if (!this.children.length)
return true;
// These types of objects may have children that we use as internal
// implementation details, but we want to expose them as leaves to platform
// accessibility APIs because screen readers might be confused if they find
// any children.
if (this._isPlainTextField() || this._isTextOnlyObject())
return true;
// Roles whose children are only presentational according to the ARIA and
// HTML5 Specs should be hidden from screen readers.
// (Note that whilst ARIA buttons can have only presentational children, HTML5
// buttons are allowed to have content.)
switch (this._role) {
case 'doc-cover':
case 'graphics-symbol':
case 'img':
case 'Meter':
case 'scrollbar':
case 'slider':
case 'separator':
case 'progressbar':
return true;
default:
break;
}
// Here and below: Android heuristics
if (this._hasFocusableChild())
return false;
if (this._focusable && this._name)
return true;
if (this._role === 'heading' && this._name)
return true;
return false;
}
isControl() {
switch (this._role) {
case 'button':
case 'checkbox':
case 'ColorWell':
case 'combobox':
case 'DisclosureTriangle':
case 'listbox':
case 'menu':
case 'menubar':
case 'menuitem':
case 'menuitemcheckbox':
case 'menuitemradio':
case 'radio':
case 'scrollbar':
case 'searchbox':
case 'slider':
case 'spinbutton':
case 'switch':
case 'tab':
case 'textbox':
case 'tree':
case 'treeitem':
return true;
default:
return false;
}
}
isInteresting(insideControl) {
const role = this._role;
if (role === 'Ignored' || this._hidden || this._ignored)
return false;
if (this._focusable || this._richlyEditable)
return true;
// If it's not focusable but has a control role, then it's interesting.
if (this.isControl())
return true;
// A non focusable child of a control is not interesting
if (insideControl)
return false;
return this.isLeafNode() && !!this._name;
}
serialize() {
const properties = new Map();
for (const property of this.payload.properties || [])
properties.set(property.name.toLowerCase(), property.value.value);
if (this.payload.name)
properties.set('name', this.payload.name.value);
if (this.payload.value)
properties.set('value', this.payload.value.value);
if (this.payload.description)
properties.set('description', this.payload.description.value);
const node = {
role: this._role,
};
const userStringProperties = [
'name',
'value',
'description',
'keyshortcuts',
'roledescription',
'valuetext',
];
const getUserStringPropertyValue = (key) => properties.get(key);
for (const userStringProperty of userStringProperties) {
if (!properties.has(userStringProperty))
continue;
node[userStringProperty] = getUserStringPropertyValue(userStringProperty);
}
const booleanProperties = [
'disabled',
'expanded',
'focused',
'modal',
'multiline',
'multiselectable',
'readonly',
'required',
'selected',
];
const getBooleanPropertyValue = (key) => properties.get(key);
for (const booleanProperty of booleanProperties) {
// RootWebArea's treat focus differently than other nodes. They report whether
// their frame has focus, not whether focus is specifically on the root
// node.
if (booleanProperty === 'focused' && this._role === 'RootWebArea')
continue;
const value = getBooleanPropertyValue(booleanProperty);
if (!value)
continue;
node[booleanProperty] = getBooleanPropertyValue(booleanProperty);
}
const tristateProperties = ['checked', 'pressed'];
for (const tristateProperty of tristateProperties) {
if (!properties.has(tristateProperty))
continue;
const value = properties.get(tristateProperty);
node[tristateProperty] =
value === 'mixed' ? 'mixed' : value === 'true' ? true : false;
}
const numericalProperties = [
'level',
'valuemax',
'valuemin',
];
const getNumericalPropertyValue = (key) => properties.get(key);
for (const numericalProperty of numericalProperties) {
if (!properties.has(numericalProperty))
continue;
node[numericalProperty] = getNumericalPropertyValue(numericalProperty);
}
const tokenProperties = [
'autocomplete',
'haspopup',
'invalid',
'orientation',
];
const getTokenPropertyValue = (key) => properties.get(key);
for (const tokenProperty of tokenProperties) {
const value = getTokenPropertyValue(tokenProperty);
if (!value || value === 'false')
continue;
node[tokenProperty] = getTokenPropertyValue(tokenProperty);
}
return node;
}
static createTree(payloads) {
const nodeById = new Map();
for (const payload of payloads)
nodeById.set(payload.nodeId, new AXNode(payload));
for (const node of nodeById.values()) {
for (const childId of node.payload.childIds || [])
node.children.push(nodeById.get(childId));
}
return nodeById.values().next().value;
}
}
//# sourceMappingURL=Accessibility.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,21 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { InternalQueryHandler } from './QueryHandler.js';
/**
* @internal
*/
export declare const ariaHandler: InternalQueryHandler;
//# sourceMappingURL=AriaQueryHandler.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AriaQueryHandler.d.ts","sourceRoot":"","sources":["../../../../src/common/AriaQueryHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAoHzD;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,oBAKzB,CAAC"}

View File

@@ -0,0 +1,85 @@
"use strict";
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ariaHandler = void 0;
async function queryAXTree(client, element, accessibleName, role) {
const { nodes } = await client.send('Accessibility.queryAXTree', {
objectId: element._remoteObject.objectId,
accessibleName,
role,
});
const filteredNodes = nodes.filter((node) => node.role.value !== 'StaticText');
return filteredNodes;
}
const normalizeValue = (value) => value.replace(/ +/g, ' ').trim();
const knownAttributes = new Set(['name', 'role']);
const attributeRegexp = /\[\s*(?<attribute>\w+)\s*=\s*(?<quote>"|')(?<value>\\.|.*?(?=\k<quote>))\k<quote>\s*\]/g;
function parseAriaSelector(selector) {
const queryOptions = {};
const defaultName = selector.replace(attributeRegexp, (_, attribute, quote, value) => {
attribute = attribute.trim();
if (!knownAttributes.has(attribute))
throw new Error(`Unknown aria attribute "${attribute}" in selector`);
queryOptions[attribute] = normalizeValue(value);
return '';
});
if (defaultName && !queryOptions.name)
queryOptions.name = normalizeValue(defaultName);
return queryOptions;
}
const queryOne = async (element, selector) => {
const exeCtx = element.executionContext();
const { name, role } = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role);
if (res.length < 1) {
return null;
}
return exeCtx._adoptBackendNodeId(res[0].backendDOMNodeId);
};
const waitFor = async (domWorld, selector, options) => {
const binding = {
name: 'ariaQuerySelector',
pptrFunction: async (selector) => {
const root = options.root || (await domWorld._document());
const element = await queryOne(root, selector);
return element;
},
};
return domWorld.waitForSelectorInPage((_, selector) => globalThis.ariaQuerySelector(selector), selector, options, binding);
};
const queryAll = async (element, selector) => {
const exeCtx = element.executionContext();
const { name, role } = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role);
return Promise.all(res.map((axNode) => exeCtx._adoptBackendNodeId(axNode.backendDOMNodeId)));
};
const queryAllArray = async (element, selector) => {
const elementHandles = await queryAll(element, selector);
const exeCtx = element.executionContext();
const jsHandle = exeCtx.evaluateHandle((...elements) => elements, ...elementHandles);
return jsHandle;
};
/**
* @internal
*/
exports.ariaHandler = {
queryOne,
waitFor,
queryAll,
queryAllArray,
};
//# sourceMappingURL=AriaQueryHandler.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AriaQueryHandler.js","sourceRoot":"","sources":["../../../../src/common/AriaQueryHandler.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,456 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/
/// <reference types="node" />
import { Target } from './Target.js';
import { EventEmitter } from './EventEmitter.js';
import { Connection } from './Connection.js';
import { Protocol } from 'devtools-protocol';
import { Page } from './Page.js';
import { ChildProcess } from 'child_process';
import { Viewport } from './PuppeteerViewport.js';
/**
* BrowserContext options.
*
* @public
*/
export interface BrowserContextOptions {
/**
* Proxy server with optional port to use for all requests.
* Username and password can be set in `Page.authenticate`.
*/
proxyServer?: string;
/**
* Bypass the proxy for the given semi-colon-separated list of hosts.
*/
proxyBypassList?: string[];
}
/**
* @internal
*/
export declare type BrowserCloseCallback = () => Promise<void> | void;
/**
* @public
*/
export declare type TargetFilterCallback = (target: Protocol.Target.TargetInfo) => boolean;
/**
* @public
*/
export declare type Permission = 'geolocation' | 'midi' | 'notifications' | 'camera' | 'microphone' | 'background-sync' | 'ambient-light-sensor' | 'accelerometer' | 'gyroscope' | 'magnetometer' | 'accessibility-events' | 'clipboard-read' | 'clipboard-write' | 'payment-handler' | 'persistent-storage' | 'idle-detection' | 'midi-sysex';
/**
* @public
*/
export interface WaitForTargetOptions {
/**
* Maximum wait time in milliseconds. Pass `0` to disable the timeout.
* @defaultValue 30 seconds.
*/
timeout?: number;
}
/**
* All the events a {@link Browser | browser instance} may emit.
*
* @public
*/
export declare const enum BrowserEmittedEvents {
/**
* Emitted when Puppeteer gets disconnected from the Chromium instance. This
* might happen because of one of the following:
*
* - Chromium is closed or crashed
*
* - The {@link Browser.disconnect | browser.disconnect } method was called.
*/
Disconnected = "disconnected",
/**
* Emitted when the url of a target changes. Contains a {@link Target} instance.
*
* @remarks
*
* Note that this includes target changes in incognito browser contexts.
*/
TargetChanged = "targetchanged",
/**
* Emitted when a target is created, for example when a new page is opened by
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/open | window.open}
* or by {@link Browser.newPage | browser.newPage}
*
* Contains a {@link Target} instance.
*
* @remarks
*
* Note that this includes target creations in incognito browser contexts.
*/
TargetCreated = "targetcreated",
/**
* Emitted when a target is destroyed, for example when a page is closed.
* Contains a {@link Target} instance.
*
* @remarks
*
* Note that this includes target destructions in incognito browser contexts.
*/
TargetDestroyed = "targetdestroyed"
}
/**
* A Browser is created when Puppeteer connects to a Chromium instance, either through
* {@link PuppeteerNode.launch} or {@link Puppeteer.connect}.
*
* @remarks
*
* The Browser class extends from Puppeteer's {@link EventEmitter} class and will
* emit various events which are documented in the {@link BrowserEmittedEvents} enum.
*
* @example
*
* An example of using a {@link Browser} to create a {@link Page}:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://example.com');
* await browser.close();
* })();
* ```
*
* @example
*
* An example of disconnecting from and reconnecting to a {@link Browser}:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* // Store the endpoint to be able to reconnect to Chromium
* const browserWSEndpoint = browser.wsEndpoint();
* // Disconnect puppeteer from Chromium
* browser.disconnect();
*
* // Use the endpoint to reestablish a connection
* const browser2 = await puppeteer.connect({browserWSEndpoint});
* // Close Chromium
* await browser2.close();
* })();
* ```
*
* @public
*/
export declare class Browser extends EventEmitter {
/**
* @internal
*/
static create(connection: Connection, contextIds: string[], ignoreHTTPSErrors: boolean, defaultViewport?: Viewport | null, process?: ChildProcess, closeCallback?: BrowserCloseCallback, targetFilterCallback?: TargetFilterCallback): Promise<Browser>;
private _ignoreHTTPSErrors;
private _defaultViewport?;
private _process?;
private _connection;
private _closeCallback;
private _targetFilterCallback;
private _defaultContext;
private _contexts;
private _screenshotTaskQueue;
private _ignoredTargets;
/**
* @internal
* Used in Target.ts directly so cannot be marked private.
*/
_targets: Map<string, Target>;
/**
* @internal
*/
constructor(connection: Connection, contextIds: string[], ignoreHTTPSErrors: boolean, defaultViewport?: Viewport | null, process?: ChildProcess, closeCallback?: BrowserCloseCallback, targetFilterCallback?: TargetFilterCallback);
/**
* The spawned browser process. Returns `null` if the browser instance was created with
* {@link Puppeteer.connect}.
*/
process(): ChildProcess | null;
/**
* Creates a new incognito browser context. This won't share cookies/cache with other
* browser contexts.
*
* @example
* ```js
* (async () => {
* const browser = await puppeteer.launch();
* // Create a new incognito browser context.
* const context = await browser.createIncognitoBrowserContext();
* // Create a new page in a pristine context.
* const page = await context.newPage();
* // Do stuff
* await page.goto('https://example.com');
* })();
* ```
*/
createIncognitoBrowserContext(options?: BrowserContextOptions): Promise<BrowserContext>;
/**
* Returns an array of all open browser contexts. In a newly created browser, this will
* return a single instance of {@link BrowserContext}.
*/
browserContexts(): BrowserContext[];
/**
* Returns the default browser context. The default browser context cannot be closed.
*/
defaultBrowserContext(): BrowserContext;
/**
* @internal
* Used by BrowserContext directly so cannot be marked private.
*/
_disposeContext(contextId?: string): Promise<void>;
private _targetCreated;
private _targetDestroyed;
private _targetInfoChanged;
/**
* The browser websocket endpoint which can be used as an argument to
* {@link Puppeteer.connect}.
*
* @returns The Browser websocket url.
*
* @remarks
*
* The format is `ws://${host}:${port}/devtools/browser/<id>`.
*
* You can find the `webSocketDebuggerUrl` from `http://${host}:${port}/json/version`.
* Learn more about the
* {@link https://chromedevtools.github.io/devtools-protocol | devtools protocol} and
* the {@link
* https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target
* | browser endpoint}.
*/
wsEndpoint(): string;
/**
* Promise which resolves to a new {@link Page} object. The Page is created in
* a default browser context.
*/
newPage(): Promise<Page>;
/**
* @internal
* Used by BrowserContext directly so cannot be marked private.
*/
_createPageInContext(contextId?: string): Promise<Page>;
/**
* All active targets inside the Browser. In case of multiple browser contexts, returns
* an array with all the targets in all browser contexts.
*/
targets(): Target[];
/**
* The target associated with the browser.
*/
target(): Target;
/**
* Searches for a target in all browser contexts.
*
* @param predicate - A function to be run for every target.
* @returns The first target found that matches the `predicate` function.
*
* @example
*
* An example of finding a target for a page opened via `window.open`:
* ```js
* await page.evaluate(() => window.open('https://www.example.com/'));
* const newWindowTarget = await browser.waitForTarget(target => target.url() === 'https://www.example.com/');
* ```
*/
waitForTarget(predicate: (x: Target) => boolean | Promise<boolean>, options?: WaitForTargetOptions): Promise<Target>;
/**
* An array of all open pages inside the Browser.
*
* @remarks
*
* In case of multiple browser contexts, returns an array with all the pages in all
* browser contexts. Non-visible pages, such as `"background_page"`, will not be listed
* here. You can find them using {@link Target.page}.
*/
pages(): Promise<Page[]>;
/**
* A string representing the browser name and version.
*
* @remarks
*
* For headless Chromium, this is similar to `HeadlessChrome/61.0.3153.0`. For
* non-headless, this is similar to `Chrome/61.0.3153.0`.
*
* The format of browser.version() might change with future releases of Chromium.
*/
version(): Promise<string>;
/**
* The browser's original user agent. Pages can override the browser user agent with
* {@link Page.setUserAgent}.
*/
userAgent(): Promise<string>;
/**
* Closes Chromium and all of its pages (if any were opened). The {@link Browser} object
* itself is considered to be disposed and cannot be used anymore.
*/
close(): Promise<void>;
/**
* Disconnects Puppeteer from the browser, but leaves the Chromium process running.
* After calling `disconnect`, the {@link Browser} object is considered disposed and
* cannot be used anymore.
*/
disconnect(): void;
/**
* Indicates that the browser is connected.
*/
isConnected(): boolean;
private _getVersion;
}
/**
* @public
*/
export declare const enum BrowserContextEmittedEvents {
/**
* Emitted when the url of a target inside the browser context changes.
* Contains a {@link Target} instance.
*/
TargetChanged = "targetchanged",
/**
* Emitted when a target is created within the browser context, for example
* when a new page is opened by
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/open | window.open}
* or by {@link BrowserContext.newPage | browserContext.newPage}
*
* Contains a {@link Target} instance.
*/
TargetCreated = "targetcreated",
/**
* Emitted when a target is destroyed within the browser context, for example
* when a page is closed. Contains a {@link Target} instance.
*/
TargetDestroyed = "targetdestroyed"
}
/**
* BrowserContexts provide a way to operate multiple independent browser
* sessions. When a browser is launched, it has a single BrowserContext used by
* default. The method {@link Browser.newPage | Browser.newPage} creates a page
* in the default browser context.
*
* @remarks
*
* The Browser class extends from Puppeteer's {@link EventEmitter} class and
* will emit various events which are documented in the
* {@link BrowserContextEmittedEvents} enum.
*
* If a page opens another page, e.g. with a `window.open` call, the popup will
* belong to the parent page's browser context.
*
* Puppeteer allows creation of "incognito" browser contexts with
* {@link Browser.createIncognitoBrowserContext | Browser.createIncognitoBrowserContext}
* method. "Incognito" browser contexts don't write any browsing data to disk.
*
* @example
* ```js
* // Create a new incognito browser context
* const context = await browser.createIncognitoBrowserContext();
* // Create a new page inside context.
* const page = await context.newPage();
* // ... do stuff with page ...
* await page.goto('https://example.com');
* // Dispose context once it's no longer needed.
* await context.close();
* ```
* @public
*/
export declare class BrowserContext extends EventEmitter {
private _connection;
private _browser;
private _id?;
/**
* @internal
*/
constructor(connection: Connection, browser: Browser, contextId?: string);
/**
* An array of all active targets inside the browser context.
*/
targets(): Target[];
/**
* This searches for a target in this specific browser context.
*
* @example
* An example of finding a target for a page opened via `window.open`:
* ```js
* await page.evaluate(() => window.open('https://www.example.com/'));
* const newWindowTarget = await browserContext.waitForTarget(target => target.url() === 'https://www.example.com/');
* ```
*
* @param predicate - A function to be run for every target
* @param options - An object of options. Accepts a timout,
* which is the maximum wait time in milliseconds.
* Pass `0` to disable the timeout. Defaults to 30 seconds.
* @returns Promise which resolves to the first target found
* that matches the `predicate` function.
*/
waitForTarget(predicate: (x: Target) => boolean | Promise<boolean>, options?: {
timeout?: number;
}): Promise<Target>;
/**
* An array of all pages inside the browser context.
*
* @returns Promise which resolves to an array of all open pages.
* Non visible pages, such as `"background_page"`, will not be listed here.
* You can find them using {@link Target.page | the target page}.
*/
pages(): Promise<Page[]>;
/**
* Returns whether BrowserContext is incognito.
* The default browser context is the only non-incognito browser context.
*
* @remarks
* The default browser context cannot be closed.
*/
isIncognito(): boolean;
/**
* @example
* ```js
* const context = browser.defaultBrowserContext();
* await context.overridePermissions('https://html5demos.com', ['geolocation']);
* ```
*
* @param origin - The origin to grant permissions to, e.g. "https://example.com".
* @param permissions - An array of permissions to grant.
* All permissions that are not listed here will be automatically denied.
*/
overridePermissions(origin: string, permissions: Permission[]): Promise<void>;
/**
* Clears all permission overrides for the browser context.
*
* @example
* ```js
* const context = browser.defaultBrowserContext();
* context.overridePermissions('https://example.com', ['clipboard-read']);
* // do stuff ..
* context.clearPermissionOverrides();
* ```
*/
clearPermissionOverrides(): Promise<void>;
/**
* Creates a new page in the browser context.
*/
newPage(): Promise<Page>;
/**
* The browser this browser context belongs to.
*/
browser(): Browser;
/**
* Closes the browser context. All the targets that belong to the browser context
* will be closed.
*
* @remarks
* Only incognito browser contexts can be closed.
*/
close(): Promise<void>;
}
//# sourceMappingURL=Browser.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Browser.d.ts","sourceRoot":"","sources":["../../../../src/common/Browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,UAAU,EAA2B,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;GAEG;AACH,oBAAY,oBAAoB,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE9D;;GAEG;AACH,oBAAY,oBAAoB,GAAG,CACjC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,KAC/B,OAAO,CAAC;AA4Bb;;GAEG;AACH,oBAAY,UAAU,GAClB,aAAa,GACb,MAAM,GACN,eAAe,GACf,QAAQ,GACR,YAAY,GACZ,iBAAiB,GACjB,sBAAsB,GACtB,eAAe,GACf,WAAW,GACX,cAAc,GACd,sBAAsB,GACtB,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,oBAAoB,GACpB,gBAAgB,GAChB,YAAY,CAAC;AAEjB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,0BAAkB,oBAAoB;IACpC;;;;;;;OAOG;IACH,YAAY,iBAAiB;IAE7B;;;;;;OAMG;IACH,aAAa,kBAAkB;IAE/B;;;;;;;;;;OAUG;IACH,aAAa,kBAAkB;IAC/B;;;;;;;OAOG;IACH,eAAe,oBAAoB;CACpC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,qBAAa,OAAQ,SAAQ,YAAY;IACvC;;OAEG;WACU,MAAM,CACjB,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,MAAM,EAAE,EACpB,iBAAiB,EAAE,OAAO,EAC1B,eAAe,CAAC,EAAE,QAAQ,GAAG,IAAI,EACjC,OAAO,CAAC,EAAE,YAAY,EACtB,aAAa,CAAC,EAAE,oBAAoB,EACpC,oBAAoB,CAAC,EAAE,oBAAoB,GAC1C,OAAO,CAAC,OAAO,CAAC;IAanB,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,gBAAgB,CAAC,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,CAAe;IAChC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,eAAe,CAAiB;IACxC,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,oBAAoB,CAAY;IACxC,OAAO,CAAC,eAAe,CAAqB;IAC5C;;;OAGG;IACH,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE9B;;OAEG;gBAED,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,MAAM,EAAE,EACpB,iBAAiB,EAAE,OAAO,EAC1B,eAAe,CAAC,EAAE,QAAQ,GAAG,IAAI,EACjC,OAAO,CAAC,EAAE,YAAY,EACtB,aAAa,CAAC,EAAE,oBAAoB,EACpC,oBAAoB,CAAC,EAAE,oBAAoB;IAkC7C;;;OAGG;IACH,OAAO,IAAI,YAAY,GAAG,IAAI;IAI9B;;;;;;;;;;;;;;;;OAgBG;IACG,6BAA6B,CACjC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,cAAc,CAAC;IAmB1B;;;OAGG;IACH,eAAe,IAAI,cAAc,EAAE;IAInC;;OAEG;IACH,qBAAqB,IAAI,cAAc;IAIvC;;;OAGG;IACG,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAU1C,cAAc;YAwCd,gBAAgB;IAmB9B,OAAO,CAAC,kBAAkB;IAqB1B;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,IAAI,MAAM;IAIpB;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B;;;OAGG;IACG,oBAAoB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB7D;;;OAGG;IACH,OAAO,IAAI,MAAM,EAAE;IAMnB;;OAEG;IACH,MAAM,IAAI,MAAM;IAUhB;;;;;;;;;;;;;OAaG;IACG,aAAa,CACjB,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EACpD,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC;IAiClB;;;;;;;;OAQG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAQ9B;;;;;;;;;OASG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAKhC;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAKlC;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B;;;;OAIG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB,OAAO,CAAC,WAAW;CAGpB;AACD;;GAEG;AACH,0BAAkB,2BAA2B;IAC3C;;;OAGG;IACH,aAAa,kBAAkB;IAE/B;;;;;;;OAOG;IACH,aAAa,kBAAkB;IAC/B;;;OAGG;IACH,eAAe,oBAAoB;CACpC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,GAAG,CAAC,CAAS;IAErB;;OAEG;gBACS,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM;IAOxE;;OAEG;IACH,OAAO,IAAI,MAAM,EAAE;IAMnB;;;;;;;;;;;;;;;;OAgBG;IACH,aAAa,CACX,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EACpD,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GACjC,OAAO,CAAC,MAAM,CAAC;IAOlB;;;;;;OAMG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAS9B;;;;;;OAMG;IACH,WAAW,IAAI,OAAO;IAItB;;;;;;;;;;OAUG;IACG,mBAAmB,CACvB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,UAAU,EAAE,GACxB,OAAO,CAAC,IAAI,CAAC;IAehB;;;;;;;;;;OAUG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/C;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;;;;;OAMG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}

View File

@@ -0,0 +1,574 @@
"use strict";
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BrowserContext = exports.Browser = void 0;
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("./helper.js");
const Target_js_1 = require("./Target.js");
const EventEmitter_js_1 = require("./EventEmitter.js");
const Connection_js_1 = require("./Connection.js");
const TaskQueue_js_1 = require("./TaskQueue.js");
const WEB_PERMISSION_TO_PROTOCOL_PERMISSION = new Map([
['geolocation', 'geolocation'],
['midi', 'midi'],
['notifications', 'notifications'],
// TODO: push isn't a valid type?
// ['push', 'push'],
['camera', 'videoCapture'],
['microphone', 'audioCapture'],
['background-sync', 'backgroundSync'],
['ambient-light-sensor', 'sensors'],
['accelerometer', 'sensors'],
['gyroscope', 'sensors'],
['magnetometer', 'sensors'],
['accessibility-events', 'accessibilityEvents'],
['clipboard-read', 'clipboardReadWrite'],
['clipboard-write', 'clipboardReadWrite'],
['payment-handler', 'paymentHandler'],
['persistent-storage', 'durableStorage'],
['idle-detection', 'idleDetection'],
// chrome-specific permissions we have.
['midi-sysex', 'midiSysex'],
]);
/**
* A Browser is created when Puppeteer connects to a Chromium instance, either through
* {@link PuppeteerNode.launch} or {@link Puppeteer.connect}.
*
* @remarks
*
* The Browser class extends from Puppeteer's {@link EventEmitter} class and will
* emit various events which are documented in the {@link BrowserEmittedEvents} enum.
*
* @example
*
* An example of using a {@link Browser} to create a {@link Page}:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://example.com');
* await browser.close();
* })();
* ```
*
* @example
*
* An example of disconnecting from and reconnecting to a {@link Browser}:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* // Store the endpoint to be able to reconnect to Chromium
* const browserWSEndpoint = browser.wsEndpoint();
* // Disconnect puppeteer from Chromium
* browser.disconnect();
*
* // Use the endpoint to reestablish a connection
* const browser2 = await puppeteer.connect({browserWSEndpoint});
* // Close Chromium
* await browser2.close();
* })();
* ```
*
* @public
*/
class Browser extends EventEmitter_js_1.EventEmitter {
/**
* @internal
*/
constructor(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback, targetFilterCallback) {
super();
this._ignoredTargets = new Set();
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
this._defaultViewport = defaultViewport;
this._process = process;
this._screenshotTaskQueue = new TaskQueue_js_1.TaskQueue();
this._connection = connection;
this._closeCallback = closeCallback || function () { };
this._targetFilterCallback = targetFilterCallback || (() => true);
this._defaultContext = new BrowserContext(this._connection, this);
this._contexts = new Map();
for (const contextId of contextIds)
this._contexts.set(contextId, new BrowserContext(this._connection, this, contextId));
this._targets = new Map();
this._connection.on(Connection_js_1.ConnectionEmittedEvents.Disconnected, () => this.emit("disconnected" /* Disconnected */));
this._connection.on('Target.targetCreated', this._targetCreated.bind(this));
this._connection.on('Target.targetDestroyed', this._targetDestroyed.bind(this));
this._connection.on('Target.targetInfoChanged', this._targetInfoChanged.bind(this));
}
/**
* @internal
*/
static async create(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback, targetFilterCallback) {
const browser = new Browser(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback, targetFilterCallback);
await connection.send('Target.setDiscoverTargets', { discover: true });
return browser;
}
/**
* The spawned browser process. Returns `null` if the browser instance was created with
* {@link Puppeteer.connect}.
*/
process() {
var _a;
return (_a = this._process) !== null && _a !== void 0 ? _a : null;
}
/**
* Creates a new incognito browser context. This won't share cookies/cache with other
* browser contexts.
*
* @example
* ```js
* (async () => {
* const browser = await puppeteer.launch();
* // Create a new incognito browser context.
* const context = await browser.createIncognitoBrowserContext();
* // Create a new page in a pristine context.
* const page = await context.newPage();
* // Do stuff
* await page.goto('https://example.com');
* })();
* ```
*/
async createIncognitoBrowserContext(options = {}) {
const { proxyServer, proxyBypassList } = options;
const { browserContextId } = await this._connection.send('Target.createBrowserContext', {
proxyServer,
proxyBypassList: proxyBypassList && proxyBypassList.join(','),
});
const context = new BrowserContext(this._connection, this, browserContextId);
this._contexts.set(browserContextId, context);
return context;
}
/**
* Returns an array of all open browser contexts. In a newly created browser, this will
* return a single instance of {@link BrowserContext}.
*/
browserContexts() {
return [this._defaultContext, ...Array.from(this._contexts.values())];
}
/**
* Returns the default browser context. The default browser context cannot be closed.
*/
defaultBrowserContext() {
return this._defaultContext;
}
/**
* @internal
* Used by BrowserContext directly so cannot be marked private.
*/
async _disposeContext(contextId) {
if (!contextId) {
return;
}
await this._connection.send('Target.disposeBrowserContext', {
browserContextId: contextId,
});
this._contexts.delete(contextId);
}
async _targetCreated(event) {
var _a;
const targetInfo = event.targetInfo;
const { browserContextId } = targetInfo;
const context = browserContextId && this._contexts.has(browserContextId)
? this._contexts.get(browserContextId)
: this._defaultContext;
if (!context) {
throw new Error('Missing browser context');
}
const shouldAttachToTarget = this._targetFilterCallback(targetInfo);
if (!shouldAttachToTarget) {
this._ignoredTargets.add(targetInfo.targetId);
return;
}
const target = new Target_js_1.Target(targetInfo, context, () => this._connection.createSession(targetInfo), this._ignoreHTTPSErrors, (_a = this._defaultViewport) !== null && _a !== void 0 ? _a : null, this._screenshotTaskQueue);
(0, assert_js_1.assert)(!this._targets.has(event.targetInfo.targetId), 'Target should not exist before targetCreated');
this._targets.set(event.targetInfo.targetId, target);
if (await target._initializedPromise) {
this.emit("targetcreated" /* TargetCreated */, target);
context.emit("targetcreated" /* TargetCreated */, target);
}
}
async _targetDestroyed(event) {
if (this._ignoredTargets.has(event.targetId))
return;
const target = this._targets.get(event.targetId);
if (!target) {
throw new Error(`Missing target in _targetDestroyed (id = ${event.targetId})`);
}
target._initializedCallback(false);
this._targets.delete(event.targetId);
target._closedCallback();
if (await target._initializedPromise) {
this.emit("targetdestroyed" /* TargetDestroyed */, target);
target
.browserContext()
.emit("targetdestroyed" /* TargetDestroyed */, target);
}
}
_targetInfoChanged(event) {
if (this._ignoredTargets.has(event.targetInfo.targetId))
return;
const target = this._targets.get(event.targetInfo.targetId);
if (!target) {
throw new Error(`Missing target in targetInfoChanged (id = ${event.targetInfo.targetId})`);
}
const previousURL = target.url();
const wasInitialized = target._isInitialized;
target._targetInfoChanged(event.targetInfo);
if (wasInitialized && previousURL !== target.url()) {
this.emit("targetchanged" /* TargetChanged */, target);
target
.browserContext()
.emit("targetchanged" /* TargetChanged */, target);
}
}
/**
* The browser websocket endpoint which can be used as an argument to
* {@link Puppeteer.connect}.
*
* @returns The Browser websocket url.
*
* @remarks
*
* The format is `ws://${host}:${port}/devtools/browser/<id>`.
*
* You can find the `webSocketDebuggerUrl` from `http://${host}:${port}/json/version`.
* Learn more about the
* {@link https://chromedevtools.github.io/devtools-protocol | devtools protocol} and
* the {@link
* https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target
* | browser endpoint}.
*/
wsEndpoint() {
return this._connection.url();
}
/**
* Promise which resolves to a new {@link Page} object. The Page is created in
* a default browser context.
*/
async newPage() {
return this._defaultContext.newPage();
}
/**
* @internal
* Used by BrowserContext directly so cannot be marked private.
*/
async _createPageInContext(contextId) {
const { targetId } = await this._connection.send('Target.createTarget', {
url: 'about:blank',
browserContextId: contextId || undefined,
});
const target = this._targets.get(targetId);
if (!target) {
throw new Error(`Missing target for page (id = ${targetId})`);
}
const initialized = await target._initializedPromise;
if (!initialized) {
throw new Error(`Failed to create target for page (id = ${targetId})`);
}
const page = await target.page();
if (!page) {
throw new Error(`Failed to create a page for context (id = ${contextId})`);
}
return page;
}
/**
* All active targets inside the Browser. In case of multiple browser contexts, returns
* an array with all the targets in all browser contexts.
*/
targets() {
return Array.from(this._targets.values()).filter((target) => target._isInitialized);
}
/**
* The target associated with the browser.
*/
target() {
const browserTarget = this.targets().find((target) => target.type() === 'browser');
if (!browserTarget) {
throw new Error('Browser target is not found');
}
return browserTarget;
}
/**
* Searches for a target in all browser contexts.
*
* @param predicate - A function to be run for every target.
* @returns The first target found that matches the `predicate` function.
*
* @example
*
* An example of finding a target for a page opened via `window.open`:
* ```js
* await page.evaluate(() => window.open('https://www.example.com/'));
* const newWindowTarget = await browser.waitForTarget(target => target.url() === 'https://www.example.com/');
* ```
*/
async waitForTarget(predicate, options = {}) {
const { timeout = 30000 } = options;
let resolve;
const targetPromise = new Promise((x) => (resolve = x));
this.on("targetcreated" /* TargetCreated */, check);
this.on("targetchanged" /* TargetChanged */, check);
try {
if (!timeout)
return await targetPromise;
return await helper_js_1.helper.waitWithTimeout(Promise.race([
targetPromise,
(async () => {
for (const target of this.targets()) {
if (await predicate(target)) {
return target;
}
}
await targetPromise;
})(),
]), 'target', timeout);
}
finally {
this.removeListener("targetcreated" /* TargetCreated */, check);
this.removeListener("targetchanged" /* TargetChanged */, check);
}
async function check(target) {
if (await predicate(target))
resolve(target);
}
}
/**
* An array of all open pages inside the Browser.
*
* @remarks
*
* In case of multiple browser contexts, returns an array with all the pages in all
* browser contexts. Non-visible pages, such as `"background_page"`, will not be listed
* here. You can find them using {@link Target.page}.
*/
async pages() {
const contextPages = await Promise.all(this.browserContexts().map((context) => context.pages()));
// Flatten array.
return contextPages.reduce((acc, x) => acc.concat(x), []);
}
/**
* A string representing the browser name and version.
*
* @remarks
*
* For headless Chromium, this is similar to `HeadlessChrome/61.0.3153.0`. For
* non-headless, this is similar to `Chrome/61.0.3153.0`.
*
* The format of browser.version() might change with future releases of Chromium.
*/
async version() {
const version = await this._getVersion();
return version.product;
}
/**
* The browser's original user agent. Pages can override the browser user agent with
* {@link Page.setUserAgent}.
*/
async userAgent() {
const version = await this._getVersion();
return version.userAgent;
}
/**
* Closes Chromium and all of its pages (if any were opened). The {@link Browser} object
* itself is considered to be disposed and cannot be used anymore.
*/
async close() {
await this._closeCallback.call(null);
this.disconnect();
}
/**
* Disconnects Puppeteer from the browser, but leaves the Chromium process running.
* After calling `disconnect`, the {@link Browser} object is considered disposed and
* cannot be used anymore.
*/
disconnect() {
this._connection.dispose();
}
/**
* Indicates that the browser is connected.
*/
isConnected() {
return !this._connection._closed;
}
_getVersion() {
return this._connection.send('Browser.getVersion');
}
}
exports.Browser = Browser;
/**
* BrowserContexts provide a way to operate multiple independent browser
* sessions. When a browser is launched, it has a single BrowserContext used by
* default. The method {@link Browser.newPage | Browser.newPage} creates a page
* in the default browser context.
*
* @remarks
*
* The Browser class extends from Puppeteer's {@link EventEmitter} class and
* will emit various events which are documented in the
* {@link BrowserContextEmittedEvents} enum.
*
* If a page opens another page, e.g. with a `window.open` call, the popup will
* belong to the parent page's browser context.
*
* Puppeteer allows creation of "incognito" browser contexts with
* {@link Browser.createIncognitoBrowserContext | Browser.createIncognitoBrowserContext}
* method. "Incognito" browser contexts don't write any browsing data to disk.
*
* @example
* ```js
* // Create a new incognito browser context
* const context = await browser.createIncognitoBrowserContext();
* // Create a new page inside context.
* const page = await context.newPage();
* // ... do stuff with page ...
* await page.goto('https://example.com');
* // Dispose context once it's no longer needed.
* await context.close();
* ```
* @public
*/
class BrowserContext extends EventEmitter_js_1.EventEmitter {
/**
* @internal
*/
constructor(connection, browser, contextId) {
super();
this._connection = connection;
this._browser = browser;
this._id = contextId;
}
/**
* An array of all active targets inside the browser context.
*/
targets() {
return this._browser
.targets()
.filter((target) => target.browserContext() === this);
}
/**
* This searches for a target in this specific browser context.
*
* @example
* An example of finding a target for a page opened via `window.open`:
* ```js
* await page.evaluate(() => window.open('https://www.example.com/'));
* const newWindowTarget = await browserContext.waitForTarget(target => target.url() === 'https://www.example.com/');
* ```
*
* @param predicate - A function to be run for every target
* @param options - An object of options. Accepts a timout,
* which is the maximum wait time in milliseconds.
* Pass `0` to disable the timeout. Defaults to 30 seconds.
* @returns Promise which resolves to the first target found
* that matches the `predicate` function.
*/
waitForTarget(predicate, options = {}) {
return this._browser.waitForTarget((target) => target.browserContext() === this && predicate(target), options);
}
/**
* An array of all pages inside the browser context.
*
* @returns Promise which resolves to an array of all open pages.
* Non visible pages, such as `"background_page"`, will not be listed here.
* You can find them using {@link Target.page | the target page}.
*/
async pages() {
const pages = await Promise.all(this.targets()
.filter((target) => target.type() === 'page')
.map((target) => target.page()));
return pages.filter((page) => !!page);
}
/**
* Returns whether BrowserContext is incognito.
* The default browser context is the only non-incognito browser context.
*
* @remarks
* The default browser context cannot be closed.
*/
isIncognito() {
return !!this._id;
}
/**
* @example
* ```js
* const context = browser.defaultBrowserContext();
* await context.overridePermissions('https://html5demos.com', ['geolocation']);
* ```
*
* @param origin - The origin to grant permissions to, e.g. "https://example.com".
* @param permissions - An array of permissions to grant.
* All permissions that are not listed here will be automatically denied.
*/
async overridePermissions(origin, permissions) {
const protocolPermissions = permissions.map((permission) => {
const protocolPermission = WEB_PERMISSION_TO_PROTOCOL_PERMISSION.get(permission);
if (!protocolPermission)
throw new Error('Unknown permission: ' + permission);
return protocolPermission;
});
await this._connection.send('Browser.grantPermissions', {
origin,
browserContextId: this._id || undefined,
permissions: protocolPermissions,
});
}
/**
* Clears all permission overrides for the browser context.
*
* @example
* ```js
* const context = browser.defaultBrowserContext();
* context.overridePermissions('https://example.com', ['clipboard-read']);
* // do stuff ..
* context.clearPermissionOverrides();
* ```
*/
async clearPermissionOverrides() {
await this._connection.send('Browser.resetPermissions', {
browserContextId: this._id || undefined,
});
}
/**
* Creates a new page in the browser context.
*/
newPage() {
return this._browser._createPageInContext(this._id);
}
/**
* The browser this browser context belongs to.
*/
browser() {
return this._browser;
}
/**
* Closes the browser context. All the targets that belong to the browser context
* will be closed.
*
* @remarks
* Only incognito browser contexts can be closed.
*/
async close() {
(0, assert_js_1.assert)(this._id, 'Non-incognito profiles cannot be closed!');
await this._browser._disposeContext(this._id);
}
}
exports.BrowserContext = BrowserContext;
//# sourceMappingURL=Browser.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,54 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ConnectionTransport } from './ConnectionTransport.js';
import { Browser, TargetFilterCallback } from './Browser.js';
import { Viewport } from './PuppeteerViewport.js';
/**
* Generic browser options that can be passed when launching any browser or when
* connecting to an existing browser instance.
* @public
*/
export interface BrowserConnectOptions {
/**
* Whether to ignore HTTPS errors during navigation.
* @defaultValue false
*/
ignoreHTTPSErrors?: boolean;
/**
* Sets the viewport for each page.
*/
defaultViewport?: Viewport | null;
/**
* Slows down Puppeteer operations by the specified amount of milliseconds to
* aid debugging.
*/
slowMo?: number;
/**
* Callback to decide if Puppeteer should connect to a given target or not.
*/
targetFilter?: TargetFilterCallback;
}
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect`.
* @internal
*/
export declare const connectToBrowser: (options: BrowserConnectOptions & {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
}) => Promise<Browser>;
//# sourceMappingURL=BrowserConnector.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserConnector.d.ts","sourceRoot":"","sources":["../../../../src/common/BrowserConnector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAI7D,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAIlD;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;OAEG;IACH,eAAe,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAClC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC;AASD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,YAClB,qBAAqB,GAAG;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC,KACA,QAAQ,OAAO,CA6CjB,CAAC"}

View File

@@ -0,0 +1,102 @@
"use strict";
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.connectToBrowser = void 0;
const Browser_js_1 = require("./Browser.js");
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("../common/helper.js");
const Connection_js_1 = require("./Connection.js");
const environment_js_1 = require("../environment.js");
const fetch_js_1 = require("./fetch.js");
const getWebSocketTransportClass = async () => {
return environment_js_1.isNode
? (await Promise.resolve().then(() => __importStar(require('../node/NodeWebSocketTransport.js')))).NodeWebSocketTransport
: (await Promise.resolve().then(() => __importStar(require('./BrowserWebSocketTransport.js'))))
.BrowserWebSocketTransport;
};
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect`.
* @internal
*/
const connectToBrowser = async (options) => {
const { browserWSEndpoint, browserURL, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, transport, slowMo = 0, targetFilter, } = options;
(0, assert_js_1.assert)(Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) ===
1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect');
let connection = null;
if (transport) {
connection = new Connection_js_1.Connection('', transport, slowMo);
}
else if (browserWSEndpoint) {
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport = await WebSocketClass.create(browserWSEndpoint);
connection = new Connection_js_1.Connection(browserWSEndpoint, connectionTransport, slowMo);
}
else if (browserURL) {
const connectionURL = await getWSEndpoint(browserURL);
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport = await WebSocketClass.create(connectionURL);
connection = new Connection_js_1.Connection(connectionURL, connectionTransport, slowMo);
}
const { browserContextIds } = await connection.send('Target.getBrowserContexts');
return Browser_js_1.Browser.create(connection, browserContextIds, ignoreHTTPSErrors, defaultViewport, null, () => connection.send('Browser.close').catch(helper_js_1.debugError), targetFilter);
};
exports.connectToBrowser = connectToBrowser;
async function getWSEndpoint(browserURL) {
const endpointURL = new URL('/json/version', browserURL);
const fetch = await (0, fetch_js_1.getFetch)();
try {
const result = await fetch(endpointURL.toString(), {
method: 'GET',
});
if (!result.ok) {
throw new Error(`HTTP ${result.statusText}`);
}
const data = await result.json();
return data.webSocketDebuggerUrl;
}
catch (error) {
error.message =
`Failed to fetch browser webSocket URL from ${endpointURL}: ` +
error.message;
throw error;
}
}
//# sourceMappingURL=BrowserConnector.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserConnector.js","sourceRoot":"","sources":["../../../../src/common/BrowserConnector.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,26 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ConnectionTransport } from './ConnectionTransport.js';
export declare class BrowserWebSocketTransport implements ConnectionTransport {
static create(url: string): Promise<BrowserWebSocketTransport>;
private _ws;
onmessage?: (message: string) => void;
onclose?: () => void;
constructor(ws: WebSocket);
send(message: string): void;
close(): void;
}
//# sourceMappingURL=BrowserWebSocketTransport.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserWebSocketTransport.d.ts","sourceRoot":"","sources":["../../../../src/common/BrowserWebSocketTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,yBAA0B,YAAW,mBAAmB;IACnE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAW9D,OAAO,CAAC,GAAG,CAAY;IACvB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;gBAET,EAAE,EAAE,SAAS;IAczB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI3B,KAAK,IAAI,IAAI;CAGd"}

View File

@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BrowserWebSocketTransport = void 0;
class BrowserWebSocketTransport {
constructor(ws) {
this._ws = ws;
this._ws.addEventListener('message', (event) => {
if (this.onmessage)
this.onmessage.call(null, event.data);
});
this._ws.addEventListener('close', () => {
if (this.onclose)
this.onclose.call(null);
});
// Silently ignore all errors - we don't know what to do with them.
this._ws.addEventListener('error', () => { });
this.onmessage = null;
this.onclose = null;
}
static create(url) {
return new Promise((resolve, reject) => {
const ws = new WebSocket(url);
ws.addEventListener('open', () => resolve(new BrowserWebSocketTransport(ws)));
ws.addEventListener('error', reject);
});
}
send(message) {
this._ws.send(message);
}
close() {
this._ws.close();
}
}
exports.BrowserWebSocketTransport = BrowserWebSocketTransport;
//# sourceMappingURL=BrowserWebSocketTransport.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserWebSocketTransport.js","sourceRoot":"","sources":["../../../../src/common/BrowserWebSocketTransport.ts"],"names":[],"mappings":";;;AAiBA,MAAa,yBAAyB;IAgBpC,YAAY,EAAa;QACvB,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACd,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YAC7C,IAAI,IAAI,CAAC,SAAS;gBAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACtC,IAAI,IAAI,CAAC,OAAO;gBAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QACH,mEAAmE;QACnE,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IA3BD,MAAM,CAAC,MAAM,CAAC,GAAW;QACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;YAE9B,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,CAC/B,OAAO,CAAC,IAAI,yBAAyB,CAAC,EAAE,CAAC,CAAC,CAC3C,CAAC;YACF,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC;IAoBD,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;CACF;AArCD,8DAqCC"}

View File

@@ -0,0 +1,136 @@
import { Protocol } from 'devtools-protocol';
import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';
import { ConnectionTransport } from './ConnectionTransport.js';
import { EventEmitter } from './EventEmitter.js';
import { ProtocolError } from './Errors.js';
/**
* @public
*/
export { ConnectionTransport, ProtocolMapping };
/**
* @public
*/
export interface ConnectionCallback {
resolve: Function;
reject: Function;
error: ProtocolError;
method: string;
}
/**
* Internal events that the Connection class emits.
*
* @internal
*/
export declare const ConnectionEmittedEvents: {
readonly Disconnected: symbol;
};
/**
* @public
*/
export declare class Connection extends EventEmitter {
_url: string;
_transport: ConnectionTransport;
_delay: number;
_lastId: number;
_sessions: Map<string, CDPSession>;
_closed: boolean;
_callbacks: Map<number, ConnectionCallback>;
constructor(url: string, transport: ConnectionTransport, delay?: number);
static fromSession(session: CDPSession): Connection | undefined;
/**
* @param sessionId - The session id
* @returns The current CDP session if it exists
*/
session(sessionId: string): CDPSession | null;
url(): string;
send<T extends keyof ProtocolMapping.Commands>(method: T, ...paramArgs: ProtocolMapping.Commands[T]['paramsType']): Promise<ProtocolMapping.Commands[T]['returnType']>;
_rawSend(message: Record<string, unknown>): number;
_onMessage(message: string): Promise<void>;
_onClose(): void;
dispose(): void;
/**
* @param targetInfo - The target info
* @returns The CDP session that is created
*/
createSession(targetInfo: Protocol.Target.TargetInfo): Promise<CDPSession>;
}
/**
* @public
*/
export interface CDPSessionOnMessageObject {
id?: number;
method: string;
params: Record<string, unknown>;
error: {
message: string;
data: any;
code: number;
};
result?: any;
}
/**
* Internal events that the CDPSession class emits.
*
* @internal
*/
export declare const CDPSessionEmittedEvents: {
readonly Disconnected: symbol;
};
/**
* The `CDPSession` instances are used to talk raw Chrome Devtools Protocol.
*
* @remarks
*
* Protocol methods can be called with {@link CDPSession.send} method and protocol
* events can be subscribed to with `CDPSession.on` method.
*
* Useful links: {@link https://chromedevtools.github.io/devtools-protocol/ | DevTools Protocol Viewer}
* and {@link https://github.com/aslushnikov/getting-started-with-cdp/blob/HEAD/README.md | Getting Started with DevTools Protocol}.
*
* @example
* ```js
* const client = await page.target().createCDPSession();
* await client.send('Animation.enable');
* client.on('Animation.animationCreated', () => console.log('Animation created!'));
* const response = await client.send('Animation.getPlaybackRate');
* console.log('playback rate is ' + response.playbackRate);
* await client.send('Animation.setPlaybackRate', {
* playbackRate: response.playbackRate / 2
* });
* ```
*
* @public
*/
export declare class CDPSession extends EventEmitter {
/**
* @internal
*/
_connection?: Connection;
private _sessionId;
private _targetType;
private _callbacks;
/**
* @internal
*/
constructor(connection: Connection, targetType: string, sessionId: string);
connection(): Connection | undefined;
send<T extends keyof ProtocolMapping.Commands>(method: T, ...paramArgs: ProtocolMapping.Commands[T]['paramsType']): Promise<ProtocolMapping.Commands[T]['returnType']>;
/**
* @internal
*/
_onMessage(object: CDPSessionOnMessageObject): void;
/**
* Detaches the cdpSession from the target. Once detached, the cdpSession object
* won't emit any events and can't be used to send messages.
*/
detach(): Promise<void>;
/**
* @internal
*/
_onClosed(): void;
/**
* @internal
*/
id(): string;
}
//# sourceMappingURL=Connection.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Connection.d.ts","sourceRoot":"","sources":["../../../../src/common/Connection.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,303 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CDPSession = exports.CDPSessionEmittedEvents = exports.Connection = exports.ConnectionEmittedEvents = void 0;
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/
const assert_js_1 = require("./assert.js");
const Debug_js_1 = require("./Debug.js");
const debugProtocolSend = (0, Debug_js_1.debug)('puppeteer:protocol:SEND ►');
const debugProtocolReceive = (0, Debug_js_1.debug)('puppeteer:protocol:RECV ◀');
const EventEmitter_js_1 = require("./EventEmitter.js");
const Errors_js_1 = require("./Errors.js");
/**
* Internal events that the Connection class emits.
*
* @internal
*/
exports.ConnectionEmittedEvents = {
Disconnected: Symbol('Connection.Disconnected'),
};
/**
* @public
*/
class Connection extends EventEmitter_js_1.EventEmitter {
constructor(url, transport, delay = 0) {
super();
this._lastId = 0;
this._sessions = new Map();
this._closed = false;
this._callbacks = new Map();
this._url = url;
this._delay = delay;
this._transport = transport;
this._transport.onmessage = this._onMessage.bind(this);
this._transport.onclose = this._onClose.bind(this);
}
static fromSession(session) {
return session._connection;
}
/**
* @param sessionId - The session id
* @returns The current CDP session if it exists
*/
session(sessionId) {
return this._sessions.get(sessionId) || null;
}
url() {
return this._url;
}
send(method, ...paramArgs) {
// There is only ever 1 param arg passed, but the Protocol defines it as an
// array of 0 or 1 items See this comment:
// https://github.com/ChromeDevTools/devtools-protocol/pull/113#issuecomment-412603285
// which explains why the protocol defines the params this way for better
// type-inference.
// So now we check if there are any params or not and deal with them accordingly.
const params = paramArgs.length ? paramArgs[0] : undefined;
const id = this._rawSend({ method, params });
return new Promise((resolve, reject) => {
this._callbacks.set(id, {
resolve,
reject,
error: new Errors_js_1.ProtocolError(),
method,
});
});
}
_rawSend(message) {
const id = ++this._lastId;
const stringifiedMessage = JSON.stringify(Object.assign({}, message, { id }));
debugProtocolSend(stringifiedMessage);
this._transport.send(stringifiedMessage);
return id;
}
async _onMessage(message) {
if (this._delay)
await new Promise((f) => setTimeout(f, this._delay));
debugProtocolReceive(message);
const object = JSON.parse(message);
if (object.method === 'Target.attachedToTarget') {
const sessionId = object.params.sessionId;
const session = new CDPSession(this, object.params.targetInfo.type, sessionId);
this._sessions.set(sessionId, session);
this.emit('sessionattached', session);
const parentSession = this._sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit('sessionattached', session);
}
}
else if (object.method === 'Target.detachedFromTarget') {
const session = this._sessions.get(object.params.sessionId);
if (session) {
session._onClosed();
this._sessions.delete(object.params.sessionId);
this.emit('sessiondetached', session);
const parentSession = this._sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit('sessiondetached', session);
}
}
}
if (object.sessionId) {
const session = this._sessions.get(object.sessionId);
if (session)
session._onMessage(object);
}
else if (object.id) {
const callback = this._callbacks.get(object.id);
// Callbacks could be all rejected if someone has called `.dispose()`.
if (callback) {
this._callbacks.delete(object.id);
if (object.error)
callback.reject(createProtocolError(callback.error, callback.method, object));
else
callback.resolve(object.result);
}
}
else {
this.emit(object.method, object.params);
}
}
_onClose() {
if (this._closed)
return;
this._closed = true;
this._transport.onmessage = undefined;
this._transport.onclose = undefined;
for (const callback of this._callbacks.values())
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
this._callbacks.clear();
for (const session of this._sessions.values())
session._onClosed();
this._sessions.clear();
this.emit(exports.ConnectionEmittedEvents.Disconnected);
}
dispose() {
this._onClose();
this._transport.close();
}
/**
* @param targetInfo - The target info
* @returns The CDP session that is created
*/
async createSession(targetInfo) {
const { sessionId } = await this.send('Target.attachToTarget', {
targetId: targetInfo.targetId,
flatten: true,
});
const session = this._sessions.get(sessionId);
if (!session) {
throw new Error('CDPSession creation failed.');
}
return session;
}
}
exports.Connection = Connection;
/**
* Internal events that the CDPSession class emits.
*
* @internal
*/
exports.CDPSessionEmittedEvents = {
Disconnected: Symbol('CDPSession.Disconnected'),
};
/**
* The `CDPSession` instances are used to talk raw Chrome Devtools Protocol.
*
* @remarks
*
* Protocol methods can be called with {@link CDPSession.send} method and protocol
* events can be subscribed to with `CDPSession.on` method.
*
* Useful links: {@link https://chromedevtools.github.io/devtools-protocol/ | DevTools Protocol Viewer}
* and {@link https://github.com/aslushnikov/getting-started-with-cdp/blob/HEAD/README.md | Getting Started with DevTools Protocol}.
*
* @example
* ```js
* const client = await page.target().createCDPSession();
* await client.send('Animation.enable');
* client.on('Animation.animationCreated', () => console.log('Animation created!'));
* const response = await client.send('Animation.getPlaybackRate');
* console.log('playback rate is ' + response.playbackRate);
* await client.send('Animation.setPlaybackRate', {
* playbackRate: response.playbackRate / 2
* });
* ```
*
* @public
*/
class CDPSession extends EventEmitter_js_1.EventEmitter {
/**
* @internal
*/
constructor(connection, targetType, sessionId) {
super();
this._callbacks = new Map();
this._connection = connection;
this._targetType = targetType;
this._sessionId = sessionId;
}
connection() {
return this._connection;
}
send(method, ...paramArgs) {
if (!this._connection)
return Promise.reject(new Error(`Protocol error (${method}): Session closed. Most likely the ${this._targetType} has been closed.`));
// See the comment in Connection#send explaining why we do this.
const params = paramArgs.length ? paramArgs[0] : undefined;
const id = this._connection._rawSend({
sessionId: this._sessionId,
method,
params,
});
return new Promise((resolve, reject) => {
this._callbacks.set(id, {
resolve,
reject,
error: new Errors_js_1.ProtocolError(),
method,
});
});
}
/**
* @internal
*/
_onMessage(object) {
const callback = object.id ? this._callbacks.get(object.id) : undefined;
if (object.id && callback) {
this._callbacks.delete(object.id);
if (object.error)
callback.reject(createProtocolError(callback.error, callback.method, object));
else
callback.resolve(object.result);
}
else {
(0, assert_js_1.assert)(!object.id);
this.emit(object.method, object.params);
}
}
/**
* Detaches the cdpSession from the target. Once detached, the cdpSession object
* won't emit any events and can't be used to send messages.
*/
async detach() {
if (!this._connection)
throw new Error(`Session already detached. Most likely the ${this._targetType} has been closed.`);
await this._connection.send('Target.detachFromTarget', {
sessionId: this._sessionId,
});
}
/**
* @internal
*/
_onClosed() {
for (const callback of this._callbacks.values())
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
this._callbacks.clear();
this._connection = undefined;
this.emit(exports.CDPSessionEmittedEvents.Disconnected);
}
/**
* @internal
*/
id() {
return this._sessionId;
}
}
exports.CDPSession = CDPSession;
/**
* @param {!Error} error
* @param {string} method
* @param {{error: {message: string, data: any}}} object
* @returns {!Error}
*/
function createProtocolError(error, method, object) {
let message = `Protocol error (${method}): ${object.error.message}`;
if ('data' in object.error)
message += ` ${object.error.data}`;
return rewriteError(error, message, object.error.message);
}
/**
* @param {!Error} error
* @param {string} message
* @returns {!Error}
*/
function rewriteError(error, message, originalMessage) {
error.message = message;
error.originalMessage = originalMessage !== null && originalMessage !== void 0 ? originalMessage : error.originalMessage;
return error;
}
//# sourceMappingURL=Connection.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,25 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
/**
* @public
*/
export interface ConnectionTransport {
send(message: string): void;
close(): void;
onmessage?: (message: string) => void;
onclose?: () => void;
}
//# sourceMappingURL=ConnectionTransport.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ConnectionTransport.d.ts","sourceRoot":"","sources":["../../../../src/common/ConnectionTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,IAAI,IAAI,CAAC;IACd,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB"}

View File

@@ -0,0 +1,18 @@
"use strict";
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=ConnectionTransport.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ConnectionTransport.js","sourceRoot":"","sources":["../../../../src/common/ConnectionTransport.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG"}

View File

@@ -0,0 +1,73 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { JSHandle } from './JSHandle.js';
/**
* @public
*/
export interface ConsoleMessageLocation {
/**
* URL of the resource if known or `undefined` otherwise.
*/
url?: string;
/**
* 0-based line number in the resource if known or `undefined` otherwise.
*/
lineNumber?: number;
/**
* 0-based column number in the resource if known or `undefined` otherwise.
*/
columnNumber?: number;
}
/**
* The supported types for console messages.
* @public
*/
export declare type ConsoleMessageType = 'log' | 'debug' | 'info' | 'error' | 'warning' | 'dir' | 'dirxml' | 'table' | 'trace' | 'clear' | 'startGroup' | 'startGroupCollapsed' | 'endGroup' | 'assert' | 'profile' | 'profileEnd' | 'count' | 'timeEnd' | 'verbose';
/**
* ConsoleMessage objects are dispatched by page via the 'console' event.
* @public
*/
export declare class ConsoleMessage {
private _type;
private _text;
private _args;
private _stackTraceLocations;
/**
* @public
*/
constructor(type: ConsoleMessageType, text: string, args: JSHandle[], stackTraceLocations: ConsoleMessageLocation[]);
/**
* @returns The type of the console message.
*/
type(): ConsoleMessageType;
/**
* @returns The text of the console message.
*/
text(): string;
/**
* @returns An array of arguments passed to the console.
*/
args(): JSHandle[];
/**
* @returns The location of the console message.
*/
location(): ConsoleMessageLocation;
/**
* @returns The array of locations on the stack of the console message.
*/
stackTrace(): ConsoleMessageLocation[];
}
//# sourceMappingURL=ConsoleMessage.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ConsoleMessage.d.ts","sourceRoot":"","sources":["../../../../src/common/ConsoleMessage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,oBAAY,kBAAkB,GAC1B,KAAK,GACL,OAAO,GACP,MAAM,GACN,OAAO,GACP,SAAS,GACT,KAAK,GACL,QAAQ,GACR,OAAO,GACP,OAAO,GACP,OAAO,GACP,YAAY,GACZ,qBAAqB,GACrB,UAAU,GACV,QAAQ,GACR,SAAS,GACT,YAAY,GACZ,OAAO,GACP,SAAS,GACT,SAAS,CAAC;AAEd;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,oBAAoB,CAA2B;IAEvD;;OAEG;gBAED,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,EAAE,EAChB,mBAAmB,EAAE,sBAAsB,EAAE;IAQ/C;;OAEG;IACH,IAAI,IAAI,kBAAkB;IAI1B;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,IAAI,IAAI,QAAQ,EAAE;IAIlB;;OAEG;IACH,QAAQ,IAAI,sBAAsB;IAIlC;;OAEG;IACH,UAAU,IAAI,sBAAsB,EAAE;CAGvC"}

View File

@@ -0,0 +1,65 @@
"use strict";
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConsoleMessage = void 0;
/**
* ConsoleMessage objects are dispatched by page via the 'console' event.
* @public
*/
class ConsoleMessage {
/**
* @public
*/
constructor(type, text, args, stackTraceLocations) {
this._type = type;
this._text = text;
this._args = args;
this._stackTraceLocations = stackTraceLocations;
}
/**
* @returns The type of the console message.
*/
type() {
return this._type;
}
/**
* @returns The text of the console message.
*/
text() {
return this._text;
}
/**
* @returns An array of arguments passed to the console.
*/
args() {
return this._args;
}
/**
* @returns The location of the console message.
*/
location() {
return this._stackTraceLocations.length ? this._stackTraceLocations[0] : {};
}
/**
* @returns The array of locations on the stack of the console message.
*/
stackTrace() {
return this._stackTraceLocations;
}
}
exports.ConsoleMessage = ConsoleMessage;
//# sourceMappingURL=ConsoleMessage.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ConsoleMessage.js","sourceRoot":"","sources":["../../../../src/common/ConsoleMessage.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAiDH;;;GAGG;AACH,MAAa,cAAc;IAMzB;;OAEG;IACH,YACE,IAAwB,EACxB,IAAY,EACZ,IAAgB,EAChB,mBAA6C;QAE7C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,oBAAoB,CAAC;IACnC,CAAC;CACF;AAvDD,wCAuDC"}

View File

@@ -0,0 +1,205 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { PuppeteerEventListener } from './helper.js';
import { Protocol } from 'devtools-protocol';
import { CDPSession } from './Connection.js';
/**
* @internal
*/
export { PuppeteerEventListener };
/**
* The CoverageEntry class represents one entry of the coverage report.
* @public
*/
export interface CoverageEntry {
/**
* The URL of the style sheet or script.
*/
url: string;
/**
* The content of the style sheet or script.
*/
text: string;
/**
* The covered range as start and end positions.
*/
ranges: Array<{
start: number;
end: number;
}>;
}
/**
* The CoverageEntry class for JavaScript
* @public
*/
export interface JSCoverageEntry extends CoverageEntry {
/**
* Raw V8 script coverage entry.
*/
rawScriptCoverage?: Protocol.Profiler.ScriptCoverage;
}
/**
* Set of configurable options for JS coverage.
* @public
*/
export interface JSCoverageOptions {
/**
* Whether to reset coverage on every navigation.
*/
resetOnNavigation?: boolean;
/**
* Whether anonymous scripts generated by the page should be reported.
*/
reportAnonymousScripts?: boolean;
/**
* Whether the result includes raw V8 script coverage entries.
*/
includeRawScriptCoverage?: boolean;
}
/**
* Set of configurable options for CSS coverage.
* @public
*/
export interface CSSCoverageOptions {
/**
* Whether to reset coverage on every navigation.
*/
resetOnNavigation?: boolean;
}
/**
* The Coverage class provides methods to gathers information about parts of
* JavaScript and CSS that were used by the page.
*
* @remarks
* To output coverage in a form consumable by {@link https://github.com/istanbuljs | Istanbul},
* see {@link https://github.com/istanbuljs/puppeteer-to-istanbul | puppeteer-to-istanbul}.
*
* @example
* An example of using JavaScript and CSS coverage to get percentage of initially
* executed code:
* ```js
* // Enable both JavaScript and CSS coverage
* await Promise.all([
* page.coverage.startJSCoverage(),
* page.coverage.startCSSCoverage()
* ]);
* // Navigate to page
* await page.goto('https://example.com');
* // Disable both JavaScript and CSS coverage
* const [jsCoverage, cssCoverage] = await Promise.all([
* page.coverage.stopJSCoverage(),
* page.coverage.stopCSSCoverage(),
* ]);
* let totalBytes = 0;
* let usedBytes = 0;
* const coverage = [...jsCoverage, ...cssCoverage];
* for (const entry of coverage) {
* totalBytes += entry.text.length;
* for (const range of entry.ranges)
* usedBytes += range.end - range.start - 1;
* }
* console.log(`Bytes used: ${usedBytes / totalBytes * 100}%`);
* ```
* @public
*/
export declare class Coverage {
/**
* @internal
*/
_jsCoverage: JSCoverage;
/**
* @internal
*/
_cssCoverage: CSSCoverage;
constructor(client: CDPSession);
/**
* @param options - Set of configurable options for coverage defaults to
* `resetOnNavigation : true, reportAnonymousScripts : false`
* @returns Promise that resolves when coverage is started.
*
* @remarks
* Anonymous scripts are ones that don't have an associated url. These are
* scripts that are dynamically created on the page using `eval` or
* `new Function`. If `reportAnonymousScripts` is set to `true`, anonymous
* scripts will have `__puppeteer_evaluation_script__` as their URL.
*/
startJSCoverage(options?: JSCoverageOptions): Promise<void>;
/**
* @returns Promise that resolves to the array of coverage reports for
* all scripts.
*
* @remarks
* JavaScript Coverage doesn't include anonymous scripts by default.
* However, scripts with sourceURLs are reported.
*/
stopJSCoverage(): Promise<JSCoverageEntry[]>;
/**
* @param options - Set of configurable options for coverage, defaults to
* `resetOnNavigation : true`
* @returns Promise that resolves when coverage is started.
*/
startCSSCoverage(options?: CSSCoverageOptions): Promise<void>;
/**
* @returns Promise that resolves to the array of coverage reports
* for all stylesheets.
* @remarks
* CSS Coverage doesn't include dynamically injected style tags
* without sourceURLs.
*/
stopCSSCoverage(): Promise<CoverageEntry[]>;
}
/**
* @public
*/
export declare class JSCoverage {
_client: CDPSession;
_enabled: boolean;
_scriptURLs: Map<string, string>;
_scriptSources: Map<string, string>;
_eventListeners: PuppeteerEventListener[];
_resetOnNavigation: boolean;
_reportAnonymousScripts: boolean;
_includeRawScriptCoverage: boolean;
constructor(client: CDPSession);
start(options?: {
resetOnNavigation?: boolean;
reportAnonymousScripts?: boolean;
includeRawScriptCoverage?: boolean;
}): Promise<void>;
_onExecutionContextsCleared(): void;
_onScriptParsed(event: Protocol.Debugger.ScriptParsedEvent): Promise<void>;
stop(): Promise<JSCoverageEntry[]>;
}
/**
* @public
*/
export declare class CSSCoverage {
_client: CDPSession;
_enabled: boolean;
_stylesheetURLs: Map<string, string>;
_stylesheetSources: Map<string, string>;
_eventListeners: PuppeteerEventListener[];
_resetOnNavigation: boolean;
_reportAnonymousScripts: boolean;
constructor(client: CDPSession);
start(options?: {
resetOnNavigation?: boolean;
}): Promise<void>;
_onExecutionContextsCleared(): void;
_onStyleSheet(event: Protocol.CSS.StyleSheetAddedEvent): Promise<void>;
stop(): Promise<CoverageEntry[]>;
}
//# sourceMappingURL=Coverage.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Coverage.d.ts","sourceRoot":"","sources":["../../../../src/common/Coverage.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,336 @@
"use strict";
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.CSSCoverage = exports.JSCoverage = exports.Coverage = void 0;
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("./helper.js");
const ExecutionContext_js_1 = require("./ExecutionContext.js");
/**
* The Coverage class provides methods to gathers information about parts of
* JavaScript and CSS that were used by the page.
*
* @remarks
* To output coverage in a form consumable by {@link https://github.com/istanbuljs | Istanbul},
* see {@link https://github.com/istanbuljs/puppeteer-to-istanbul | puppeteer-to-istanbul}.
*
* @example
* An example of using JavaScript and CSS coverage to get percentage of initially
* executed code:
* ```js
* // Enable both JavaScript and CSS coverage
* await Promise.all([
* page.coverage.startJSCoverage(),
* page.coverage.startCSSCoverage()
* ]);
* // Navigate to page
* await page.goto('https://example.com');
* // Disable both JavaScript and CSS coverage
* const [jsCoverage, cssCoverage] = await Promise.all([
* page.coverage.stopJSCoverage(),
* page.coverage.stopCSSCoverage(),
* ]);
* let totalBytes = 0;
* let usedBytes = 0;
* const coverage = [...jsCoverage, ...cssCoverage];
* for (const entry of coverage) {
* totalBytes += entry.text.length;
* for (const range of entry.ranges)
* usedBytes += range.end - range.start - 1;
* }
* console.log(`Bytes used: ${usedBytes / totalBytes * 100}%`);
* ```
* @public
*/
class Coverage {
constructor(client) {
this._jsCoverage = new JSCoverage(client);
this._cssCoverage = new CSSCoverage(client);
}
/**
* @param options - Set of configurable options for coverage defaults to
* `resetOnNavigation : true, reportAnonymousScripts : false`
* @returns Promise that resolves when coverage is started.
*
* @remarks
* Anonymous scripts are ones that don't have an associated url. These are
* scripts that are dynamically created on the page using `eval` or
* `new Function`. If `reportAnonymousScripts` is set to `true`, anonymous
* scripts will have `__puppeteer_evaluation_script__` as their URL.
*/
async startJSCoverage(options = {}) {
return await this._jsCoverage.start(options);
}
/**
* @returns Promise that resolves to the array of coverage reports for
* all scripts.
*
* @remarks
* JavaScript Coverage doesn't include anonymous scripts by default.
* However, scripts with sourceURLs are reported.
*/
async stopJSCoverage() {
return await this._jsCoverage.stop();
}
/**
* @param options - Set of configurable options for coverage, defaults to
* `resetOnNavigation : true`
* @returns Promise that resolves when coverage is started.
*/
async startCSSCoverage(options = {}) {
return await this._cssCoverage.start(options);
}
/**
* @returns Promise that resolves to the array of coverage reports
* for all stylesheets.
* @remarks
* CSS Coverage doesn't include dynamically injected style tags
* without sourceURLs.
*/
async stopCSSCoverage() {
return await this._cssCoverage.stop();
}
}
exports.Coverage = Coverage;
/**
* @public
*/
class JSCoverage {
constructor(client) {
this._enabled = false;
this._scriptURLs = new Map();
this._scriptSources = new Map();
this._eventListeners = [];
this._resetOnNavigation = false;
this._reportAnonymousScripts = false;
this._includeRawScriptCoverage = false;
this._client = client;
}
async start(options = {}) {
(0, assert_js_1.assert)(!this._enabled, 'JSCoverage is already enabled');
const { resetOnNavigation = true, reportAnonymousScripts = false, includeRawScriptCoverage = false, } = options;
this._resetOnNavigation = resetOnNavigation;
this._reportAnonymousScripts = reportAnonymousScripts;
this._includeRawScriptCoverage = includeRawScriptCoverage;
this._enabled = true;
this._scriptURLs.clear();
this._scriptSources.clear();
this._eventListeners = [
helper_js_1.helper.addEventListener(this._client, 'Debugger.scriptParsed', this._onScriptParsed.bind(this)),
helper_js_1.helper.addEventListener(this._client, 'Runtime.executionContextsCleared', this._onExecutionContextsCleared.bind(this)),
];
await Promise.all([
this._client.send('Profiler.enable'),
this._client.send('Profiler.startPreciseCoverage', {
callCount: this._includeRawScriptCoverage,
detailed: true,
}),
this._client.send('Debugger.enable'),
this._client.send('Debugger.setSkipAllPauses', { skip: true }),
]);
}
_onExecutionContextsCleared() {
if (!this._resetOnNavigation)
return;
this._scriptURLs.clear();
this._scriptSources.clear();
}
async _onScriptParsed(event) {
// Ignore puppeteer-injected scripts
if (event.url === ExecutionContext_js_1.EVALUATION_SCRIPT_URL)
return;
// Ignore other anonymous scripts unless the reportAnonymousScripts option is true.
if (!event.url && !this._reportAnonymousScripts)
return;
try {
const response = await this._client.send('Debugger.getScriptSource', {
scriptId: event.scriptId,
});
this._scriptURLs.set(event.scriptId, event.url);
this._scriptSources.set(event.scriptId, response.scriptSource);
}
catch (error) {
// This might happen if the page has already navigated away.
(0, helper_js_1.debugError)(error);
}
}
async stop() {
(0, assert_js_1.assert)(this._enabled, 'JSCoverage is not enabled');
this._enabled = false;
const result = await Promise.all([
this._client.send('Profiler.takePreciseCoverage'),
this._client.send('Profiler.stopPreciseCoverage'),
this._client.send('Profiler.disable'),
this._client.send('Debugger.disable'),
]);
helper_js_1.helper.removeEventListeners(this._eventListeners);
const coverage = [];
const profileResponse = result[0];
for (const entry of profileResponse.result) {
let url = this._scriptURLs.get(entry.scriptId);
if (!url && this._reportAnonymousScripts)
url = 'debugger://VM' + entry.scriptId;
const text = this._scriptSources.get(entry.scriptId);
if (text === undefined || url === undefined)
continue;
const flattenRanges = [];
for (const func of entry.functions)
flattenRanges.push(...func.ranges);
const ranges = convertToDisjointRanges(flattenRanges);
if (!this._includeRawScriptCoverage) {
coverage.push({ url, ranges, text });
}
else {
coverage.push({ url, ranges, text, rawScriptCoverage: entry });
}
}
return coverage;
}
}
exports.JSCoverage = JSCoverage;
/**
* @public
*/
class CSSCoverage {
constructor(client) {
this._enabled = false;
this._stylesheetURLs = new Map();
this._stylesheetSources = new Map();
this._eventListeners = [];
this._resetOnNavigation = false;
this._reportAnonymousScripts = false;
this._client = client;
}
async start(options = {}) {
(0, assert_js_1.assert)(!this._enabled, 'CSSCoverage is already enabled');
const { resetOnNavigation = true } = options;
this._resetOnNavigation = resetOnNavigation;
this._enabled = true;
this._stylesheetURLs.clear();
this._stylesheetSources.clear();
this._eventListeners = [
helper_js_1.helper.addEventListener(this._client, 'CSS.styleSheetAdded', this._onStyleSheet.bind(this)),
helper_js_1.helper.addEventListener(this._client, 'Runtime.executionContextsCleared', this._onExecutionContextsCleared.bind(this)),
];
await Promise.all([
this._client.send('DOM.enable'),
this._client.send('CSS.enable'),
this._client.send('CSS.startRuleUsageTracking'),
]);
}
_onExecutionContextsCleared() {
if (!this._resetOnNavigation)
return;
this._stylesheetURLs.clear();
this._stylesheetSources.clear();
}
async _onStyleSheet(event) {
const header = event.header;
// Ignore anonymous scripts
if (!header.sourceURL)
return;
try {
const response = await this._client.send('CSS.getStyleSheetText', {
styleSheetId: header.styleSheetId,
});
this._stylesheetURLs.set(header.styleSheetId, header.sourceURL);
this._stylesheetSources.set(header.styleSheetId, response.text);
}
catch (error) {
// This might happen if the page has already navigated away.
(0, helper_js_1.debugError)(error);
}
}
async stop() {
(0, assert_js_1.assert)(this._enabled, 'CSSCoverage is not enabled');
this._enabled = false;
const ruleTrackingResponse = await this._client.send('CSS.stopRuleUsageTracking');
await Promise.all([
this._client.send('CSS.disable'),
this._client.send('DOM.disable'),
]);
helper_js_1.helper.removeEventListeners(this._eventListeners);
// aggregate by styleSheetId
const styleSheetIdToCoverage = new Map();
for (const entry of ruleTrackingResponse.ruleUsage) {
let ranges = styleSheetIdToCoverage.get(entry.styleSheetId);
if (!ranges) {
ranges = [];
styleSheetIdToCoverage.set(entry.styleSheetId, ranges);
}
ranges.push({
startOffset: entry.startOffset,
endOffset: entry.endOffset,
count: entry.used ? 1 : 0,
});
}
const coverage = [];
for (const styleSheetId of this._stylesheetURLs.keys()) {
const url = this._stylesheetURLs.get(styleSheetId);
const text = this._stylesheetSources.get(styleSheetId);
const ranges = convertToDisjointRanges(styleSheetIdToCoverage.get(styleSheetId) || []);
coverage.push({ url, ranges, text });
}
return coverage;
}
}
exports.CSSCoverage = CSSCoverage;
function convertToDisjointRanges(nestedRanges) {
const points = [];
for (const range of nestedRanges) {
points.push({ offset: range.startOffset, type: 0, range });
points.push({ offset: range.endOffset, type: 1, range });
}
// Sort points to form a valid parenthesis sequence.
points.sort((a, b) => {
// Sort with increasing offsets.
if (a.offset !== b.offset)
return a.offset - b.offset;
// All "end" points should go before "start" points.
if (a.type !== b.type)
return b.type - a.type;
const aLength = a.range.endOffset - a.range.startOffset;
const bLength = b.range.endOffset - b.range.startOffset;
// For two "start" points, the one with longer range goes first.
if (a.type === 0)
return bLength - aLength;
// For two "end" points, the one with shorter range goes first.
return aLength - bLength;
});
const hitCountStack = [];
const results = [];
let lastOffset = 0;
// Run scanning line to intersect all ranges.
for (const point of points) {
if (hitCountStack.length &&
lastOffset < point.offset &&
hitCountStack[hitCountStack.length - 1] > 0) {
const lastResult = results.length ? results[results.length - 1] : null;
if (lastResult && lastResult.end === lastOffset)
lastResult.end = point.offset;
else
results.push({ start: lastOffset, end: point.offset });
}
lastOffset = point.offset;
if (point.type === 0)
hitCountStack.push(point.range.count);
else
hitCountStack.pop();
}
// Filter out empty ranges.
return results.filter((range) => range.end - range.start > 1);
}
//# sourceMappingURL=Coverage.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,181 @@
/**
* Copyright 2019 Google Inc. All rights reserved.
*
* 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.
*/
/// <reference types="node" />
import { PuppeteerLifeCycleEvent } from './LifecycleWatcher.js';
import { JSHandle, ElementHandle } from './JSHandle.js';
import { ExecutionContext } from './ExecutionContext.js';
import { TimeoutSettings } from './TimeoutSettings.js';
import { MouseButton } from './Input.js';
import { FrameManager, Frame } from './FrameManager.js';
import { SerializableOrJSHandle, EvaluateHandleFn, WrapElementHandle, EvaluateFn, EvaluateFnReturnType, UnwrapPromiseLike } from './EvalTypes.js';
import { CDPSession } from './Connection.js';
/**
* @public
*/
export interface WaitForSelectorOptions {
visible?: boolean;
hidden?: boolean;
timeout?: number;
root?: ElementHandle;
}
/**
* @internal
*/
export interface PageBinding {
name: string;
pptrFunction: Function;
}
/**
* @internal
*/
export declare class DOMWorld {
private _frameManager;
private _client;
private _frame;
private _timeoutSettings;
private _documentPromise?;
private _contextPromise?;
private _contextResolveCallback?;
private _detached;
/**
* @internal
*/
_waitTasks: Set<WaitTask>;
/**
* @internal
* Contains mapping from functions that should be bound to Puppeteer functions.
*/
_boundFunctions: Map<string, Function>;
private _ctxBindings;
private static bindingIdentifier;
constructor(client: CDPSession, frameManager: FrameManager, frame: Frame, timeoutSettings: TimeoutSettings);
frame(): Frame;
_setContext(context?: ExecutionContext): Promise<void>;
_hasContext(): boolean;
_detach(): void;
executionContext(): Promise<ExecutionContext>;
evaluateHandle<HandlerType extends JSHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<HandlerType>;
evaluate<T extends EvaluateFn>(pageFunction: T, ...args: SerializableOrJSHandle[]): Promise<UnwrapPromiseLike<EvaluateFnReturnType<T>>>;
$<T extends Element = Element>(selector: string): Promise<ElementHandle<T> | null>;
_document(): Promise<ElementHandle>;
$x(expression: string): Promise<ElementHandle[]>;
$eval<ReturnType>(selector: string, pageFunction: (element: Element, ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
$$eval<ReturnType>(selector: string, pageFunction: (elements: Element[], ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
$$<T extends Element = Element>(selector: string): Promise<Array<ElementHandle<T>>>;
content(): Promise<string>;
setContent(html: string, options?: {
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<void>;
/**
* Adds a script tag into the current context.
*
* @remarks
*
* You can pass a URL, filepath or string of contents. Note that when running Puppeteer
* in a browser environment you cannot pass a filepath and should use either
* `url` or `content`.
*/
addScriptTag(options: {
url?: string;
path?: string;
content?: string;
id?: string;
type?: string;
}): Promise<ElementHandle>;
/**
* Adds a style tag into the current context.
*
* @remarks
*
* You can pass a URL, filepath or string of contents. Note that when running Puppeteer
* in a browser environment you cannot pass a filepath and should use either
* `url` or `content`.
*
*/
addStyleTag(options: {
url?: string;
path?: string;
content?: string;
}): Promise<ElementHandle>;
click(selector: string, options: {
delay?: number;
button?: MouseButton;
clickCount?: number;
}): Promise<void>;
focus(selector: string): Promise<void>;
hover(selector: string): Promise<void>;
select(selector: string, ...values: string[]): Promise<string[]>;
tap(selector: string): Promise<void>;
type(selector: string, text: string, options?: {
delay: number;
}): Promise<void>;
waitForSelector(selector: string, options: WaitForSelectorOptions): Promise<ElementHandle | null>;
private _settingUpBinding;
/**
* @internal
*/
addBindingToContext(context: ExecutionContext, name: string): Promise<void>;
private _onBindingCalled;
/**
* @internal
*/
waitForSelectorInPage(queryOne: Function, selector: string, options: WaitForSelectorOptions, binding?: PageBinding): Promise<ElementHandle | null>;
waitForXPath(xpath: string, options: WaitForSelectorOptions): Promise<ElementHandle | null>;
waitForFunction(pageFunction: Function | string, options?: {
polling?: string | number;
timeout?: number;
}, ...args: SerializableOrJSHandle[]): Promise<JSHandle>;
title(): Promise<string>;
}
/**
* @internal
*/
export interface WaitTaskOptions {
domWorld: DOMWorld;
predicateBody: Function | string;
predicateAcceptsContextElement: boolean;
title: string;
polling: string | number;
timeout: number;
binding?: PageBinding;
args: SerializableOrJSHandle[];
root?: ElementHandle;
}
/**
* @internal
*/
export declare class WaitTask {
_domWorld: DOMWorld;
_polling: string | number;
_timeout: number;
_predicateBody: string;
_predicateAcceptsContextElement: boolean;
_args: SerializableOrJSHandle[];
_binding: PageBinding;
_runCount: number;
promise: Promise<JSHandle>;
_resolve: (x: JSHandle) => void;
_reject: (x: Error) => void;
_timeoutTimer?: NodeJS.Timeout;
_terminated: boolean;
_root: ElementHandle;
constructor(options: WaitTaskOptions);
terminate(error: Error): void;
rerun(): Promise<void>;
_cleanup(): void;
}
//# sourceMappingURL=DOMWorld.d.ts.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,683 @@
"use strict";
/**
* Copyright 2019 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.WaitTask = exports.DOMWorld = void 0;
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("./helper.js");
const LifecycleWatcher_js_1 = require("./LifecycleWatcher.js");
const Errors_js_1 = require("./Errors.js");
const QueryHandler_js_1 = require("./QueryHandler.js");
const environment_js_1 = require("../environment.js");
/**
* @internal
*/
class DOMWorld {
constructor(client, frameManager, frame, timeoutSettings) {
this._documentPromise = null;
this._contextPromise = null;
this._contextResolveCallback = null;
this._detached = false;
/**
* @internal
*/
this._waitTasks = new Set();
/**
* @internal
* Contains mapping from functions that should be bound to Puppeteer functions.
*/
this._boundFunctions = new Map();
// Set of bindings that have been registered in the current context.
this._ctxBindings = new Set();
// If multiple waitFor are set up asynchronously, we need to wait for the
// first one to set up the binding in the page before running the others.
this._settingUpBinding = null;
// Keep own reference to client because it might differ from the FrameManager's
// client for OOP iframes.
this._client = client;
this._frameManager = frameManager;
this._frame = frame;
this._timeoutSettings = timeoutSettings;
this._setContext(null);
this._onBindingCalled = this._onBindingCalled.bind(this);
this._client.on('Runtime.bindingCalled', this._onBindingCalled);
}
frame() {
return this._frame;
}
async _setContext(context) {
if (context) {
(0, assert_js_1.assert)(this._contextResolveCallback, 'Execution Context has already been set.');
this._ctxBindings.clear();
this._contextResolveCallback.call(null, context);
this._contextResolveCallback = null;
for (const waitTask of this._waitTasks)
waitTask.rerun();
}
else {
this._documentPromise = null;
this._contextPromise = new Promise((fulfill) => {
this._contextResolveCallback = fulfill;
});
}
}
_hasContext() {
return !this._contextResolveCallback;
}
_detach() {
this._detached = true;
this._client.off('Runtime.bindingCalled', this._onBindingCalled);
for (const waitTask of this._waitTasks)
waitTask.terminate(new Error('waitForFunction failed: frame got detached.'));
}
executionContext() {
if (this._detached)
throw new Error(`Execution context is not available in detached frame "${this._frame.url()}" (are you trying to evaluate?)`);
return this._contextPromise;
}
async evaluateHandle(pageFunction, ...args) {
const context = await this.executionContext();
return context.evaluateHandle(pageFunction, ...args);
}
async evaluate(pageFunction, ...args) {
const context = await this.executionContext();
return context.evaluate(pageFunction, ...args);
}
async $(selector) {
const document = await this._document();
const value = await document.$(selector);
return value;
}
async _document() {
if (this._documentPromise)
return this._documentPromise;
this._documentPromise = this.executionContext().then(async (context) => {
const document = await context.evaluateHandle('document');
return document.asElement();
});
return this._documentPromise;
}
async $x(expression) {
const document = await this._document();
const value = await document.$x(expression);
return value;
}
async $eval(selector, pageFunction, ...args) {
const document = await this._document();
return document.$eval(selector, pageFunction, ...args);
}
async $$eval(selector, pageFunction, ...args) {
const document = await this._document();
const value = await document.$$eval(selector, pageFunction, ...args);
return value;
}
async $$(selector) {
const document = await this._document();
const value = await document.$$(selector);
return value;
}
async content() {
return await this.evaluate(() => {
let retVal = '';
if (document.doctype)
retVal = new XMLSerializer().serializeToString(document.doctype);
if (document.documentElement)
retVal += document.documentElement.outerHTML;
return retVal;
});
}
async setContent(html, options = {}) {
const { waitUntil = ['load'], timeout = this._timeoutSettings.navigationTimeout(), } = options;
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
await this.evaluate((html) => {
document.open();
document.write(html);
document.close();
}, html);
const watcher = new LifecycleWatcher_js_1.LifecycleWatcher(this._frameManager, this._frame, waitUntil, timeout);
const error = await Promise.race([
watcher.timeoutOrTerminationPromise(),
watcher.lifecyclePromise(),
]);
watcher.dispose();
if (error)
throw error;
}
/**
* Adds a script tag into the current context.
*
* @remarks
*
* You can pass a URL, filepath or string of contents. Note that when running Puppeteer
* in a browser environment you cannot pass a filepath and should use either
* `url` or `content`.
*/
async addScriptTag(options) {
const { url = null, path = null, content = null, id = '', type = '', } = options;
if (url !== null) {
try {
const context = await this.executionContext();
return (await context.evaluateHandle(addScriptUrl, url, id, type)).asElement();
}
catch (error) {
throw new Error(`Loading script from ${url} failed`);
}
}
if (path !== null) {
if (!environment_js_1.isNode) {
throw new Error('Cannot pass a filepath to addScriptTag in the browser environment.');
}
const fs = await helper_js_1.helper.importFSModule();
let contents = await fs.promises.readFile(path, 'utf8');
contents += '//# sourceURL=' + path.replace(/\n/g, '');
const context = await this.executionContext();
return (await context.evaluateHandle(addScriptContent, contents, id, type)).asElement();
}
if (content !== null) {
const context = await this.executionContext();
return (await context.evaluateHandle(addScriptContent, content, id, type)).asElement();
}
throw new Error('Provide an object with a `url`, `path` or `content` property');
async function addScriptUrl(url, id, type) {
const script = document.createElement('script');
script.src = url;
if (id)
script.id = id;
if (type)
script.type = type;
const promise = new Promise((res, rej) => {
script.onload = res;
script.onerror = rej;
});
document.head.appendChild(script);
await promise;
return script;
}
function addScriptContent(content, id, type = 'text/javascript') {
const script = document.createElement('script');
script.type = type;
script.text = content;
if (id)
script.id = id;
let error = null;
script.onerror = (e) => (error = e);
document.head.appendChild(script);
if (error)
throw error;
return script;
}
}
/**
* Adds a style tag into the current context.
*
* @remarks
*
* You can pass a URL, filepath or string of contents. Note that when running Puppeteer
* in a browser environment you cannot pass a filepath and should use either
* `url` or `content`.
*
*/
async addStyleTag(options) {
const { url = null, path = null, content = null } = options;
if (url !== null) {
try {
const context = await this.executionContext();
return (await context.evaluateHandle(addStyleUrl, url)).asElement();
}
catch (error) {
throw new Error(`Loading style from ${url} failed`);
}
}
if (path !== null) {
if (!environment_js_1.isNode) {
throw new Error('Cannot pass a filepath to addStyleTag in the browser environment.');
}
const fs = await helper_js_1.helper.importFSModule();
let contents = await fs.promises.readFile(path, 'utf8');
contents += '/*# sourceURL=' + path.replace(/\n/g, '') + '*/';
const context = await this.executionContext();
return (await context.evaluateHandle(addStyleContent, contents)).asElement();
}
if (content !== null) {
const context = await this.executionContext();
return (await context.evaluateHandle(addStyleContent, content)).asElement();
}
throw new Error('Provide an object with a `url`, `path` or `content` property');
async function addStyleUrl(url) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
const promise = new Promise((res, rej) => {
link.onload = res;
link.onerror = rej;
});
document.head.appendChild(link);
await promise;
return link;
}
async function addStyleContent(content) {
const style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode(content));
const promise = new Promise((res, rej) => {
style.onload = res;
style.onerror = rej;
});
document.head.appendChild(style);
await promise;
return style;
}
}
async click(selector, options) {
const handle = await this.$(selector);
(0, assert_js_1.assert)(handle, 'No node found for selector: ' + selector);
await handle.click(options);
await handle.dispose();
}
async focus(selector) {
const handle = await this.$(selector);
(0, assert_js_1.assert)(handle, 'No node found for selector: ' + selector);
await handle.focus();
await handle.dispose();
}
async hover(selector) {
const handle = await this.$(selector);
(0, assert_js_1.assert)(handle, 'No node found for selector: ' + selector);
await handle.hover();
await handle.dispose();
}
async select(selector, ...values) {
const handle = await this.$(selector);
(0, assert_js_1.assert)(handle, 'No node found for selector: ' + selector);
const result = await handle.select(...values);
await handle.dispose();
return result;
}
async tap(selector) {
const handle = await this.$(selector);
await handle.tap();
await handle.dispose();
}
async type(selector, text, options) {
const handle = await this.$(selector);
(0, assert_js_1.assert)(handle, 'No node found for selector: ' + selector);
await handle.type(text, options);
await handle.dispose();
}
async waitForSelector(selector, options) {
const { updatedSelector, queryHandler } = (0, QueryHandler_js_1.getQueryHandlerAndSelector)(selector);
return queryHandler.waitFor(this, updatedSelector, options);
}
/**
* @internal
*/
async addBindingToContext(context, name) {
// Previous operation added the binding so we are done.
if (this._ctxBindings.has(DOMWorld.bindingIdentifier(name, context._contextId))) {
return;
}
// Wait for other operation to finish
if (this._settingUpBinding) {
await this._settingUpBinding;
return this.addBindingToContext(context, name);
}
const bind = async (name) => {
const expression = helper_js_1.helper.pageBindingInitString('internal', name);
try {
// TODO: In theory, it would be enough to call this just once
await context._client.send('Runtime.addBinding', {
name,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore The protocol definition is not up to date.
executionContextName: context._contextName,
});
await context.evaluate(expression);
}
catch (error) {
// We could have tried to evaluate in a context which was already
// destroyed. This happens, for example, if the page is navigated while
// we are trying to add the binding
const ctxDestroyed = error.message.includes('Execution context was destroyed');
const ctxNotFound = error.message.includes('Cannot find context with specified id');
if (ctxDestroyed || ctxNotFound) {
return;
}
else {
(0, helper_js_1.debugError)(error);
return;
}
}
this._ctxBindings.add(DOMWorld.bindingIdentifier(name, context._contextId));
};
this._settingUpBinding = bind(name);
await this._settingUpBinding;
this._settingUpBinding = null;
}
async _onBindingCalled(event) {
let payload;
if (!this._hasContext())
return;
const context = await this.executionContext();
try {
payload = JSON.parse(event.payload);
}
catch {
// The binding was either called by something in the page or it was
// called before our wrapper was initialized.
return;
}
const { type, name, seq, args } = payload;
if (type !== 'internal' ||
!this._ctxBindings.has(DOMWorld.bindingIdentifier(name, context._contextId)))
return;
if (context._contextId !== event.executionContextId)
return;
try {
const result = await this._boundFunctions.get(name)(...args);
await context.evaluate(deliverResult, name, seq, result);
}
catch (error) {
// The WaitTask may already have been resolved by timing out, or the
// exection context may have been destroyed.
// In both caes, the promises above are rejected with a protocol error.
// We can safely ignores these, as the WaitTask is re-installed in
// the next execution context if needed.
if (error.message.includes('Protocol error'))
return;
(0, helper_js_1.debugError)(error);
}
function deliverResult(name, seq, result) {
globalThis[name].callbacks.get(seq).resolve(result);
globalThis[name].callbacks.delete(seq);
}
}
/**
* @internal
*/
async waitForSelectorInPage(queryOne, selector, options, binding) {
const { visible: waitForVisible = false, hidden: waitForHidden = false, timeout = this._timeoutSettings.timeout(), } = options;
const polling = waitForVisible || waitForHidden ? 'raf' : 'mutation';
const title = `selector \`${selector}\`${waitForHidden ? ' to be hidden' : ''}`;
async function predicate(root, selector, waitForVisible, waitForHidden) {
const node = predicateQueryHandler
? (await predicateQueryHandler(root, selector))
: root.querySelector(selector);
return checkWaitForOptions(node, waitForVisible, waitForHidden);
}
const waitTaskOptions = {
domWorld: this,
predicateBody: helper_js_1.helper.makePredicateString(predicate, queryOne),
predicateAcceptsContextElement: true,
title,
polling,
timeout,
args: [selector, waitForVisible, waitForHidden],
binding,
root: options.root,
};
const waitTask = new WaitTask(waitTaskOptions);
const jsHandle = await waitTask.promise;
const elementHandle = jsHandle.asElement();
if (!elementHandle) {
await jsHandle.dispose();
return null;
}
return elementHandle;
}
async waitForXPath(xpath, options) {
const { visible: waitForVisible = false, hidden: waitForHidden = false, timeout = this._timeoutSettings.timeout(), } = options;
const polling = waitForVisible || waitForHidden ? 'raf' : 'mutation';
const title = `XPath \`${xpath}\`${waitForHidden ? ' to be hidden' : ''}`;
function predicate(root, xpath, waitForVisible, waitForHidden) {
const node = document.evaluate(xpath, root, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
return checkWaitForOptions(node, waitForVisible, waitForHidden);
}
const waitTaskOptions = {
domWorld: this,
predicateBody: helper_js_1.helper.makePredicateString(predicate),
predicateAcceptsContextElement: true,
title,
polling,
timeout,
args: [xpath, waitForVisible, waitForHidden],
root: options.root,
};
const waitTask = new WaitTask(waitTaskOptions);
const jsHandle = await waitTask.promise;
const elementHandle = jsHandle.asElement();
if (!elementHandle) {
await jsHandle.dispose();
return null;
}
return elementHandle;
}
waitForFunction(pageFunction, options = {}, ...args) {
const { polling = 'raf', timeout = this._timeoutSettings.timeout() } = options;
const waitTaskOptions = {
domWorld: this,
predicateBody: pageFunction,
predicateAcceptsContextElement: false,
title: 'function',
polling,
timeout,
args,
};
const waitTask = new WaitTask(waitTaskOptions);
return waitTask.promise;
}
async title() {
return this.evaluate(() => document.title);
}
}
exports.DOMWorld = DOMWorld;
DOMWorld.bindingIdentifier = (name, contextId) => `${name}_${contextId}`;
/**
* @internal
*/
class WaitTask {
constructor(options) {
this._runCount = 0;
this._terminated = false;
this._root = null;
if (helper_js_1.helper.isString(options.polling))
(0, assert_js_1.assert)(options.polling === 'raf' || options.polling === 'mutation', 'Unknown polling option: ' + options.polling);
else if (helper_js_1.helper.isNumber(options.polling))
(0, assert_js_1.assert)(options.polling > 0, 'Cannot poll with non-positive interval: ' + options.polling);
else
throw new Error('Unknown polling options: ' + options.polling);
function getPredicateBody(predicateBody) {
if (helper_js_1.helper.isString(predicateBody))
return `return (${predicateBody});`;
return `return (${predicateBody})(...args);`;
}
this._domWorld = options.domWorld;
this._polling = options.polling;
this._timeout = options.timeout;
this._root = options.root;
this._predicateBody = getPredicateBody(options.predicateBody);
this._predicateAcceptsContextElement =
options.predicateAcceptsContextElement;
this._args = options.args;
this._binding = options.binding;
this._runCount = 0;
this._domWorld._waitTasks.add(this);
if (this._binding) {
this._domWorld._boundFunctions.set(this._binding.name, this._binding.pptrFunction);
}
this.promise = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
// Since page navigation requires us to re-install the pageScript, we should track
// timeout on our end.
if (options.timeout) {
const timeoutError = new Errors_js_1.TimeoutError(`waiting for ${options.title} failed: timeout ${options.timeout}ms exceeded`);
this._timeoutTimer = setTimeout(() => this.terminate(timeoutError), options.timeout);
}
this.rerun();
}
terminate(error) {
this._terminated = true;
this._reject(error);
this._cleanup();
}
async rerun() {
const runCount = ++this._runCount;
let success = null;
let error = null;
const context = await this._domWorld.executionContext();
if (this._terminated || runCount !== this._runCount)
return;
if (this._binding) {
await this._domWorld.addBindingToContext(context, this._binding.name);
}
if (this._terminated || runCount !== this._runCount)
return;
try {
success = await context.evaluateHandle(waitForPredicatePageFunction, this._root || null, this._predicateBody, this._predicateAcceptsContextElement, this._polling, this._timeout, ...this._args);
}
catch (error_) {
error = error_;
}
if (this._terminated || runCount !== this._runCount) {
if (success)
await success.dispose();
return;
}
// Ignore timeouts in pageScript - we track timeouts ourselves.
// If the frame's execution context has already changed, `frame.evaluate` will
// throw an error - ignore this predicate run altogether.
if (!error &&
(await this._domWorld.evaluate((s) => !s, success).catch(() => true))) {
await success.dispose();
return;
}
if (error) {
if (error.message.includes('TypeError: binding is not a function')) {
return this.rerun();
}
// When frame is detached the task should have been terminated by the DOMWorld.
// This can fail if we were adding this task while the frame was detached,
// so we terminate here instead.
if (error.message.includes('Execution context is not available in detached frame')) {
this.terminate(new Error('waitForFunction failed: frame got detached.'));
return;
}
// When the page is navigated, the promise is rejected.
// We will try again in the new execution context.
if (error.message.includes('Execution context was destroyed'))
return;
// We could have tried to evaluate in a context which was already
// destroyed.
if (error.message.includes('Cannot find context with specified id'))
return;
this._reject(error);
}
else {
this._resolve(success);
}
this._cleanup();
}
_cleanup() {
clearTimeout(this._timeoutTimer);
this._domWorld._waitTasks.delete(this);
}
}
exports.WaitTask = WaitTask;
async function waitForPredicatePageFunction(root, predicateBody, predicateAcceptsContextElement, polling, timeout, ...args) {
root = root || document;
const predicate = new Function('...args', predicateBody);
let timedOut = false;
if (timeout)
setTimeout(() => (timedOut = true), timeout);
if (polling === 'raf')
return await pollRaf();
if (polling === 'mutation')
return await pollMutation();
if (typeof polling === 'number')
return await pollInterval(polling);
/**
* @returns {!Promise<*>}
*/
async function pollMutation() {
const success = predicateAcceptsContextElement
? await predicate(root, ...args)
: await predicate(...args);
if (success)
return Promise.resolve(success);
let fulfill;
const result = new Promise((x) => (fulfill = x));
const observer = new MutationObserver(async () => {
if (timedOut) {
observer.disconnect();
fulfill();
}
const success = predicateAcceptsContextElement
? await predicate(root, ...args)
: await predicate(...args);
if (success) {
observer.disconnect();
fulfill(success);
}
});
observer.observe(root, {
childList: true,
subtree: true,
attributes: true,
});
return result;
}
async function pollRaf() {
let fulfill;
const result = new Promise((x) => (fulfill = x));
await onRaf();
return result;
async function onRaf() {
if (timedOut) {
fulfill();
return;
}
const success = predicateAcceptsContextElement
? await predicate(root, ...args)
: await predicate(...args);
if (success)
fulfill(success);
else
requestAnimationFrame(onRaf);
}
}
async function pollInterval(pollInterval) {
let fulfill;
const result = new Promise((x) => (fulfill = x));
await onTimeout();
return result;
async function onTimeout() {
if (timedOut) {
fulfill();
return;
}
const success = predicateAcceptsContextElement
? await predicate(root, ...args)
: await predicate(...args);
if (success)
fulfill(success);
else
setTimeout(onTimeout, pollInterval);
}
}
}
//# sourceMappingURL=DOMWorld.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,53 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
/**
* A debug function that can be used in any environment.
*
* @remarks
*
* If used in Node, it falls back to the
* {@link https://www.npmjs.com/package/debug | debug module}. In the browser it
* uses `console.log`.
*
* @param prefix - this will be prefixed to each log.
* @returns a function that can be called to log to that debug channel.
*
* In Node, use the `DEBUG` environment variable to control logging:
*
* ```
* DEBUG=* // logs all channels
* DEBUG=foo // logs the `foo` channel
* DEBUG=foo* // logs any channels starting with `foo`
* ```
*
* In the browser, set `window.__PUPPETEER_DEBUG` to a string:
*
* ```
* window.__PUPPETEER_DEBUG='*'; // logs all channels
* window.__PUPPETEER_DEBUG='foo'; // logs the `foo` channel
* window.__PUPPETEER_DEBUG='foo*'; // logs any channels starting with `foo`
* ```
*
* @example
* ```
* const log = debug('Page');
*
* log('new page created')
* // logs "Page: new page created"
* ```
*/
export declare const debug: (prefix: string) => (...args: unknown[]) => void;
//# sourceMappingURL=Debug.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Debug.d.ts","sourceRoot":"","sources":["../../../../src/common/Debug.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,KAAK,WAAY,MAAM,eAAc,OAAO,EAAE,KAAK,IA4B/D,CAAC"}

View File

@@ -0,0 +1,82 @@
"use strict";
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.debug = void 0;
const environment_js_1 = require("../environment.js");
/**
* A debug function that can be used in any environment.
*
* @remarks
*
* If used in Node, it falls back to the
* {@link https://www.npmjs.com/package/debug | debug module}. In the browser it
* uses `console.log`.
*
* @param prefix - this will be prefixed to each log.
* @returns a function that can be called to log to that debug channel.
*
* In Node, use the `DEBUG` environment variable to control logging:
*
* ```
* DEBUG=* // logs all channels
* DEBUG=foo // logs the `foo` channel
* DEBUG=foo* // logs any channels starting with `foo`
* ```
*
* In the browser, set `window.__PUPPETEER_DEBUG` to a string:
*
* ```
* window.__PUPPETEER_DEBUG='*'; // logs all channels
* window.__PUPPETEER_DEBUG='foo'; // logs the `foo` channel
* window.__PUPPETEER_DEBUG='foo*'; // logs any channels starting with `foo`
* ```
*
* @example
* ```
* const log = debug('Page');
*
* log('new page created')
* // logs "Page: new page created"
* ```
*/
const debug = (prefix) => {
if (environment_js_1.isNode) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
return require('debug')(prefix);
}
return (...logArgs) => {
const debugLevel = globalThis.__PUPPETEER_DEBUG;
if (!debugLevel)
return;
const everythingShouldBeLogged = debugLevel === '*';
const prefixMatchesDebugLevel = everythingShouldBeLogged ||
/**
* If the debug level is `foo*`, that means we match any prefix that
* starts with `foo`. If the level is `foo`, we match only the prefix
* `foo`.
*/
(debugLevel.endsWith('*')
? prefix.startsWith(debugLevel)
: prefix === debugLevel);
if (!prefixMatchesDebugLevel)
return;
// eslint-disable-next-line no-console
console.log(`${prefix}:`, ...logArgs);
};
};
exports.debug = debug;
//# sourceMappingURL=Debug.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Debug.js","sourceRoot":"","sources":["../../../../src/common/Debug.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH,sDAA2C;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACI,MAAM,KAAK,GAAG,CAAC,MAAc,EAAkC,EAAE;IACtE,IAAI,uBAAM,EAAE;QACV,8DAA8D;QAC9D,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;KACjC;IAED,OAAO,CAAC,GAAG,OAAkB,EAAQ,EAAE;QACrC,MAAM,UAAU,GAAG,UAAU,CAAC,iBAA2B,CAAC;QAC1D,IAAI,CAAC,UAAU;YAAE,OAAO;QAExB,MAAM,wBAAwB,GAAG,UAAU,KAAK,GAAG,CAAC;QAEpD,MAAM,uBAAuB,GAC3B,wBAAwB;YACxB;;;;eAIG;YACH,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC;gBACvB,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;gBAC/B,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;QAE7B,IAAI,CAAC,uBAAuB;YAAE,OAAO;QAErC,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC,CAAC;AA5BW,QAAA,KAAK,SA4BhB"}

View File

@@ -0,0 +1,41 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/
/**
* @public
*/
export interface Device {
name: string;
userAgent: string;
viewport: {
width: number;
height: number;
deviceScaleFactor: number;
isMobile: boolean;
hasTouch: boolean;
isLandscape: boolean;
};
}
/**
* @public
*/
export declare type DevicesMap = {
[name: string]: Device;
};
/**
* @internal
*/
export declare const devicesMap: DevicesMap;
//# sourceMappingURL=DeviceDescriptors.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DeviceDescriptors.d.ts","sourceRoot":"","sources":["../../../../src/common/DeviceDescriptors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,iBAAiB,EAAE,MAAM,CAAC;QAC1B,QAAQ,EAAE,OAAO,CAAC;QAClB,QAAQ,EAAE,OAAO,CAAC;QAClB,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC;CACH;AA29CD;;GAEG;AACH,oBAAY,UAAU,GAAG;IACvB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,UAAe,CAAC"}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,75 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CDPSession } from './Connection.js';
import { Protocol } from 'devtools-protocol';
/**
* Dialog instances are dispatched by the {@link Page} via the `dialog` event.
*
* @remarks
*
* @example
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* page.on('dialog', async dialog => {
* console.log(dialog.message());
* await dialog.dismiss();
* await browser.close();
* });
* page.evaluate(() => alert('1'));
* })();
* ```
* @public
*/
export declare class Dialog {
private _client;
private _type;
private _message;
private _defaultValue;
private _handled;
/**
* @internal
*/
constructor(client: CDPSession, type: Protocol.Page.DialogType, message: string, defaultValue?: string);
/**
* @returns The type of the dialog.
*/
type(): Protocol.Page.DialogType;
/**
* @returns The message displayed in the dialog.
*/
message(): string;
/**
* @returns The default value of the prompt, or an empty string if the dialog
* is not a `prompt`.
*/
defaultValue(): string;
/**
* @param promptText - optional text that will be entered in the dialog
* prompt. Has no effect if the dialog's type is not `prompt`.
*
* @returns A promise that resolves when the dialog has been accepted.
*/
accept(promptText?: string): Promise<void>;
/**
* @returns A promise which will resolve once the dialog has been dismissed
*/
dismiss(): Promise<void>;
}
//# sourceMappingURL=Dialog.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../../src/common/Dialog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAS;IAEzB;;OAEG;gBAED,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,EAC9B,OAAO,EAAE,MAAM,EACf,YAAY,SAAK;IAQnB;;OAEG;IACH,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU;IAIhC;;OAEG;IACH,OAAO,IAAI,MAAM;IAIjB;;;OAGG;IACH,YAAY,IAAI,MAAM;IAItB;;;;;OAKG;IACG,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAShD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAO/B"}

View File

@@ -0,0 +1,98 @@
"use strict";
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Dialog = void 0;
const assert_js_1 = require("./assert.js");
/**
* Dialog instances are dispatched by the {@link Page} via the `dialog` event.
*
* @remarks
*
* @example
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* page.on('dialog', async dialog => {
* console.log(dialog.message());
* await dialog.dismiss();
* await browser.close();
* });
* page.evaluate(() => alert('1'));
* })();
* ```
* @public
*/
class Dialog {
/**
* @internal
*/
constructor(client, type, message, defaultValue = '') {
this._handled = false;
this._client = client;
this._type = type;
this._message = message;
this._defaultValue = defaultValue;
}
/**
* @returns The type of the dialog.
*/
type() {
return this._type;
}
/**
* @returns The message displayed in the dialog.
*/
message() {
return this._message;
}
/**
* @returns The default value of the prompt, or an empty string if the dialog
* is not a `prompt`.
*/
defaultValue() {
return this._defaultValue;
}
/**
* @param promptText - optional text that will be entered in the dialog
* prompt. Has no effect if the dialog's type is not `prompt`.
*
* @returns A promise that resolves when the dialog has been accepted.
*/
async accept(promptText) {
(0, assert_js_1.assert)(!this._handled, 'Cannot accept dialog which is already handled!');
this._handled = true;
await this._client.send('Page.handleJavaScriptDialog', {
accept: true,
promptText: promptText,
});
}
/**
* @returns A promise which will resolve once the dialog has been dismissed
*/
async dismiss() {
(0, assert_js_1.assert)(!this._handled, 'Cannot dismiss dialog which is already handled!');
this._handled = true;
await this._client.send('Page.handleJavaScriptDialog', {
accept: false,
});
}
}
exports.Dialog = Dialog;
//# sourceMappingURL=Dialog.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Dialog.js","sourceRoot":"","sources":["../../../../src/common/Dialog.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH,2CAAqC;AAIrC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAa,MAAM;IAOjB;;OAEG;IACH,YACE,MAAkB,EAClB,IAA8B,EAC9B,OAAe,EACf,YAAY,GAAG,EAAE;QATX,aAAQ,GAAG,KAAK,CAAC;QAWvB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;OAGG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,MAAM,CAAC,UAAmB;QAC9B,IAAA,kBAAM,EAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,gDAAgD,CAAC,CAAC;QACzE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAE;YACrD,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,UAAU;SACvB,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAA,kBAAM,EAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,iDAAiD,CAAC,CAAC;QAC1E,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAE;YACrD,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;IACL,CAAC;CACF;AArED,wBAqEC"}

View File

@@ -0,0 +1,25 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CDPSession } from './Connection.js';
import { Viewport } from './PuppeteerViewport.js';
export declare class EmulationManager {
_client: CDPSession;
_emulatingMobile: boolean;
_hasTouch: boolean;
constructor(client: CDPSession);
emulateViewport(viewport: Viewport): Promise<boolean>;
}
//# sourceMappingURL=EmulationManager.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EmulationManager.d.ts","sourceRoot":"","sources":["../../../../src/common/EmulationManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGlD,qBAAa,gBAAgB;IAC3B,OAAO,EAAE,UAAU,CAAC;IACpB,gBAAgB,UAAS;IACzB,SAAS,UAAS;gBAEN,MAAM,EAAE,UAAU;IAIxB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;CA8B5D"}

View File

@@ -0,0 +1,38 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EmulationManager = void 0;
class EmulationManager {
constructor(client) {
this._emulatingMobile = false;
this._hasTouch = false;
this._client = client;
}
async emulateViewport(viewport) {
const mobile = viewport.isMobile || false;
const width = viewport.width;
const height = viewport.height;
const deviceScaleFactor = viewport.deviceScaleFactor || 1;
const screenOrientation = viewport.isLandscape
? { angle: 90, type: 'landscapePrimary' }
: { angle: 0, type: 'portraitPrimary' };
const hasTouch = viewport.hasTouch || false;
await Promise.all([
this._client.send('Emulation.setDeviceMetricsOverride', {
mobile,
width,
height,
deviceScaleFactor,
screenOrientation,
}),
this._client.send('Emulation.setTouchEmulationEnabled', {
enabled: hasTouch,
}),
]);
const reloadNeeded = this._emulatingMobile !== mobile || this._hasTouch !== hasTouch;
this._emulatingMobile = mobile;
this._hasTouch = hasTouch;
return reloadNeeded;
}
}
exports.EmulationManager = EmulationManager;
//# sourceMappingURL=EmulationManager.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EmulationManager.js","sourceRoot":"","sources":["../../../../src/common/EmulationManager.ts"],"names":[],"mappings":";;;AAmBA,MAAa,gBAAgB;IAK3B,YAAY,MAAkB;QAH9B,qBAAgB,GAAG,KAAK,CAAC;QACzB,cAAS,GAAG,KAAK,CAAC;QAGhB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAAkB;QACtC,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,IAAI,KAAK,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QAC7B,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC/B,MAAM,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,IAAI,CAAC,CAAC;QAC1D,MAAM,iBAAiB,GACrB,QAAQ,CAAC,WAAW;YAClB,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE;YACzC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,KAAK,CAAC;QAE5C,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE;gBACtD,MAAM;gBACN,KAAK;gBACL,MAAM;gBACN,iBAAiB;gBACjB,iBAAiB;aAClB,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE;gBACtD,OAAO,EAAE,QAAQ;aAClB,CAAC;SACH,CAAC,CAAC;QAEH,MAAM,YAAY,GAChB,IAAI,CAAC,gBAAgB,KAAK,MAAM,IAAI,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC;QAClE,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,OAAO,YAAY,CAAC;IACtB,CAAC;CACF;AAvCD,4CAuCC"}

View File

@@ -0,0 +1,51 @@
/**
* Copyright 2018 Google Inc. All rights reserved.
*
* 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.
*/
/**
* @public
*/
export declare class CustomError extends Error {
constructor(message?: string);
}
/**
* TimeoutError is emitted whenever certain operations are terminated due to timeout.
*
* @remarks
*
* Example operations are {@link Page.waitForSelector | page.waitForSelector}
* or {@link PuppeteerNode.launch | puppeteer.launch}.
*
* @public
*/
export declare class TimeoutError extends CustomError {
}
/**
* ProtocolError is emitted whenever there is an error from the protocol.
*
* @public
*/
export declare class ProtocolError extends CustomError {
code?: number;
originalMessage: string;
}
/**
* @public
*/
export declare type PuppeteerErrors = Record<string, typeof CustomError>;
/**
* @public
*/
export declare const puppeteerErrors: PuppeteerErrors;
//# sourceMappingURL=Errors.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Errors.d.ts","sourceRoot":"","sources":["../../../../src/common/Errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,CAAC,EAAE,MAAM;CAK7B;AAED;;;;;;;;;GASG;AACH,qBAAa,YAAa,SAAQ,WAAW;CAAG;AAChD;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,WAAW;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,SAAM;CAC7B;AACD;;GAEG;AACH,oBAAY,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,WAAW,CAAC,CAAC;AACjE;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,eAE7B,CAAC"}

View File

@@ -0,0 +1,61 @@
"use strict";
/**
* Copyright 2018 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.puppeteerErrors = exports.ProtocolError = exports.TimeoutError = exports.CustomError = void 0;
/**
* @public
*/
class CustomError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
exports.CustomError = CustomError;
/**
* TimeoutError is emitted whenever certain operations are terminated due to timeout.
*
* @remarks
*
* Example operations are {@link Page.waitForSelector | page.waitForSelector}
* or {@link PuppeteerNode.launch | puppeteer.launch}.
*
* @public
*/
class TimeoutError extends CustomError {
}
exports.TimeoutError = TimeoutError;
/**
* ProtocolError is emitted whenever there is an error from the protocol.
*
* @public
*/
class ProtocolError extends CustomError {
constructor() {
super(...arguments);
this.originalMessage = '';
}
}
exports.ProtocolError = ProtocolError;
/**
* @public
*/
exports.puppeteerErrors = {
TimeoutError,
};
//# sourceMappingURL=Errors.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Errors.js","sourceRoot":"","sources":["../../../../src/common/Errors.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH;;GAEG;AACH,MAAa,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAgB;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF;AAND,kCAMC;AAED;;;;;;;;;GASG;AACH,MAAa,YAAa,SAAQ,WAAW;CAAG;AAAhD,oCAAgD;AAChD;;;;GAIG;AACH,MAAa,aAAc,SAAQ,WAAW;IAA9C;;QAES,oBAAe,GAAG,EAAE,CAAC;IAC9B,CAAC;CAAA;AAHD,sCAGC;AAKD;;GAEG;AACU,QAAA,eAAe,GAAoB;IAC9C,YAAY;CACb,CAAC"}

View File

@@ -0,0 +1,61 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { JSHandle, ElementHandle } from './JSHandle.js';
/**
* @public
*/
export declare type EvaluateFn<T = any> = string | ((arg1: T, ...args: any[]) => any);
/**
* @public
*/
export declare type UnwrapPromiseLike<T> = T extends PromiseLike<infer U> ? U : T;
/**
* @public
*/
export declare type EvaluateFnReturnType<T extends EvaluateFn> = T extends (...args: any[]) => infer R ? R : any;
/**
* @public
*/
export declare type EvaluateHandleFn = string | ((...args: any[]) => any);
/**
* @public
*/
export declare type Serializable = number | string | boolean | null | BigInt | JSONArray | JSONObject;
/**
* @public
*/
export declare type JSONArray = readonly Serializable[];
/**
* @public
*/
export interface JSONObject {
[key: string]: Serializable;
}
/**
* @public
*/
export declare type SerializableOrJSHandle = Serializable | JSHandle;
/**
* Wraps a DOM element into an ElementHandle instance
* @public
**/
export declare type WrapElementHandle<X> = X extends Element ? ElementHandle<X> : X;
/**
* Unwraps a DOM element out of an ElementHandle instance
* @public
**/
export declare type UnwrapElementHandle<X> = X extends ElementHandle<infer E> ? E : X;
//# sourceMappingURL=EvalTypes.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EvalTypes.d.ts","sourceRoot":"","sources":["../../../../src/common/EvalTypes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAExD;;GAEG;AACH,oBAAY,UAAU,CAAC,CAAC,GAAG,GAAG,IAAI,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC;AAC9E;;GAEG;AACH,oBAAY,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE1E;;GAEG;AACH,oBAAY,oBAAoB,CAAC,CAAC,SAAS,UAAU,IAAI,CAAC,SAAS,CACjE,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,MAAM,CAAC,GACR,CAAC,GACD,GAAG,CAAC;AAER;;GAEG;AACH,oBAAY,gBAAgB,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC;AAElE;;GAEG;AACH,oBAAY,YAAY,GACpB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,MAAM,GACN,SAAS,GACT,UAAU,CAAC;AAEf;;GAEG;AACH,oBAAY,SAAS,GAAG,SAAS,YAAY,EAAE,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAC;CAC7B;AAED;;GAEG;AACH,oBAAY,sBAAsB,GAAG,YAAY,GAAG,QAAQ,CAAC;AAE7D;;;IAGI;AACJ,oBAAY,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAE5E;;;IAGI;AACJ,oBAAY,mBAAmB,CAAC,CAAC,IAAI,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC"}

View File

@@ -0,0 +1,18 @@
"use strict";
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=EvalTypes.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EvalTypes.js","sourceRoot":"","sources":["../../../../src/common/EvalTypes.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG"}

View File

@@ -0,0 +1,93 @@
import { EventType, Handler } from '../../vendor/mitt/src/index.js';
/**
* @public
*/
export { EventType, Handler };
/**
* @public
*/
export interface CommonEventEmitter {
on(event: EventType, handler: Handler): CommonEventEmitter;
off(event: EventType, handler: Handler): CommonEventEmitter;
addListener(event: EventType, handler: Handler): CommonEventEmitter;
removeListener(event: EventType, handler: Handler): CommonEventEmitter;
emit(event: EventType, eventData?: unknown): boolean;
once(event: EventType, handler: Handler): CommonEventEmitter;
listenerCount(event: string): number;
removeAllListeners(event?: EventType): CommonEventEmitter;
}
/**
* The EventEmitter class that many Puppeteer classes extend.
*
* @remarks
*
* This allows you to listen to events that Puppeteer classes fire and act
* accordingly. Therefore you'll mostly use {@link EventEmitter.on | on} and
* {@link EventEmitter.off | off} to bind
* and unbind to event listeners.
*
* @public
*/
export declare class EventEmitter implements CommonEventEmitter {
private emitter;
private eventsMap;
/**
* @internal
*/
constructor();
/**
* Bind an event listener to fire when an event occurs.
* @param event - the event type you'd like to listen to. Can be a string or symbol.
* @param handler - the function to be called when the event occurs.
* @returns `this` to enable you to chain method calls.
*/
on(event: EventType, handler: Handler): EventEmitter;
/**
* Remove an event listener from firing.
* @param event - the event type you'd like to stop listening to.
* @param handler - the function that should be removed.
* @returns `this` to enable you to chain method calls.
*/
off(event: EventType, handler: Handler): EventEmitter;
/**
* Remove an event listener.
* @deprecated please use {@link EventEmitter.off} instead.
*/
removeListener(event: EventType, handler: Handler): EventEmitter;
/**
* Add an event listener.
* @deprecated please use {@link EventEmitter.on} instead.
*/
addListener(event: EventType, handler: Handler): EventEmitter;
/**
* Emit an event and call any associated listeners.
*
* @param event - the event you'd like to emit
* @param eventData - any data you'd like to emit with the event
* @returns `true` if there are any listeners, `false` if there are not.
*/
emit(event: EventType, eventData?: unknown): boolean;
/**
* Like `on` but the listener will only be fired once and then it will be removed.
* @param event - the event you'd like to listen to
* @param handler - the handler function to run when the event occurs
* @returns `this` to enable you to chain method calls.
*/
once(event: EventType, handler: Handler): EventEmitter;
/**
* Gets the number of listeners for a given event.
*
* @param event - the event to get the listener count for
* @returns the number of listeners bound to the given event
*/
listenerCount(event: EventType): number;
/**
* Removes all listeners. If given an event argument, it will remove only
* listeners for that event.
* @param event - the event to remove listeners for.
* @returns `this` to enable you to chain method calls.
*/
removeAllListeners(event?: EventType): EventEmitter;
private eventListenersCount;
}
//# sourceMappingURL=EventEmitter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EventEmitter.d.ts","sourceRoot":"","sources":["../../../../src/common/EventEmitter.ts"],"names":[],"mappings":"AAAA,OAAa,EAEX,SAAS,EACT,OAAO,EACR,MAAM,gCAAgC,CAAC;AAExC;;GAEG;AACH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAE9B;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAC3D,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAK5D,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAAC;IACpE,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAAC;IACvE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACrD,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAC7D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAErC,kBAAkB,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,kBAAkB,CAAC;CAC3D;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,YAAa,YAAW,kBAAkB;IACrD,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,SAAS,CAAmC;IAEpD;;OAEG;;IAKH;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY;IAKpD;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY;IAKrD;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY;IAKhE;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY;IAK7D;;;;;;OAMG;IACH,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO;IAKpD;;;;;OAKG;IACH,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY;IAStD;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM;IAIvC;;;;;OAKG;IACH,kBAAkB,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,YAAY;IASnD,OAAO,CAAC,mBAAmB;CAG5B"}

View File

@@ -0,0 +1,118 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventEmitter = void 0;
const index_js_1 = __importDefault(require("../../vendor/mitt/src/index.js"));
/**
* The EventEmitter class that many Puppeteer classes extend.
*
* @remarks
*
* This allows you to listen to events that Puppeteer classes fire and act
* accordingly. Therefore you'll mostly use {@link EventEmitter.on | on} and
* {@link EventEmitter.off | off} to bind
* and unbind to event listeners.
*
* @public
*/
class EventEmitter {
/**
* @internal
*/
constructor() {
this.eventsMap = new Map();
this.emitter = (0, index_js_1.default)(this.eventsMap);
}
/**
* Bind an event listener to fire when an event occurs.
* @param event - the event type you'd like to listen to. Can be a string or symbol.
* @param handler - the function to be called when the event occurs.
* @returns `this` to enable you to chain method calls.
*/
on(event, handler) {
this.emitter.on(event, handler);
return this;
}
/**
* Remove an event listener from firing.
* @param event - the event type you'd like to stop listening to.
* @param handler - the function that should be removed.
* @returns `this` to enable you to chain method calls.
*/
off(event, handler) {
this.emitter.off(event, handler);
return this;
}
/**
* Remove an event listener.
* @deprecated please use {@link EventEmitter.off} instead.
*/
removeListener(event, handler) {
this.off(event, handler);
return this;
}
/**
* Add an event listener.
* @deprecated please use {@link EventEmitter.on} instead.
*/
addListener(event, handler) {
this.on(event, handler);
return this;
}
/**
* Emit an event and call any associated listeners.
*
* @param event - the event you'd like to emit
* @param eventData - any data you'd like to emit with the event
* @returns `true` if there are any listeners, `false` if there are not.
*/
emit(event, eventData) {
this.emitter.emit(event, eventData);
return this.eventListenersCount(event) > 0;
}
/**
* Like `on` but the listener will only be fired once and then it will be removed.
* @param event - the event you'd like to listen to
* @param handler - the handler function to run when the event occurs
* @returns `this` to enable you to chain method calls.
*/
once(event, handler) {
const onceHandler = (eventData) => {
handler(eventData);
this.off(event, onceHandler);
};
return this.on(event, onceHandler);
}
/**
* Gets the number of listeners for a given event.
*
* @param event - the event to get the listener count for
* @returns the number of listeners bound to the given event
*/
listenerCount(event) {
return this.eventListenersCount(event);
}
/**
* Removes all listeners. If given an event argument, it will remove only
* listeners for that event.
* @param event - the event to remove listeners for.
* @returns `this` to enable you to chain method calls.
*/
removeAllListeners(event) {
if (event) {
this.eventsMap.delete(event);
}
else {
this.eventsMap.clear();
}
return this;
}
eventListenersCount(event) {
var _a;
return ((_a = this.eventsMap.get(event)) === null || _a === void 0 ? void 0 : _a.length) || 0;
}
}
exports.EventEmitter = EventEmitter;
//# sourceMappingURL=EventEmitter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EventEmitter.js","sourceRoot":"","sources":["../../../../src/common/EventEmitter.ts"],"names":[],"mappings":";;;;;;AAAA,8EAIwC;AA0BxC;;;;;;;;;;;GAWG;AACH,MAAa,YAAY;IAIvB;;OAEG;IACH;QALQ,cAAS,GAAG,IAAI,GAAG,EAAwB,CAAC;QAMlD,IAAI,CAAC,OAAO,GAAG,IAAA,kBAAI,EAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED;;;;;OAKG;IACH,EAAE,CAAC,KAAgB,EAAE,OAAgB;QACnC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,KAAgB,EAAE,OAAgB;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,KAAgB,EAAE,OAAgB;QAC/C,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,KAAgB,EAAE,OAAgB;QAC5C,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;OAMG;IACH,IAAI,CAAC,KAAgB,EAAE,SAAmB;QACxC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,KAAgB,EAAE,OAAgB;QACrC,MAAM,WAAW,GAAY,CAAC,SAAS,EAAE,EAAE;YACzC,OAAO,CAAC,SAAS,CAAC,CAAC;YACnB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAC/B,CAAC,CAAC;QAEF,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACrC,CAAC;IAED;;;;;OAKG;IACH,aAAa,CAAC,KAAgB;QAC5B,OAAO,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,KAAiB;QAClC,IAAI,KAAK,EAAE;YACT,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;SAC9B;aAAM;YACL,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;SACxB;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,mBAAmB,CAAC,KAAgB;;QAC1C,OAAO,CAAA,MAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,0CAAE,MAAM,KAAI,CAAC,CAAC;IAChD,CAAC;CACF;AA1GD,oCA0GC"}

View File

@@ -0,0 +1,82 @@
/**
* Copyright 2019 Google Inc. All rights reserved.
*
* 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.
*/
/**
* IMPORTANT: we are mid-way through migrating away from this Events.ts file
* in favour of defining events next to the class that emits them.
*
* However we need to maintain this file for now because the legacy DocLint
* system relies on them. Be aware in the mean time if you make a change here
* you probably need to replicate it in the relevant class. For example if you
* add a new Page event, you should update the PageEmittedEvents enum in
* src/common/Page.ts.
*
* Chat to @jackfranklin if you're unsure.
*/
export declare const Events: {
readonly Page: {
readonly Close: "close";
readonly Console: "console";
readonly Dialog: "dialog";
readonly DOMContentLoaded: "domcontentloaded";
readonly Error: "error";
readonly PageError: "pageerror";
readonly Request: "request";
readonly Response: "response";
readonly RequestFailed: "requestfailed";
readonly RequestFinished: "requestfinished";
readonly FrameAttached: "frameattached";
readonly FrameDetached: "framedetached";
readonly FrameNavigated: "framenavigated";
readonly Load: "load";
readonly Metrics: "metrics";
readonly Popup: "popup";
readonly WorkerCreated: "workercreated";
readonly WorkerDestroyed: "workerdestroyed";
};
readonly Browser: {
readonly TargetCreated: "targetcreated";
readonly TargetDestroyed: "targetdestroyed";
readonly TargetChanged: "targetchanged";
readonly Disconnected: "disconnected";
};
readonly BrowserContext: {
readonly TargetCreated: "targetcreated";
readonly TargetDestroyed: "targetdestroyed";
readonly TargetChanged: "targetchanged";
};
readonly NetworkManager: {
readonly Request: symbol;
readonly Response: symbol;
readonly RequestFailed: symbol;
readonly RequestFinished: symbol;
};
readonly FrameManager: {
readonly FrameAttached: symbol;
readonly FrameNavigated: symbol;
readonly FrameDetached: symbol;
readonly LifecycleEvent: symbol;
readonly FrameNavigatedWithinDocument: symbol;
readonly ExecutionContextCreated: symbol;
readonly ExecutionContextDestroyed: symbol;
};
readonly Connection: {
readonly Disconnected: symbol;
};
readonly CDPSession: {
readonly Disconnected: symbol;
};
};
//# sourceMappingURL=Events.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Events.d.ts","sourceRoot":"","sources":["../../../../src/common/Events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmET,CAAC"}

View File

@@ -0,0 +1,87 @@
"use strict";
/**
* Copyright 2019 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Events = void 0;
/**
* IMPORTANT: we are mid-way through migrating away from this Events.ts file
* in favour of defining events next to the class that emits them.
*
* However we need to maintain this file for now because the legacy DocLint
* system relies on them. Be aware in the mean time if you make a change here
* you probably need to replicate it in the relevant class. For example if you
* add a new Page event, you should update the PageEmittedEvents enum in
* src/common/Page.ts.
*
* Chat to @jackfranklin if you're unsure.
*/
exports.Events = {
Page: {
Close: 'close',
Console: 'console',
Dialog: 'dialog',
DOMContentLoaded: 'domcontentloaded',
Error: 'error',
// Can't use just 'error' due to node.js special treatment of error events.
// @see https://nodejs.org/api/events.html#events_error_events
PageError: 'pageerror',
Request: 'request',
Response: 'response',
RequestFailed: 'requestfailed',
RequestFinished: 'requestfinished',
FrameAttached: 'frameattached',
FrameDetached: 'framedetached',
FrameNavigated: 'framenavigated',
Load: 'load',
Metrics: 'metrics',
Popup: 'popup',
WorkerCreated: 'workercreated',
WorkerDestroyed: 'workerdestroyed',
},
Browser: {
TargetCreated: 'targetcreated',
TargetDestroyed: 'targetdestroyed',
TargetChanged: 'targetchanged',
Disconnected: 'disconnected',
},
BrowserContext: {
TargetCreated: 'targetcreated',
TargetDestroyed: 'targetdestroyed',
TargetChanged: 'targetchanged',
},
NetworkManager: {
Request: Symbol('Events.NetworkManager.Request'),
Response: Symbol('Events.NetworkManager.Response'),
RequestFailed: Symbol('Events.NetworkManager.RequestFailed'),
RequestFinished: Symbol('Events.NetworkManager.RequestFinished'),
},
FrameManager: {
FrameAttached: Symbol('Events.FrameManager.FrameAttached'),
FrameNavigated: Symbol('Events.FrameManager.FrameNavigated'),
FrameDetached: Symbol('Events.FrameManager.FrameDetached'),
LifecycleEvent: Symbol('Events.FrameManager.LifecycleEvent'),
FrameNavigatedWithinDocument: Symbol('Events.FrameManager.FrameNavigatedWithinDocument'),
ExecutionContextCreated: Symbol('Events.FrameManager.ExecutionContextCreated'),
ExecutionContextDestroyed: Symbol('Events.FrameManager.ExecutionContextDestroyed'),
},
Connection: {
Disconnected: Symbol('Events.Connection.Disconnected'),
},
CDPSession: {
Disconnected: Symbol('Events.CDPSession.Disconnected'),
},
};
//# sourceMappingURL=Events.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Events.js","sourceRoot":"","sources":["../../../../src/common/Events.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH;;;;;;;;;;;GAWG;AAEU,QAAA,MAAM,GAAG;IACpB,IAAI,EAAE;QACJ,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,SAAS;QAClB,MAAM,EAAE,QAAQ;QAChB,gBAAgB,EAAE,kBAAkB;QACpC,KAAK,EAAE,OAAO;QACd,2EAA2E;QAC3E,8DAA8D;QAC9D,SAAS,EAAE,WAAW;QACtB,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,UAAU;QACpB,aAAa,EAAE,eAAe;QAC9B,eAAe,EAAE,iBAAiB;QAClC,aAAa,EAAE,eAAe;QAC9B,aAAa,EAAE,eAAe;QAC9B,cAAc,EAAE,gBAAgB;QAChC,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,OAAO;QACd,aAAa,EAAE,eAAe;QAC9B,eAAe,EAAE,iBAAiB;KACnC;IAED,OAAO,EAAE;QACP,aAAa,EAAE,eAAe;QAC9B,eAAe,EAAE,iBAAiB;QAClC,aAAa,EAAE,eAAe;QAC9B,YAAY,EAAE,cAAc;KAC7B;IAED,cAAc,EAAE;QACd,aAAa,EAAE,eAAe;QAC9B,eAAe,EAAE,iBAAiB;QAClC,aAAa,EAAE,eAAe;KAC/B;IAED,cAAc,EAAE;QACd,OAAO,EAAE,MAAM,CAAC,+BAA+B,CAAC;QAChD,QAAQ,EAAE,MAAM,CAAC,gCAAgC,CAAC;QAClD,aAAa,EAAE,MAAM,CAAC,qCAAqC,CAAC;QAC5D,eAAe,EAAE,MAAM,CAAC,uCAAuC,CAAC;KACjE;IAED,YAAY,EAAE;QACZ,aAAa,EAAE,MAAM,CAAC,mCAAmC,CAAC;QAC1D,cAAc,EAAE,MAAM,CAAC,oCAAoC,CAAC;QAC5D,aAAa,EAAE,MAAM,CAAC,mCAAmC,CAAC;QAC1D,cAAc,EAAE,MAAM,CAAC,oCAAoC,CAAC;QAC5D,4BAA4B,EAAE,MAAM,CAClC,kDAAkD,CACnD;QACD,uBAAuB,EAAE,MAAM,CAC7B,6CAA6C,CAC9C;QACD,yBAAyB,EAAE,MAAM,CAC/B,+CAA+C,CAChD;KACF;IAED,UAAU,EAAE;QACV,YAAY,EAAE,MAAM,CAAC,gCAAgC,CAAC;KACvD;IAED,UAAU,EAAE;QACV,YAAY,EAAE,MAAM,CAAC,gCAAgC,CAAC;KACvD;CACO,CAAC"}

View File

@@ -0,0 +1,194 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { JSHandle, ElementHandle } from './JSHandle.js';
import { CDPSession } from './Connection.js';
import { DOMWorld } from './DOMWorld.js';
import { Frame } from './FrameManager.js';
import { Protocol } from 'devtools-protocol';
import { EvaluateHandleFn, SerializableOrJSHandle } from './EvalTypes.js';
/**
* @public
*/
export declare const EVALUATION_SCRIPT_URL = "__puppeteer_evaluation_script__";
/**
* This class represents a context for JavaScript execution. A [Page] might have
* many execution contexts:
* - each
* {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe |
* frame } has "default" execution context that is always created after frame is
* attached to DOM. This context is returned by the
* {@link Frame.executionContext} method.
* - {@link https://developer.chrome.com/extensions | Extension}'s content scripts
* create additional execution contexts.
*
* Besides pages, execution contexts can be found in
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API |
* workers }.
*
* @public
*/
export declare class ExecutionContext {
/**
* @internal
*/
_client: CDPSession;
/**
* @internal
*/
_world: DOMWorld;
/**
* @internal
*/
_contextId: number;
/**
* @internal
*/
_contextName: string;
/**
* @internal
*/
constructor(client: CDPSession, contextPayload: Protocol.Runtime.ExecutionContextDescription, world: DOMWorld);
/**
* @remarks
*
* Not every execution context is associated with a frame. For
* example, workers and extensions have execution contexts that are not
* associated with frames.
*
* @returns The frame associated with this execution context.
*/
frame(): Frame | null;
/**
* @remarks
* If the function passed to the `executionContext.evaluate` returns a
* Promise, then `executionContext.evaluate` would wait for the promise to
* resolve and return its value. If the function passed to the
* `executionContext.evaluate` returns a non-serializable value, then
* `executionContext.evaluate` resolves to `undefined`. DevTools Protocol also
* supports transferring some additional values that are not serializable by
* `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`, and bigint literals.
*
*
* @example
* ```js
* const executionContext = await page.mainFrame().executionContext();
* const result = await executionContext.evaluate(() => Promise.resolve(8 * 7))* ;
* console.log(result); // prints "56"
* ```
*
* @example
* A string can also be passed in instead of a function.
*
* ```js
* console.log(await executionContext.evaluate('1 + 2')); // prints "3"
* ```
*
* @example
* {@link JSHandle} instances can be passed as arguments to the
* `executionContext.* evaluate`:
* ```js
* const oneHandle = await executionContext.evaluateHandle(() => 1);
* const twoHandle = await executionContext.evaluateHandle(() => 2);
* const result = await executionContext.evaluate(
* (a, b) => a + b, oneHandle, * twoHandle
* );
* await oneHandle.dispose();
* await twoHandle.dispose();
* console.log(result); // prints '3'.
* ```
* @param pageFunction - a function to be evaluated in the `executionContext`
* @param args - argument to pass to the page function
*
* @returns A promise that resolves to the return value of the given function.
*/
evaluate<ReturnType>(pageFunction: Function | string, ...args: unknown[]): Promise<ReturnType>;
/**
* @remarks
* The only difference between `executionContext.evaluate` and
* `executionContext.evaluateHandle` is that `executionContext.evaluateHandle`
* returns an in-page object (a {@link JSHandle}).
* If the function passed to the `executionContext.evaluateHandle` returns a
* Promise, then `executionContext.evaluateHandle` would wait for the
* promise to resolve and return its value.
*
* @example
* ```js
* const context = await page.mainFrame().executionContext();
* const aHandle = await context.evaluateHandle(() => Promise.resolve(self));
* aHandle; // Handle for the global object.
* ```
*
* @example
* A string can also be passed in instead of a function.
*
* ```js
* // Handle for the '3' * object.
* const aHandle = await context.evaluateHandle('1 + 2');
* ```
*
* @example
* JSHandle instances can be passed as arguments
* to the `executionContext.* evaluateHandle`:
*
* ```js
* const aHandle = await context.evaluateHandle(() => document.body);
* const resultHandle = await context.evaluateHandle(body => body.innerHTML, * aHandle);
* console.log(await resultHandle.jsonValue()); // prints body's innerHTML
* await aHandle.dispose();
* await resultHandle.dispose();
* ```
*
* @param pageFunction - a function to be evaluated in the `executionContext`
* @param args - argument to pass to the page function
*
* @returns A promise that resolves to the return value of the given function
* as an in-page object (a {@link JSHandle}).
*/
evaluateHandle<HandleType extends JSHandle | ElementHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<HandleType>;
private _evaluateInternal;
/**
* This method iterates the JavaScript heap and finds all the objects with the
* given prototype.
* @remarks
* @example
* ```js
* // Create a Map object
* await page.evaluate(() => window.map = new Map());
* // Get a handle to the Map object prototype
* const mapPrototype = await page.evaluateHandle(() => Map.prototype);
* // Query all map instances into an array
* const mapInstances = await page.queryObjects(mapPrototype);
* // Count amount of map objects in heap
* const count = await page.evaluate(maps => maps.length, mapInstances);
* await mapInstances.dispose();
* await mapPrototype.dispose();
* ```
*
* @param prototypeHandle - a handle to the object prototype
*
* @returns A handle to an array of objects with the given prototype.
*/
queryObjects(prototypeHandle: JSHandle): Promise<JSHandle>;
/**
* @internal
*/
_adoptBackendNodeId(backendNodeId: Protocol.DOM.BackendNodeId): Promise<ElementHandle>;
/**
* @internal
*/
_adoptElementHandle(elementHandle: ElementHandle): Promise<ElementHandle>;
}
//# sourceMappingURL=ExecutionContext.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExecutionContext.d.ts","sourceRoot":"","sources":["../../../../src/common/ExecutionContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAkB,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC1E;;GAEG;AACH,eAAO,MAAM,qBAAqB,oCAAoC,CAAC;AAGvE;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,gBAAgB;IAC3B;;OAEG;IACH,OAAO,EAAE,UAAU,CAAC;IACpB;;OAEG;IACH,MAAM,EAAE,QAAQ,CAAC;IACjB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;gBAED,MAAM,EAAE,UAAU,EAClB,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,2BAA2B,EAC5D,KAAK,EAAE,QAAQ;IAQjB;;;;;;;;OAQG;IACH,KAAK,IAAI,KAAK,GAAG,IAAI;IAIrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACG,QAAQ,CAAC,UAAU,EACvB,YAAY,EAAE,QAAQ,GAAG,MAAM,EAC/B,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,UAAU,CAAC;IAQtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;IACG,cAAc,CAAC,UAAU,SAAS,QAAQ,GAAG,aAAa,GAAG,QAAQ,EACzE,YAAY,EAAE,gBAAgB,EAC9B,GAAG,IAAI,EAAE,sBAAsB,EAAE,GAChC,OAAO,CAAC,UAAU,CAAC;YAIR,iBAAiB;IAqI/B;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,YAAY,CAAC,eAAe,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAYhE;;OAEG;IACG,mBAAmB,CACvB,aAAa,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,GACxC,OAAO,CAAC,aAAa,CAAC;IAQzB;;OAEG;IACG,mBAAmB,CACvB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,aAAa,CAAC;CAW1B"}

View File

@@ -0,0 +1,322 @@
"use strict";
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExecutionContext = exports.EVALUATION_SCRIPT_URL = void 0;
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("./helper.js");
const JSHandle_js_1 = require("./JSHandle.js");
/**
* @public
*/
exports.EVALUATION_SCRIPT_URL = '__puppeteer_evaluation_script__';
const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m;
/**
* This class represents a context for JavaScript execution. A [Page] might have
* many execution contexts:
* - each
* {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe |
* frame } has "default" execution context that is always created after frame is
* attached to DOM. This context is returned by the
* {@link Frame.executionContext} method.
* - {@link https://developer.chrome.com/extensions | Extension}'s content scripts
* create additional execution contexts.
*
* Besides pages, execution contexts can be found in
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API |
* workers }.
*
* @public
*/
class ExecutionContext {
/**
* @internal
*/
constructor(client, contextPayload, world) {
this._client = client;
this._world = world;
this._contextId = contextPayload.id;
this._contextName = contextPayload.name;
}
/**
* @remarks
*
* Not every execution context is associated with a frame. For
* example, workers and extensions have execution contexts that are not
* associated with frames.
*
* @returns The frame associated with this execution context.
*/
frame() {
return this._world ? this._world.frame() : null;
}
/**
* @remarks
* If the function passed to the `executionContext.evaluate` returns a
* Promise, then `executionContext.evaluate` would wait for the promise to
* resolve and return its value. If the function passed to the
* `executionContext.evaluate` returns a non-serializable value, then
* `executionContext.evaluate` resolves to `undefined`. DevTools Protocol also
* supports transferring some additional values that are not serializable by
* `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`, and bigint literals.
*
*
* @example
* ```js
* const executionContext = await page.mainFrame().executionContext();
* const result = await executionContext.evaluate(() => Promise.resolve(8 * 7))* ;
* console.log(result); // prints "56"
* ```
*
* @example
* A string can also be passed in instead of a function.
*
* ```js
* console.log(await executionContext.evaluate('1 + 2')); // prints "3"
* ```
*
* @example
* {@link JSHandle} instances can be passed as arguments to the
* `executionContext.* evaluate`:
* ```js
* const oneHandle = await executionContext.evaluateHandle(() => 1);
* const twoHandle = await executionContext.evaluateHandle(() => 2);
* const result = await executionContext.evaluate(
* (a, b) => a + b, oneHandle, * twoHandle
* );
* await oneHandle.dispose();
* await twoHandle.dispose();
* console.log(result); // prints '3'.
* ```
* @param pageFunction - a function to be evaluated in the `executionContext`
* @param args - argument to pass to the page function
*
* @returns A promise that resolves to the return value of the given function.
*/
async evaluate(pageFunction, ...args) {
return await this._evaluateInternal(true, pageFunction, ...args);
}
/**
* @remarks
* The only difference between `executionContext.evaluate` and
* `executionContext.evaluateHandle` is that `executionContext.evaluateHandle`
* returns an in-page object (a {@link JSHandle}).
* If the function passed to the `executionContext.evaluateHandle` returns a
* Promise, then `executionContext.evaluateHandle` would wait for the
* promise to resolve and return its value.
*
* @example
* ```js
* const context = await page.mainFrame().executionContext();
* const aHandle = await context.evaluateHandle(() => Promise.resolve(self));
* aHandle; // Handle for the global object.
* ```
*
* @example
* A string can also be passed in instead of a function.
*
* ```js
* // Handle for the '3' * object.
* const aHandle = await context.evaluateHandle('1 + 2');
* ```
*
* @example
* JSHandle instances can be passed as arguments
* to the `executionContext.* evaluateHandle`:
*
* ```js
* const aHandle = await context.evaluateHandle(() => document.body);
* const resultHandle = await context.evaluateHandle(body => body.innerHTML, * aHandle);
* console.log(await resultHandle.jsonValue()); // prints body's innerHTML
* await aHandle.dispose();
* await resultHandle.dispose();
* ```
*
* @param pageFunction - a function to be evaluated in the `executionContext`
* @param args - argument to pass to the page function
*
* @returns A promise that resolves to the return value of the given function
* as an in-page object (a {@link JSHandle}).
*/
async evaluateHandle(pageFunction, ...args) {
return this._evaluateInternal(false, pageFunction, ...args);
}
async _evaluateInternal(returnByValue, pageFunction, ...args) {
const suffix = `//# sourceURL=${exports.EVALUATION_SCRIPT_URL}`;
if (helper_js_1.helper.isString(pageFunction)) {
const contextId = this._contextId;
const expression = pageFunction;
const expressionWithSourceUrl = SOURCE_URL_REGEX.test(expression)
? expression
: expression + '\n' + suffix;
const { exceptionDetails, result: remoteObject } = await this._client
.send('Runtime.evaluate', {
expression: expressionWithSourceUrl,
contextId,
returnByValue,
awaitPromise: true,
userGesture: true,
})
.catch(rewriteError);
if (exceptionDetails)
throw new Error('Evaluation failed: ' + helper_js_1.helper.getExceptionMessage(exceptionDetails));
return returnByValue
? helper_js_1.helper.valueFromRemoteObject(remoteObject)
: (0, JSHandle_js_1.createJSHandle)(this, remoteObject);
}
if (typeof pageFunction !== 'function')
throw new Error(`Expected to get |string| or |function| as the first argument, but got "${pageFunction}" instead.`);
let functionText = pageFunction.toString();
try {
new Function('(' + functionText + ')');
}
catch (error) {
// This means we might have a function shorthand. Try another
// time prefixing 'function '.
if (functionText.startsWith('async '))
functionText =
'async function ' + functionText.substring('async '.length);
else
functionText = 'function ' + functionText;
try {
new Function('(' + functionText + ')');
}
catch (error) {
// We tried hard to serialize, but there's a weird beast here.
throw new Error('Passed function is not well-serializable!');
}
}
let callFunctionOnPromise;
try {
callFunctionOnPromise = this._client.send('Runtime.callFunctionOn', {
functionDeclaration: functionText + '\n' + suffix + '\n',
executionContextId: this._contextId,
arguments: args.map(convertArgument.bind(this)),
returnByValue,
awaitPromise: true,
userGesture: true,
});
}
catch (error) {
if (error instanceof TypeError &&
error.message.startsWith('Converting circular structure to JSON'))
error.message += ' Are you passing a nested JSHandle?';
throw error;
}
const { exceptionDetails, result: remoteObject } = await callFunctionOnPromise.catch(rewriteError);
if (exceptionDetails)
throw new Error('Evaluation failed: ' + helper_js_1.helper.getExceptionMessage(exceptionDetails));
return returnByValue
? helper_js_1.helper.valueFromRemoteObject(remoteObject)
: (0, JSHandle_js_1.createJSHandle)(this, remoteObject);
/**
* @param {*} arg
* @returns {*}
* @this {ExecutionContext}
*/
function convertArgument(arg) {
if (typeof arg === 'bigint')
// eslint-disable-line valid-typeof
return { unserializableValue: `${arg.toString()}n` };
if (Object.is(arg, -0))
return { unserializableValue: '-0' };
if (Object.is(arg, Infinity))
return { unserializableValue: 'Infinity' };
if (Object.is(arg, -Infinity))
return { unserializableValue: '-Infinity' };
if (Object.is(arg, NaN))
return { unserializableValue: 'NaN' };
const objectHandle = arg && arg instanceof JSHandle_js_1.JSHandle ? arg : null;
if (objectHandle) {
if (objectHandle._context !== this)
throw new Error('JSHandles can be evaluated only in the context they were created!');
if (objectHandle._disposed)
throw new Error('JSHandle is disposed!');
if (objectHandle._remoteObject.unserializableValue)
return {
unserializableValue: objectHandle._remoteObject.unserializableValue,
};
if (!objectHandle._remoteObject.objectId)
return { value: objectHandle._remoteObject.value };
return { objectId: objectHandle._remoteObject.objectId };
}
return { value: arg };
}
function rewriteError(error) {
if (error.message.includes('Object reference chain is too long'))
return { result: { type: 'undefined' } };
if (error.message.includes("Object couldn't be returned by value"))
return { result: { type: 'undefined' } };
if (error.message.endsWith('Cannot find context with specified id') ||
error.message.endsWith('Inspected target navigated or closed'))
throw new Error('Execution context was destroyed, most likely because of a navigation.');
throw error;
}
}
/**
* This method iterates the JavaScript heap and finds all the objects with the
* given prototype.
* @remarks
* @example
* ```js
* // Create a Map object
* await page.evaluate(() => window.map = new Map());
* // Get a handle to the Map object prototype
* const mapPrototype = await page.evaluateHandle(() => Map.prototype);
* // Query all map instances into an array
* const mapInstances = await page.queryObjects(mapPrototype);
* // Count amount of map objects in heap
* const count = await page.evaluate(maps => maps.length, mapInstances);
* await mapInstances.dispose();
* await mapPrototype.dispose();
* ```
*
* @param prototypeHandle - a handle to the object prototype
*
* @returns A handle to an array of objects with the given prototype.
*/
async queryObjects(prototypeHandle) {
(0, assert_js_1.assert)(!prototypeHandle._disposed, 'Prototype JSHandle is disposed!');
(0, assert_js_1.assert)(prototypeHandle._remoteObject.objectId, 'Prototype JSHandle must not be referencing primitive value');
const response = await this._client.send('Runtime.queryObjects', {
prototypeObjectId: prototypeHandle._remoteObject.objectId,
});
return (0, JSHandle_js_1.createJSHandle)(this, response.objects);
}
/**
* @internal
*/
async _adoptBackendNodeId(backendNodeId) {
const { object } = await this._client.send('DOM.resolveNode', {
backendNodeId: backendNodeId,
executionContextId: this._contextId,
});
return (0, JSHandle_js_1.createJSHandle)(this, object);
}
/**
* @internal
*/
async _adoptElementHandle(elementHandle) {
(0, assert_js_1.assert)(elementHandle.executionContext() !== this, 'Cannot adopt handle that already belongs to this execution context');
(0, assert_js_1.assert)(this._world, 'Cannot adopt handle without DOMWorld');
const nodeInfo = await this._client.send('DOM.describeNode', {
objectId: elementHandle._remoteObject.objectId,
});
return this._adoptBackendNodeId(nodeInfo.node.backendNodeId);
}
}
exports.ExecutionContext = ExecutionContext;
//# sourceMappingURL=ExecutionContext.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,59 @@
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ElementHandle } from './JSHandle.js';
import { Protocol } from 'devtools-protocol';
/**
* File choosers let you react to the page requesting for a file.
* @remarks
* `FileChooser` objects are returned via the `page.waitForFileChooser` method.
* @example
* An example of using `FileChooser`:
* ```js
* const [fileChooser] = await Promise.all([
* page.waitForFileChooser(),
* page.click('#upload-file-button'), // some button that triggers file selection
* ]);
* await fileChooser.accept(['/tmp/myfile.pdf']);
* ```
* **NOTE** In browsers, only one file chooser can be opened at a time.
* All file choosers must be accepted or canceled. Not doing so will prevent
* subsequent file choosers from appearing.
* @public
*/
export declare class FileChooser {
private _element;
private _multiple;
private _handled;
/**
* @internal
*/
constructor(element: ElementHandle, event: Protocol.Page.FileChooserOpenedEvent);
/**
* Whether file chooser allow for {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-multiple | multiple} file selection.
*/
isMultiple(): boolean;
/**
* Accept the file chooser request with given paths.
* @param filePaths - If some of the `filePaths` are relative paths,
* then they are resolved relative to the {@link https://nodejs.org/api/process.html#process_process_cwd | current working directory}.
*/
accept(filePaths: string[]): Promise<void>;
/**
* Closes the file chooser without selecting any files.
*/
cancel(): void;
}
//# sourceMappingURL=FileChooser.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FileChooser.d.ts","sourceRoot":"","sources":["../../../../src/common/FileChooser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,QAAQ,CAAS;IAEzB;;OAEG;gBAED,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,sBAAsB;IAM7C;;OAEG;IACH,UAAU,IAAI,OAAO;IAIrB;;;;OAIG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAShD;;OAEG;IACH,MAAM,IAAI,IAAI;CAOf"}

View File

@@ -0,0 +1,72 @@
"use strict";
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileChooser = void 0;
const assert_js_1 = require("./assert.js");
/**
* File choosers let you react to the page requesting for a file.
* @remarks
* `FileChooser` objects are returned via the `page.waitForFileChooser` method.
* @example
* An example of using `FileChooser`:
* ```js
* const [fileChooser] = await Promise.all([
* page.waitForFileChooser(),
* page.click('#upload-file-button'), // some button that triggers file selection
* ]);
* await fileChooser.accept(['/tmp/myfile.pdf']);
* ```
* **NOTE** In browsers, only one file chooser can be opened at a time.
* All file choosers must be accepted or canceled. Not doing so will prevent
* subsequent file choosers from appearing.
* @public
*/
class FileChooser {
/**
* @internal
*/
constructor(element, event) {
this._handled = false;
this._element = element;
this._multiple = event.mode !== 'selectSingle';
}
/**
* Whether file chooser allow for {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-multiple | multiple} file selection.
*/
isMultiple() {
return this._multiple;
}
/**
* Accept the file chooser request with given paths.
* @param filePaths - If some of the `filePaths` are relative paths,
* then they are resolved relative to the {@link https://nodejs.org/api/process.html#process_process_cwd | current working directory}.
*/
async accept(filePaths) {
(0, assert_js_1.assert)(!this._handled, 'Cannot accept FileChooser which is already handled!');
this._handled = true;
await this._element.uploadFile(...filePaths);
}
/**
* Closes the file chooser without selecting any files.
*/
cancel() {
(0, assert_js_1.assert)(!this._handled, 'Cannot cancel FileChooser which is already handled!');
this._handled = true;
}
}
exports.FileChooser = FileChooser;
//# sourceMappingURL=FileChooser.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FileChooser.js","sourceRoot":"","sources":["../../../../src/common/FileChooser.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAIH,2CAAqC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,WAAW;IAKtB;;OAEG;IACH,YACE,OAAsB,EACtB,KAA2C;QAPrC,aAAQ,GAAG,KAAK,CAAC;QASvB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,SAAmB;QAC9B,IAAA,kBAAM,EACJ,CAAC,IAAI,CAAC,QAAQ,EACd,qDAAqD,CACtD,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,IAAA,kBAAM,EACJ,CAAC,IAAI,CAAC,QAAQ,EACd,qDAAqD,CACtD,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;CACF;AA/CD,kCA+CC"}

View File

@@ -0,0 +1,754 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { EventEmitter } from './EventEmitter.js';
import { ExecutionContext } from './ExecutionContext.js';
import { PuppeteerLifeCycleEvent } from './LifecycleWatcher.js';
import { DOMWorld, WaitForSelectorOptions } from './DOMWorld.js';
import { NetworkManager } from './NetworkManager.js';
import { TimeoutSettings } from './TimeoutSettings.js';
import { CDPSession } from './Connection.js';
import { JSHandle, ElementHandle } from './JSHandle.js';
import { MouseButton } from './Input.js';
import { Page } from './Page.js';
import { HTTPResponse } from './HTTPResponse.js';
import { Protocol } from 'devtools-protocol';
import { SerializableOrJSHandle, EvaluateHandleFn, WrapElementHandle, EvaluateFn, EvaluateFnReturnType, UnwrapPromiseLike } from './EvalTypes.js';
/**
* We use symbols to prevent external parties listening to these events.
* They are internal to Puppeteer.
*
* @internal
*/
export declare const FrameManagerEmittedEvents: {
FrameAttached: symbol;
FrameNavigated: symbol;
FrameDetached: symbol;
FrameSwapped: symbol;
LifecycleEvent: symbol;
FrameNavigatedWithinDocument: symbol;
ExecutionContextCreated: symbol;
ExecutionContextDestroyed: symbol;
};
/**
* @internal
*/
export declare class FrameManager extends EventEmitter {
_client: CDPSession;
private _page;
private _networkManager;
_timeoutSettings: TimeoutSettings;
private _frames;
private _contextIdToContext;
private _isolatedWorlds;
private _mainFrame;
constructor(client: CDPSession, page: Page, ignoreHTTPSErrors: boolean, timeoutSettings: TimeoutSettings);
private setupEventListeners;
initialize(client?: CDPSession): Promise<void>;
networkManager(): NetworkManager;
navigateFrame(frame: Frame, url: string, options?: {
referer?: string;
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<HTTPResponse | null>;
waitForFrameNavigation(frame: Frame, options?: {
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<HTTPResponse | null>;
private _onAttachedToTarget;
private _onDetachedFromTarget;
_onLifecycleEvent(event: Protocol.Page.LifecycleEventEvent): void;
_onFrameStoppedLoading(frameId: string): void;
_handleFrameTree(session: CDPSession, frameTree: Protocol.Page.FrameTree): void;
page(): Page;
mainFrame(): Frame;
frames(): Frame[];
frame(frameId: string): Frame | null;
_onFrameAttached(session: CDPSession, frameId: string, parentFrameId?: string): void;
_onFrameNavigated(framePayload: Protocol.Page.Frame): void;
_ensureIsolatedWorld(session: CDPSession, name: string): Promise<void>;
_onFrameNavigatedWithinDocument(frameId: string, url: string): void;
_onFrameDetached(frameId: string, reason: Protocol.Page.FrameDetachedEventReason): void;
_onExecutionContextCreated(contextPayload: Protocol.Runtime.ExecutionContextDescription, session: CDPSession): void;
private _onExecutionContextDestroyed;
private _onExecutionContextsCleared;
executionContextById(contextId: number, session?: CDPSession): ExecutionContext;
private _removeFramesRecursively;
}
/**
* @public
*/
export interface FrameWaitForFunctionOptions {
/**
* An interval at which the `pageFunction` is executed, defaults to `raf`. If
* `polling` is a number, then it is treated as an interval in milliseconds at
* which the function would be executed. If `polling` is a string, then it can
* be one of the following values:
*
* - `raf` - to constantly execute `pageFunction` in `requestAnimationFrame`
* callback. This is the tightest polling mode which is suitable to observe
* styling changes.
*
* - `mutation` - to execute `pageFunction` on every DOM mutation.
*/
polling?: string | number;
/**
* Maximum time to wait in milliseconds. Defaults to `30000` (30 seconds).
* Pass `0` to disable the timeout. Puppeteer's default timeout can be changed
* using {@link Page.setDefaultTimeout}.
*/
timeout?: number;
}
/**
* @public
*/
export interface FrameAddScriptTagOptions {
/**
* the URL of the script to be added.
*/
url?: string;
/**
* The path to a JavaScript file to be injected into the frame.
* @remarks
* If `path` is a relative path, it is resolved relative to the current
* working directory (`process.cwd()` in Node.js).
*/
path?: string;
/**
* Raw JavaScript content to be injected into the frame.
*/
content?: string;
/**
* Set the script's `type`. Use `module` in order to load an ES2015 module.
*/
type?: string;
}
/**
* @public
*/
export interface FrameAddStyleTagOptions {
/**
* the URL of the CSS file to be added.
*/
url?: string;
/**
* The path to a CSS file to be injected into the frame.
* @remarks
* If `path` is a relative path, it is resolved relative to the current
* working directory (`process.cwd()` in Node.js).
*/
path?: string;
/**
* Raw CSS content to be injected into the frame.
*/
content?: string;
}
/**
* At every point of time, page exposes its current frame tree via the
* {@link Page.mainFrame | page.mainFrame} and
* {@link Frame.childFrames | frame.childFrames} methods.
*
* @remarks
*
* `Frame` object lifecycles are controlled by three events that are all
* dispatched on the page object:
*
* - {@link PageEmittedEvents.FrameAttached}
*
* - {@link PageEmittedEvents.FrameNavigated}
*
* - {@link PageEmittedEvents.FrameDetached}
*
* @Example
* An example of dumping frame tree:
*
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://www.google.com/chrome/browser/canary.html');
* dumpFrameTree(page.mainFrame(), '');
* await browser.close();
*
* function dumpFrameTree(frame, indent) {
* console.log(indent + frame.url());
* for (const child of frame.childFrames()) {
* dumpFrameTree(child, indent + ' ');
* }
* }
* })();
* ```
*
* @Example
* An example of getting text from an iframe element:
*
* ```js
* const frame = page.frames().find(frame => frame.name() === 'myframe');
* const text = await frame.$eval('.selector', element => element.textContent);
* console.log(text);
* ```
*
* @public
*/
export declare class Frame {
/**
* @internal
*/
_frameManager: FrameManager;
private _parentFrame?;
/**
* @internal
*/
_id: string;
private _url;
private _detached;
/**
* @internal
*/
_loaderId: string;
/**
* @internal
*/
_name?: string;
/**
* @internal
*/
_lifecycleEvents: Set<string>;
/**
* @internal
*/
_mainWorld: DOMWorld;
/**
* @internal
*/
_secondaryWorld: DOMWorld;
/**
* @internal
*/
_childFrames: Set<Frame>;
/**
* @internal
*/
_client: CDPSession;
/**
* @internal
*/
constructor(frameManager: FrameManager, parentFrame: Frame | null, frameId: string, client: CDPSession);
/**
* @internal
*/
_updateClient(client: CDPSession): void;
/**
* @remarks
*
* @returns `true` if the frame is an OOP frame, or `false` otherwise.
*/
isOOPFrame(): boolean;
/**
* @remarks
*
* `frame.goto` will throw an error if:
* - there's an SSL error (e.g. in case of self-signed certificates).
*
* - target URL is invalid.
*
* - the `timeout` is exceeded during navigation.
*
* - the remote server does not respond or is unreachable.
*
* - the main resource failed to load.
*
* `frame.goto` will not throw an error when any valid HTTP status code is
* returned by the remote server, including 404 "Not Found" and 500 "Internal
* Server Error". The status code for such responses can be retrieved by
* calling {@link HTTPResponse.status}.
*
* NOTE: `frame.goto` either throws an error or returns a main resource
* response. The only exceptions are navigation to `about:blank` or
* navigation to the same URL with a different hash, which would succeed and
* return `null`.
*
* NOTE: Headless mode doesn't support navigation to a PDF document. See
* the {@link https://bugs.chromium.org/p/chromium/issues/detail?id=761295 | upstream
* issue}.
*
* @param url - the URL to navigate the frame to. This should include the
* scheme, e.g. `https://`.
* @param options - navigation options. `waitUntil` is useful to define when
* the navigation should be considered successful - see the docs for
* {@link PuppeteerLifeCycleEvent} for more details.
*
* @returns A promise which resolves to the main resource response. In case of
* multiple redirects, the navigation will resolve with the response of the
* last redirect.
*/
goto(url: string, options?: {
referer?: string;
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<HTTPResponse | null>;
/**
* @remarks
*
* This resolves when the frame navigates to a new URL. It is useful for when
* you run code which will indirectly cause the frame to navigate. Consider
* this example:
*
* ```js
* const [response] = await Promise.all([
* // The navigation promise resolves after navigation has finished
* frame.waitForNavigation(),
* // Clicking the link will indirectly cause a navigation
* frame.click('a.my-link'),
* ]);
* ```
*
* Usage of the {@link https://developer.mozilla.org/en-US/docs/Web/API/History_API | History API} to change the URL is considered a navigation.
*
* @param options - options to configure when the navigation is consided finished.
* @returns a promise that resolves when the frame navigates to a new URL.
*/
waitForNavigation(options?: {
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<HTTPResponse | null>;
/**
* @internal
*/
client(): CDPSession;
/**
* @returns a promise that resolves to the frame's default execution context.
*/
executionContext(): Promise<ExecutionContext>;
/**
* @remarks
*
* The only difference between {@link Frame.evaluate} and
* `frame.evaluateHandle` is that `evaluateHandle` will return the value
* wrapped in an in-page object.
*
* This method behaves identically to {@link Page.evaluateHandle} except it's
* run within the context of the `frame`, rather than the entire page.
*
* @param pageFunction - a function that is run within the frame
* @param args - arguments to be passed to the pageFunction
*/
evaluateHandle<HandlerType extends JSHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<HandlerType>;
/**
* @remarks
*
* This method behaves identically to {@link Page.evaluate} except it's run
* within the context of the `frame`, rather than the entire page.
*
* @param pageFunction - a function that is run within the frame
* @param args - arguments to be passed to the pageFunction
*/
evaluate<T extends EvaluateFn>(pageFunction: T, ...args: SerializableOrJSHandle[]): Promise<UnwrapPromiseLike<EvaluateFnReturnType<T>>>;
/**
* This method queries the frame for the given selector.
*
* @param selector - a selector to query for.
* @returns A promise which resolves to an `ElementHandle` pointing at the
* element, or `null` if it was not found.
*/
$<T extends Element = Element>(selector: string): Promise<ElementHandle<T> | null>;
/**
* This method evaluates the given XPath expression and returns the results.
*
* @param expression - the XPath expression to evaluate.
*/
$x(expression: string): Promise<ElementHandle[]>;
/**
* @remarks
*
* This method runs `document.querySelector` within
* the frame and passes it as the first argument to `pageFunction`.
*
* If `pageFunction` returns a Promise, then `frame.$eval` would wait for
* the promise to resolve and return its value.
*
* @example
*
* ```js
* const searchValue = await frame.$eval('#search', el => el.value);
* ```
*
* @param selector - the selector to query for
* @param pageFunction - the function to be evaluated in the frame's context
* @param args - additional arguments to pass to `pageFunction`
*/
$eval<ReturnType>(selector: string, pageFunction: (element: Element, ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
/**
* @remarks
*
* This method runs `Array.from(document.querySelectorAll(selector))` within
* the frame and passes it as the first argument to `pageFunction`.
*
* If `pageFunction` returns a Promise, then `frame.$$eval` would wait for
* the promise to resolve and return its value.
*
* @example
*
* ```js
* const divsCounts = await frame.$$eval('div', divs => divs.length);
* ```
*
* @param selector - the selector to query for
* @param pageFunction - the function to be evaluated in the frame's context
* @param args - additional arguments to pass to `pageFunction`
*/
$$eval<ReturnType>(selector: string, pageFunction: (elements: Element[], ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
/**
* This runs `document.querySelectorAll` in the frame and returns the result.
*
* @param selector - a selector to search for
* @returns An array of element handles pointing to the found frame elements.
*/
$$<T extends Element = Element>(selector: string): Promise<Array<ElementHandle<T>>>;
/**
* @returns the full HTML contents of the frame, including the doctype.
*/
content(): Promise<string>;
/**
* Set the content of the frame.
*
* @param html - HTML markup to assign to the page.
* @param options - options to configure how long before timing out and at
* what point to consider the content setting successful.
*/
setContent(html: string, options?: {
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<void>;
/**
* @remarks
*
* If the name is empty, it returns the `id` attribute instead.
*
* Note: This value is calculated once when the frame is created, and will not
* update if the attribute is changed later.
*
* @returns the frame's `name` attribute as specified in the tag.
*/
name(): string;
/**
* @returns the frame's URL.
*/
url(): string;
/**
* @returns the parent `Frame`, if any. Detached and main frames return `null`.
*/
parentFrame(): Frame | null;
/**
* @returns an array of child frames.
*/
childFrames(): Frame[];
/**
* @returns `true` if the frame has been detached, or `false` otherwise.
*/
isDetached(): boolean;
/**
* Adds a `<script>` tag into the page with the desired url or content.
*
* @param options - configure the script to add to the page.
*
* @returns a promise that resolves to the added tag when the script's
* `onload` event fires or when the script content was injected into the
* frame.
*/
addScriptTag(options: FrameAddScriptTagOptions): Promise<ElementHandle>;
/**
* Adds a `<link rel="stylesheet">` tag into the page with the desired url or
* a `<style type="text/css">` tag with the content.
*
* @param options - configure the CSS to add to the page.
*
* @returns a promise that resolves to the added tag when the stylesheets's
* `onload` event fires or when the CSS content was injected into the
* frame.
*/
addStyleTag(options: FrameAddStyleTagOptions): Promise<ElementHandle>;
/**
*
* This method clicks the first element found that matches `selector`.
*
* @remarks
*
* This method scrolls the element into view if needed, and then uses
* {@link Page.mouse} to click in the center of the element. If there's no
* element matching `selector`, the method throws an error.
*
* Bear in mind that if `click()` triggers a navigation event and there's a
* separate `page.waitForNavigation()` promise to be resolved, you may end up
* with a race condition that yields unexpected results. The correct pattern
* for click and wait for navigation is the following:
*
* ```javascript
* const [response] = await Promise.all([
* page.waitForNavigation(waitOptions),
* frame.click(selector, clickOptions),
* ]);
* ```
* @param selector - the selector to search for to click. If there are
* multiple elements, the first will be clicked.
*/
click(selector: string, options?: {
delay?: number;
button?: MouseButton;
clickCount?: number;
}): Promise<void>;
/**
* This method fetches an element with `selector` and focuses it.
*
* @remarks
* If there's no element matching `selector`, the method throws an error.
*
* @param selector - the selector for the element to focus. If there are
* multiple elements, the first will be focused.
*/
focus(selector: string): Promise<void>;
/**
* This method fetches an element with `selector`, scrolls it into view if
* needed, and then uses {@link Page.mouse} to hover over the center of the
* element.
*
* @remarks
* If there's no element matching `selector`, the method throws an
*
* @param selector - the selector for the element to hover. If there are
* multiple elements, the first will be hovered.
*/
hover(selector: string): Promise<void>;
/**
* Triggers a `change` and `input` event once all the provided options have
* been selected.
*
* @remarks
*
* If there's no `<select>` element matching `selector`, the
* method throws an error.
*
* @example
* ```js
* frame.select('select#colors', 'blue'); // single selection
* frame.select('select#colors', 'red', 'green', 'blue'); // multiple selections
* ```
*
* @param selector - a selector to query the frame for
* @param values - an array of values to select. If the `<select>` has the
* `multiple` attribute, all values are considered, otherwise only the first
* one is taken into account.
* @returns the list of values that were successfully selected.
*/
select(selector: string, ...values: string[]): Promise<string[]>;
/**
* This method fetches an element with `selector`, scrolls it into view if
* needed, and then uses {@link Page.touchscreen} to tap in the center of the
* element.
*
* @remarks
*
* If there's no element matching `selector`, the method throws an error.
*
* @param selector - the selector to tap.
* @returns a promise that resolves when the element has been tapped.
*/
tap(selector: string): Promise<void>;
/**
* Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character
* in the text.
*
* @remarks
* To press a special key, like `Control` or `ArrowDown`, use
* {@link Keyboard.press}.
*
* @example
* ```js
* await frame.type('#mytextarea', 'Hello'); // Types instantly
* await frame.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user
* ```
*
* @param selector - the selector for the element to type into. If there are
* multiple the first will be used.
* @param text - text to type into the element
* @param options - takes one option, `delay`, which sets the time to wait
* between key presses in milliseconds. Defaults to `0`.
*
* @returns a promise that resolves when the typing is complete.
*/
type(selector: string, text: string, options?: {
delay: number;
}): Promise<void>;
/**
* @remarks
*
* This method behaves differently depending on the first parameter. If it's a
* `string`, it will be treated as a `selector` or `xpath` (if the string
* starts with `//`). This method then is a shortcut for
* {@link Frame.waitForSelector} or {@link Frame.waitForXPath}.
*
* If the first argument is a function this method is a shortcut for
* {@link Frame.waitForFunction}.
*
* If the first argument is a `number`, it's treated as a timeout in
* milliseconds and the method returns a promise which resolves after the
* timeout.
*
* @param selectorOrFunctionOrTimeout - a selector, predicate or timeout to
* wait for.
* @param options - optional waiting parameters.
* @param args - arguments to pass to `pageFunction`.
*
* @deprecated Don't use this method directly. Instead use the more explicit
* methods available: {@link Frame.waitForSelector},
* {@link Frame.waitForXPath}, {@link Frame.waitForFunction} or
* {@link Frame.waitForTimeout}.
*/
waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: Record<string, unknown>, ...args: SerializableOrJSHandle[]): Promise<JSHandle | null>;
/**
* Causes your script to wait for the given number of milliseconds.
*
* @remarks
* It's generally recommended to not wait for a number of seconds, but instead
* use {@link Frame.waitForSelector}, {@link Frame.waitForXPath} or
* {@link Frame.waitForFunction} to wait for exactly the conditions you want.
*
* @example
*
* Wait for 1 second:
*
* ```
* await frame.waitForTimeout(1000);
* ```
*
* @param milliseconds - the number of milliseconds to wait.
*/
waitForTimeout(milliseconds: number): Promise<void>;
/**
* @remarks
*
*
* Wait for the `selector` to appear in page. If at the moment of calling the
* method the `selector` already exists, the method will return immediately.
* If the selector doesn't appear after the `timeout` milliseconds of waiting,
* the function will throw.
*
* This method works across navigations.
*
* @example
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* let currentURL;
* page.mainFrame()
* .waitForSelector('img')
* .then(() => console.log('First URL with image: ' + currentURL));
*
* for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com']) {
* await page.goto(currentURL);
* }
* await browser.close();
* })();
* ```
* @param selector - the selector to wait for.
* @param options - options to define if the element should be visible and how
* long to wait before timing out.
* @returns a promise which resolves when an element matching the selector
* string is added to the DOM.
*/
waitForSelector(selector: string, options?: WaitForSelectorOptions): Promise<ElementHandle | null>;
/**
* @remarks
* Wait for the `xpath` to appear in page. If at the moment of calling the
* method the `xpath` already exists, the method will return immediately. If
* the xpath doesn't appear after the `timeout` milliseconds of waiting, the
* function will throw.
*
* For a code example, see the example for {@link Frame.waitForSelector}. That
* function behaves identically other than taking a CSS selector rather than
* an XPath.
*
* @param xpath - the XPath expression to wait for.
* @param options - options to configure the visiblity of the element and how
* long to wait before timing out.
*/
waitForXPath(xpath: string, options?: WaitForSelectorOptions): Promise<ElementHandle | null>;
/**
* @remarks
*
* @example
*
* The `waitForFunction` can be used to observe viewport size change:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* . const browser = await puppeteer.launch();
* . const page = await browser.newPage();
* . const watchDog = page.mainFrame().waitForFunction('window.innerWidth < 100');
* . page.setViewport({width: 50, height: 50});
* . await watchDog;
* . await browser.close();
* })();
* ```
*
* To pass arguments from Node.js to the predicate of `page.waitForFunction` function:
*
* ```js
* const selector = '.foo';
* await frame.waitForFunction(
* selector => !!document.querySelector(selector),
* {}, // empty options object
* selector
*);
* ```
*
* @param pageFunction - the function to evaluate in the frame context.
* @param options - options to configure the polling method and timeout.
* @param args - arguments to pass to the `pageFunction`.
* @returns the promise which resolve when the `pageFunction` returns a truthy value.
*/
waitForFunction(pageFunction: Function | string, options?: FrameWaitForFunctionOptions, ...args: SerializableOrJSHandle[]): Promise<JSHandle>;
/**
* @returns the frame's title.
*/
title(): Promise<string>;
/**
* @internal
*/
_navigated(framePayload: Protocol.Page.Frame): void;
/**
* @internal
*/
_navigatedWithinDocument(url: string): void;
/**
* @internal
*/
_onLifecycleEvent(loaderId: string, name: string): void;
/**
* @internal
*/
_onLoadingStopped(): void;
/**
* @internal
*/
_detach(): void;
}
//# sourceMappingURL=FrameManager.d.ts.map

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,387 @@
/// <reference types="node" />
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';
import { EventEmitter } from './EventEmitter.js';
import { Frame } from './FrameManager.js';
import { HTTPResponse } from './HTTPResponse.js';
import { Protocol } from 'devtools-protocol';
/**
* @public
*/
export interface ContinueRequestOverrides {
/**
* If set, the request URL will change. This is not a redirect.
*/
url?: string;
method?: string;
postData?: string;
headers?: Record<string, string>;
}
/**
* @public
*/
export interface InterceptResolutionState {
action: InterceptResolutionAction;
priority?: number;
}
/**
* Required response data to fulfill a request with.
*
* @public
*/
export interface ResponseForRequest {
status: number;
/**
* Optional response headers. All values are converted to strings.
*/
headers: Record<string, unknown>;
contentType: string;
body: string | Buffer;
}
/**
* Resource types for HTTPRequests as perceived by the rendering engine.
*
* @public
*/
export declare type ResourceType = Lowercase<Protocol.Network.ResourceType>;
/**
* The default cooperative request interception resolution priority
*
* @public
*/
export declare const DEFAULT_INTERCEPT_RESOLUTION_PRIORITY = 0;
interface CDPSession extends EventEmitter {
send<T extends keyof ProtocolMapping.Commands>(method: T, ...paramArgs: ProtocolMapping.Commands[T]['paramsType']): Promise<ProtocolMapping.Commands[T]['returnType']>;
}
/**
*
* Represents an HTTP request sent by a page.
* @remarks
*
* Whenever the page sends a request, such as for a network resource, the
* following events are emitted by Puppeteer's `page`:
*
* - `request`: emitted when the request is issued by the page.
* - `requestfinished` - emitted when the response body is downloaded and the
* request is complete.
*
* If request fails at some point, then instead of `requestfinished` event the
* `requestfailed` event is emitted.
*
* All of these events provide an instance of `HTTPRequest` representing the
* request that occurred:
*
* ```
* page.on('request', request => ...)
* ```
*
* NOTE: HTTP Error responses, such as 404 or 503, are still successful
* responses from HTTP standpoint, so request will complete with
* `requestfinished` event.
*
* If request gets a 'redirect' response, the request is successfully finished
* with the `requestfinished` event, and a new request is issued to a
* redirected url.
*
* @public
*/
export declare class HTTPRequest {
/**
* @internal
*/
_requestId: string;
/**
* @internal
*/
_interceptionId: string;
/**
* @internal
*/
_failureText: any;
/**
* @internal
*/
_response: HTTPResponse | null;
/**
* @internal
*/
_fromMemoryCache: boolean;
/**
* @internal
*/
_redirectChain: HTTPRequest[];
private _client;
private _isNavigationRequest;
private _allowInterception;
private _interceptionHandled;
private _url;
private _resourceType;
private _method;
private _postData?;
private _headers;
private _frame;
private _continueRequestOverrides;
private _responseForRequest;
private _abortErrorReason;
private _interceptResolutionState;
private _interceptHandlers;
private _initiator;
/**
* @internal
*/
constructor(client: CDPSession, frame: Frame, interceptionId: string, allowInterception: boolean, event: Protocol.Network.RequestWillBeSentEvent, redirectChain: HTTPRequest[]);
/**
* @returns the URL of the request
*/
url(): string;
/**
* @returns the `ContinueRequestOverrides` that will be used
* if the interception is allowed to continue (ie, `abort()` and
* `respond()` aren't called).
*/
continueRequestOverrides(): ContinueRequestOverrides;
/**
* @returns The `ResponseForRequest` that gets used if the
* interception is allowed to respond (ie, `abort()` is not called).
*/
responseForRequest(): Partial<ResponseForRequest>;
/**
* @returns the most recent reason for aborting the request
*/
abortErrorReason(): Protocol.Network.ErrorReason;
/**
* @returns An InterceptResolutionState object describing the current resolution
* action and priority.
*
* InterceptResolutionState contains:
* action: InterceptResolutionAction
* priority?: number
*
* InterceptResolutionAction is one of: `abort`, `respond`, `continue`,
* `disabled`, `none`, or `already-handled`.
*/
interceptResolutionState(): InterceptResolutionState;
/**
* @returns `true` if the intercept resolution has already been handled,
* `false` otherwise.
*/
isInterceptResolutionHandled(): boolean;
/**
* Adds an async request handler to the processing queue.
* Deferred handlers are not guaranteed to execute in any particular order,
* but they are guaranteed to resolve before the request interception
* is finalized.
*/
enqueueInterceptAction(pendingHandler: () => void | PromiseLike<unknown>): void;
/**
* Awaits pending interception handlers and then decides how to fulfill
* the request interception.
*/
finalizeInterceptions(): Promise<void>;
/**
* Contains the request's resource type as it was perceived by the rendering
* engine.
*/
resourceType(): ResourceType;
/**
* @returns the method used (`GET`, `POST`, etc.)
*/
method(): string;
/**
* @returns the request's post body, if any.
*/
postData(): string | undefined;
/**
* @returns an object with HTTP headers associated with the request. All
* header names are lower-case.
*/
headers(): Record<string, string>;
/**
* @returns A matching `HTTPResponse` object, or null if the response has not
* been received yet.
*/
response(): HTTPResponse | null;
/**
* @returns the frame that initiated the request, or null if navigating to
* error pages.
*/
frame(): Frame | null;
/**
* @returns true if the request is the driver of the current frame's navigation.
*/
isNavigationRequest(): boolean;
/**
* @returns the initiator of the request.
*/
initiator(): Protocol.Network.Initiator;
/**
* A `redirectChain` is a chain of requests initiated to fetch a resource.
* @remarks
*
* `redirectChain` is shared between all the requests of the same chain.
*
* For example, if the website `http://example.com` has a single redirect to
* `https://example.com`, then the chain will contain one request:
*
* ```js
* const response = await page.goto('http://example.com');
* const chain = response.request().redirectChain();
* console.log(chain.length); // 1
* console.log(chain[0].url()); // 'http://example.com'
* ```
*
* If the website `https://google.com` has no redirects, then the chain will be empty:
*
* ```js
* const response = await page.goto('https://google.com');
* const chain = response.request().redirectChain();
* console.log(chain.length); // 0
* ```
*
* @returns the chain of requests - if a server responds with at least a
* single redirect, this chain will contain all requests that were redirected.
*/
redirectChain(): HTTPRequest[];
/**
* Access information about the request's failure.
*
* @remarks
*
* @example
*
* Example of logging all failed requests:
*
* ```js
* page.on('requestfailed', request => {
* console.log(request.url() + ' ' + request.failure().errorText);
* });
* ```
*
* @returns `null` unless the request failed. If the request fails this can
* return an object with `errorText` containing a human-readable error
* message, e.g. `net::ERR_FAILED`. It is not guaranteed that there will be
* failure text if the request fails.
*/
failure(): {
errorText: string;
} | null;
/**
* Continues request with optional request overrides.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example
* ```js
* await page.setRequestInterception(true);
* page.on('request', request => {
* // Override headers
* const headers = Object.assign({}, request.headers(), {
* foo: 'bar', // set "foo" header
* origin: undefined, // remove "origin" header
* });
* request.continue({headers});
* });
* ```
*
* @param overrides - optional overrides to apply to the request.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
continue(overrides?: ContinueRequestOverrides, priority?: number): Promise<void>;
private _continue;
/**
* Fulfills a request with the given response.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example
* An example of fulfilling all requests with 404 responses:
* ```js
* await page.setRequestInterception(true);
* page.on('request', request => {
* request.respond({
* status: 404,
* contentType: 'text/plain',
* body: 'Not Found!'
* });
* });
* ```
*
* NOTE: Mocking responses for dataURL requests is not supported.
* Calling `request.respond` for a dataURL request is a noop.
*
* @param response - the response to fulfill the request with.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
respond(response: Partial<ResponseForRequest>, priority?: number): Promise<void>;
private _respond;
/**
* Aborts a request.
*
* @remarks
* To use this, request interception should be enabled with
* {@link Page.setRequestInterception}. If it is not enabled, this method will
* throw an exception immediately.
*
* @param errorCode - optional error code to provide.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
abort(errorCode?: ErrorCode, priority?: number): Promise<void>;
private _abort;
}
/**
* @public
*/
export declare enum InterceptResolutionAction {
Abort = "abort",
Respond = "respond",
Continue = "continue",
Disabled = "disabled",
None = "none",
AlreadyHandled = "already-handled"
}
/**
* @public
*
* @deprecated please use {@link InterceptResolutionAction} instead.
*/
export declare type InterceptResolutionStrategy = InterceptResolutionAction;
/**
* @public
*/
export declare type ErrorCode = 'aborted' | 'accessdenied' | 'addressunreachable' | 'blockedbyclient' | 'blockedbyresponse' | 'connectionaborted' | 'connectionclosed' | 'connectionfailed' | 'connectionrefused' | 'connectionreset' | 'internetdisconnected' | 'namenotresolved' | 'timedout' | 'failed';
/**
* @public
*/
export declare type ActionResult = 'continue' | 'abort' | 'respond';
export {};
//# sourceMappingURL=HTTPRequest.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTTPRequest.d.ts","sourceRoot":"","sources":["../../../../src/common/HTTPRequest.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,yBAAyB,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,oBAAY,YAAY,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;AAEpE;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,IAAI,CAAC;AAEvD,UAAU,UAAW,SAAQ,YAAY;IACvC,IAAI,CAAC,CAAC,SAAS,MAAM,eAAe,CAAC,QAAQ,EAC3C,MAAM,EAAE,CAAC,EACT,GAAG,SAAS,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GACtD,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,WAAW;IACtB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,YAAY,MAAQ;IACpB;;OAEG;IACH,SAAS,EAAE,YAAY,GAAG,IAAI,CAAQ;IACtC;;OAEG;IACH,gBAAgB,UAAS;IACzB;;OAEG;IACH,cAAc,EAAE,WAAW,EAAE,CAAC;IAE9B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,oBAAoB,CAAU;IACtC,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,aAAa,CAAe;IAEpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,yBAAyB,CAA2B;IAC5D,OAAO,CAAC,mBAAmB,CAA8B;IACzD,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,yBAAyB,CAA2B;IAC5D,OAAO,CAAC,kBAAkB,CAAuC;IACjE,OAAO,CAAC,UAAU,CAA6B;IAE/C;;OAEG;gBAED,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,KAAK,EACZ,cAAc,EAAE,MAAM,EACtB,iBAAiB,EAAE,OAAO,EAC1B,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,sBAAsB,EAC9C,aAAa,EAAE,WAAW,EAAE;IAuB9B;;OAEG;IACH,GAAG,IAAI,MAAM;IAIb;;;;OAIG;IACH,wBAAwB,IAAI,wBAAwB;IAKpD;;;OAGG;IACH,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKjD;;OAEG;IACH,gBAAgB,IAAI,QAAQ,CAAC,OAAO,CAAC,WAAW;IAKhD;;;;;;;;;;OAUG;IACH,wBAAwB,IAAI,wBAAwB;IAQpD;;;OAGG;IACH,4BAA4B,IAAI,OAAO;IAIvC;;;;;OAKG;IACH,sBAAsB,CACpB,cAAc,EAAE,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,GAChD,IAAI;IAIP;;;OAGG;IACG,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5C;;;OAGG;IACH,YAAY,IAAI,YAAY;IAI5B;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B;;;OAGG;IACH,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIjC;;;OAGG;IACH,QAAQ,IAAI,YAAY,GAAG,IAAI;IAI/B;;;OAGG;IACH,KAAK,IAAI,KAAK,GAAG,IAAI;IAIrB;;OAEG;IACH,mBAAmB,IAAI,OAAO;IAI9B;;OAEG;IACH,SAAS,IAAI,QAAQ,CAAC,OAAO,CAAC,SAAS;IAIvC;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,aAAa,IAAI,WAAW,EAAE;IAI9B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,IAAI;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAOvC;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACG,QAAQ,CACZ,SAAS,GAAE,wBAA6B,EACxC,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;YAgCF,SAAS;IAwBvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACG,OAAO,CACX,QAAQ,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACrC,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;YA2BF,QAAQ;IAuCtB;;;;;;;;;;;;OAYG;IACG,KAAK,CACT,SAAS,GAAE,SAAoB,EAC/B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;YAuBF,MAAM;CAWrB;AAED;;GAEG;AACH,oBAAY,yBAAyB;IACnC,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,IAAI,SAAS;IACb,cAAc,oBAAoB;CACnC;AAED;;;;GAIG;AACH,oBAAY,2BAA2B,GAAG,yBAAyB,CAAC;AAEpE;;GAEG;AACH,oBAAY,SAAS,GACjB,SAAS,GACT,cAAc,GACd,oBAAoB,GACpB,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,GACnB,kBAAkB,GAClB,kBAAkB,GAClB,mBAAmB,GACnB,iBAAiB,GACjB,sBAAsB,GACtB,iBAAiB,GACjB,UAAU,GACV,QAAQ,CAAC;AAmBb;;GAEG;AACH,oBAAY,YAAY,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC"}

View File

@@ -0,0 +1,594 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InterceptResolutionAction = exports.HTTPRequest = exports.DEFAULT_INTERCEPT_RESOLUTION_PRIORITY = void 0;
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("./helper.js");
/**
* The default cooperative request interception resolution priority
*
* @public
*/
exports.DEFAULT_INTERCEPT_RESOLUTION_PRIORITY = 0;
/**
*
* Represents an HTTP request sent by a page.
* @remarks
*
* Whenever the page sends a request, such as for a network resource, the
* following events are emitted by Puppeteer's `page`:
*
* - `request`: emitted when the request is issued by the page.
* - `requestfinished` - emitted when the response body is downloaded and the
* request is complete.
*
* If request fails at some point, then instead of `requestfinished` event the
* `requestfailed` event is emitted.
*
* All of these events provide an instance of `HTTPRequest` representing the
* request that occurred:
*
* ```
* page.on('request', request => ...)
* ```
*
* NOTE: HTTP Error responses, such as 404 or 503, are still successful
* responses from HTTP standpoint, so request will complete with
* `requestfinished` event.
*
* If request gets a 'redirect' response, the request is successfully finished
* with the `requestfinished` event, and a new request is issued to a
* redirected url.
*
* @public
*/
class HTTPRequest {
/**
* @internal
*/
constructor(client, frame, interceptionId, allowInterception, event, redirectChain) {
/**
* @internal
*/
this._failureText = null;
/**
* @internal
*/
this._response = null;
/**
* @internal
*/
this._fromMemoryCache = false;
this._interceptionHandled = false;
this._headers = {};
this._client = client;
this._requestId = event.requestId;
this._isNavigationRequest =
event.requestId === event.loaderId && event.type === 'Document';
this._interceptionId = interceptionId;
this._allowInterception = allowInterception;
this._url = event.request.url;
this._resourceType = event.type.toLowerCase();
this._method = event.request.method;
this._postData = event.request.postData;
this._frame = frame;
this._redirectChain = redirectChain;
this._continueRequestOverrides = {};
this._interceptResolutionState = { action: InterceptResolutionAction.None };
this._interceptHandlers = [];
this._initiator = event.initiator;
for (const key of Object.keys(event.request.headers))
this._headers[key.toLowerCase()] = event.request.headers[key];
}
/**
* @returns the URL of the request
*/
url() {
return this._url;
}
/**
* @returns the `ContinueRequestOverrides` that will be used
* if the interception is allowed to continue (ie, `abort()` and
* `respond()` aren't called).
*/
continueRequestOverrides() {
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
return this._continueRequestOverrides;
}
/**
* @returns The `ResponseForRequest` that gets used if the
* interception is allowed to respond (ie, `abort()` is not called).
*/
responseForRequest() {
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
return this._responseForRequest;
}
/**
* @returns the most recent reason for aborting the request
*/
abortErrorReason() {
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
return this._abortErrorReason;
}
/**
* @returns An InterceptResolutionState object describing the current resolution
* action and priority.
*
* InterceptResolutionState contains:
* action: InterceptResolutionAction
* priority?: number
*
* InterceptResolutionAction is one of: `abort`, `respond`, `continue`,
* `disabled`, `none`, or `already-handled`.
*/
interceptResolutionState() {
if (!this._allowInterception)
return { action: InterceptResolutionAction.Disabled };
if (this._interceptionHandled)
return { action: InterceptResolutionAction.AlreadyHandled };
return { ...this._interceptResolutionState };
}
/**
* @returns `true` if the intercept resolution has already been handled,
* `false` otherwise.
*/
isInterceptResolutionHandled() {
return this._interceptionHandled;
}
/**
* Adds an async request handler to the processing queue.
* Deferred handlers are not guaranteed to execute in any particular order,
* but they are guaranteed to resolve before the request interception
* is finalized.
*/
enqueueInterceptAction(pendingHandler) {
this._interceptHandlers.push(pendingHandler);
}
/**
* Awaits pending interception handlers and then decides how to fulfill
* the request interception.
*/
async finalizeInterceptions() {
await this._interceptHandlers.reduce((promiseChain, interceptAction) => promiseChain.then(interceptAction), Promise.resolve());
const { action } = this.interceptResolutionState();
switch (action) {
case 'abort':
return this._abort(this._abortErrorReason);
case 'respond':
return this._respond(this._responseForRequest);
case 'continue':
return this._continue(this._continueRequestOverrides);
}
}
/**
* Contains the request's resource type as it was perceived by the rendering
* engine.
*/
resourceType() {
return this._resourceType;
}
/**
* @returns the method used (`GET`, `POST`, etc.)
*/
method() {
return this._method;
}
/**
* @returns the request's post body, if any.
*/
postData() {
return this._postData;
}
/**
* @returns an object with HTTP headers associated with the request. All
* header names are lower-case.
*/
headers() {
return this._headers;
}
/**
* @returns A matching `HTTPResponse` object, or null if the response has not
* been received yet.
*/
response() {
return this._response;
}
/**
* @returns the frame that initiated the request, or null if navigating to
* error pages.
*/
frame() {
return this._frame;
}
/**
* @returns true if the request is the driver of the current frame's navigation.
*/
isNavigationRequest() {
return this._isNavigationRequest;
}
/**
* @returns the initiator of the request.
*/
initiator() {
return this._initiator;
}
/**
* A `redirectChain` is a chain of requests initiated to fetch a resource.
* @remarks
*
* `redirectChain` is shared between all the requests of the same chain.
*
* For example, if the website `http://example.com` has a single redirect to
* `https://example.com`, then the chain will contain one request:
*
* ```js
* const response = await page.goto('http://example.com');
* const chain = response.request().redirectChain();
* console.log(chain.length); // 1
* console.log(chain[0].url()); // 'http://example.com'
* ```
*
* If the website `https://google.com` has no redirects, then the chain will be empty:
*
* ```js
* const response = await page.goto('https://google.com');
* const chain = response.request().redirectChain();
* console.log(chain.length); // 0
* ```
*
* @returns the chain of requests - if a server responds with at least a
* single redirect, this chain will contain all requests that were redirected.
*/
redirectChain() {
return this._redirectChain.slice();
}
/**
* Access information about the request's failure.
*
* @remarks
*
* @example
*
* Example of logging all failed requests:
*
* ```js
* page.on('requestfailed', request => {
* console.log(request.url() + ' ' + request.failure().errorText);
* });
* ```
*
* @returns `null` unless the request failed. If the request fails this can
* return an object with `errorText` containing a human-readable error
* message, e.g. `net::ERR_FAILED`. It is not guaranteed that there will be
* failure text if the request fails.
*/
failure() {
if (!this._failureText)
return null;
return {
errorText: this._failureText,
};
}
/**
* Continues request with optional request overrides.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example
* ```js
* await page.setRequestInterception(true);
* page.on('request', request => {
* // Override headers
* const headers = Object.assign({}, request.headers(), {
* foo: 'bar', // set "foo" header
* origin: undefined, // remove "origin" header
* });
* request.continue({headers});
* });
* ```
*
* @param overrides - optional overrides to apply to the request.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
async continue(overrides = {}, priority) {
// Request interception is not supported for data: urls.
if (this._url.startsWith('data:'))
return;
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
(0, assert_js_1.assert)(!this._interceptionHandled, 'Request is already handled!');
if (priority === undefined) {
return this._continue(overrides);
}
this._continueRequestOverrides = overrides;
if (priority > this._interceptResolutionState.priority ||
this._interceptResolutionState.priority === undefined) {
this._interceptResolutionState = {
action: InterceptResolutionAction.Continue,
priority,
};
return;
}
if (priority === this._interceptResolutionState.priority) {
if (this._interceptResolutionState.action === 'abort' ||
this._interceptResolutionState.action === 'respond') {
return;
}
this._interceptResolutionState.action =
InterceptResolutionAction.Continue;
}
return;
}
async _continue(overrides = {}) {
const { url, method, postData, headers } = overrides;
this._interceptionHandled = true;
const postDataBinaryBase64 = postData
? Buffer.from(postData).toString('base64')
: undefined;
await this._client
.send('Fetch.continueRequest', {
requestId: this._interceptionId,
url,
method,
postData: postDataBinaryBase64,
headers: headers ? headersArray(headers) : undefined,
})
.catch((error) => {
this._interceptionHandled = false;
return handleError(error);
});
}
/**
* Fulfills a request with the given response.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example
* An example of fulfilling all requests with 404 responses:
* ```js
* await page.setRequestInterception(true);
* page.on('request', request => {
* request.respond({
* status: 404,
* contentType: 'text/plain',
* body: 'Not Found!'
* });
* });
* ```
*
* NOTE: Mocking responses for dataURL requests is not supported.
* Calling `request.respond` for a dataURL request is a noop.
*
* @param response - the response to fulfill the request with.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
async respond(response, priority) {
// Mocking responses for dataURL requests is not currently supported.
if (this._url.startsWith('data:'))
return;
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
(0, assert_js_1.assert)(!this._interceptionHandled, 'Request is already handled!');
if (priority === undefined) {
return this._respond(response);
}
this._responseForRequest = response;
if (priority > this._interceptResolutionState.priority ||
this._interceptResolutionState.priority === undefined) {
this._interceptResolutionState = {
action: InterceptResolutionAction.Respond,
priority,
};
return;
}
if (priority === this._interceptResolutionState.priority) {
if (this._interceptResolutionState.action === 'abort') {
return;
}
this._interceptResolutionState.action = InterceptResolutionAction.Respond;
}
}
async _respond(response) {
this._interceptionHandled = true;
const responseBody = response.body && helper_js_1.helper.isString(response.body)
? Buffer.from(response.body)
: response.body || null;
const responseHeaders = {};
if (response.headers) {
for (const header of Object.keys(response.headers)) {
const value = response.headers[header];
responseHeaders[header.toLowerCase()] = Array.isArray(value)
? value.map((item) => String(item))
: String(value);
}
}
if (response.contentType)
responseHeaders['content-type'] = response.contentType;
if (responseBody && !('content-length' in responseHeaders))
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
await this._client
.send('Fetch.fulfillRequest', {
requestId: this._interceptionId,
responseCode: response.status || 200,
responsePhrase: STATUS_TEXTS[response.status || 200],
responseHeaders: headersArray(responseHeaders),
body: responseBody ? responseBody.toString('base64') : undefined,
})
.catch((error) => {
this._interceptionHandled = false;
return handleError(error);
});
}
/**
* Aborts a request.
*
* @remarks
* To use this, request interception should be enabled with
* {@link Page.setRequestInterception}. If it is not enabled, this method will
* throw an exception immediately.
*
* @param errorCode - optional error code to provide.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
async abort(errorCode = 'failed', priority) {
// Request interception is not supported for data: urls.
if (this._url.startsWith('data:'))
return;
const errorReason = errorReasons[errorCode];
(0, assert_js_1.assert)(errorReason, 'Unknown error code: ' + errorCode);
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
(0, assert_js_1.assert)(!this._interceptionHandled, 'Request is already handled!');
if (priority === undefined) {
return this._abort(errorReason);
}
this._abortErrorReason = errorReason;
if (priority >= this._interceptResolutionState.priority ||
this._interceptResolutionState.priority === undefined) {
this._interceptResolutionState = {
action: InterceptResolutionAction.Abort,
priority,
};
return;
}
}
async _abort(errorReason) {
this._interceptionHandled = true;
await this._client
.send('Fetch.failRequest', {
requestId: this._interceptionId,
errorReason,
})
.catch(handleError);
}
}
exports.HTTPRequest = HTTPRequest;
/**
* @public
*/
var InterceptResolutionAction;
(function (InterceptResolutionAction) {
InterceptResolutionAction["Abort"] = "abort";
InterceptResolutionAction["Respond"] = "respond";
InterceptResolutionAction["Continue"] = "continue";
InterceptResolutionAction["Disabled"] = "disabled";
InterceptResolutionAction["None"] = "none";
InterceptResolutionAction["AlreadyHandled"] = "already-handled";
})(InterceptResolutionAction = exports.InterceptResolutionAction || (exports.InterceptResolutionAction = {}));
const errorReasons = {
aborted: 'Aborted',
accessdenied: 'AccessDenied',
addressunreachable: 'AddressUnreachable',
blockedbyclient: 'BlockedByClient',
blockedbyresponse: 'BlockedByResponse',
connectionaborted: 'ConnectionAborted',
connectionclosed: 'ConnectionClosed',
connectionfailed: 'ConnectionFailed',
connectionrefused: 'ConnectionRefused',
connectionreset: 'ConnectionReset',
internetdisconnected: 'InternetDisconnected',
namenotresolved: 'NameNotResolved',
timedout: 'TimedOut',
failed: 'Failed',
};
function headersArray(headers) {
const result = [];
for (const name in headers) {
const value = headers[name];
if (!Object.is(value, undefined)) {
const values = Array.isArray(value) ? value : [value];
result.push(...values.map((value) => ({ name, value: value + '' })));
}
}
return result;
}
async function handleError(error) {
if (['Invalid header'].includes(error.originalMessage)) {
throw error;
}
// In certain cases, protocol will return error if the request was
// already canceled or the page was closed. We should tolerate these
// errors.
(0, helper_js_1.debugError)(error);
}
// List taken from
// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
// with extra 306 and 418 codes.
const STATUS_TEXTS = {
'100': 'Continue',
'101': 'Switching Protocols',
'102': 'Processing',
'103': 'Early Hints',
'200': 'OK',
'201': 'Created',
'202': 'Accepted',
'203': 'Non-Authoritative Information',
'204': 'No Content',
'205': 'Reset Content',
'206': 'Partial Content',
'207': 'Multi-Status',
'208': 'Already Reported',
'226': 'IM Used',
'300': 'Multiple Choices',
'301': 'Moved Permanently',
'302': 'Found',
'303': 'See Other',
'304': 'Not Modified',
'305': 'Use Proxy',
'306': 'Switch Proxy',
'307': 'Temporary Redirect',
'308': 'Permanent Redirect',
'400': 'Bad Request',
'401': 'Unauthorized',
'402': 'Payment Required',
'403': 'Forbidden',
'404': 'Not Found',
'405': 'Method Not Allowed',
'406': 'Not Acceptable',
'407': 'Proxy Authentication Required',
'408': 'Request Timeout',
'409': 'Conflict',
'410': 'Gone',
'411': 'Length Required',
'412': 'Precondition Failed',
'413': 'Payload Too Large',
'414': 'URI Too Long',
'415': 'Unsupported Media Type',
'416': 'Range Not Satisfiable',
'417': 'Expectation Failed',
'418': "I'm a teapot",
'421': 'Misdirected Request',
'422': 'Unprocessable Entity',
'423': 'Locked',
'424': 'Failed Dependency',
'425': 'Too Early',
'426': 'Upgrade Required',
'428': 'Precondition Required',
'429': 'Too Many Requests',
'431': 'Request Header Fields Too Large',
'451': 'Unavailable For Legal Reasons',
'500': 'Internal Server Error',
'501': 'Not Implemented',
'502': 'Bad Gateway',
'503': 'Service Unavailable',
'504': 'Gateway Timeout',
'505': 'HTTP Version Not Supported',
'506': 'Variant Also Negotiates',
'507': 'Insufficient Storage',
'508': 'Loop Detected',
'510': 'Not Extended',
'511': 'Network Authentication Required',
};
//# sourceMappingURL=HTTPRequest.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,140 @@
/// <reference types="node" />
/**
* Copyright 2020 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';
import { EventEmitter } from './EventEmitter.js';
import { Frame } from './FrameManager.js';
import { HTTPRequest } from './HTTPRequest.js';
import { SecurityDetails } from './SecurityDetails.js';
import { Protocol } from 'devtools-protocol';
/**
* @public
*/
export interface RemoteAddress {
ip: string;
port: number;
}
interface CDPSession extends EventEmitter {
send<T extends keyof ProtocolMapping.Commands>(method: T, ...paramArgs: ProtocolMapping.Commands[T]['paramsType']): Promise<ProtocolMapping.Commands[T]['returnType']>;
}
/**
* The HTTPResponse class represents responses which are received by the
* {@link Page} class.
*
* @public
*/
export declare class HTTPResponse {
private _client;
private _request;
private _contentPromise;
private _bodyLoadedPromise;
private _bodyLoadedPromiseFulfill;
private _remoteAddress;
private _status;
private _statusText;
private _url;
private _fromDiskCache;
private _fromServiceWorker;
private _headers;
private _securityDetails;
private _timing;
/**
* @internal
*/
constructor(client: CDPSession, request: HTTPRequest, responsePayload: Protocol.Network.Response, extraInfo: Protocol.Network.ResponseReceivedExtraInfoEvent | null);
/**
* @internal
*/
_parseStatusTextFromExtrInfo(extraInfo: Protocol.Network.ResponseReceivedExtraInfoEvent | null): string | undefined;
/**
* @internal
*/
_resolveBody(err: Error | null): void;
/**
* @returns The IP address and port number used to connect to the remote
* server.
*/
remoteAddress(): RemoteAddress;
/**
* @returns The URL of the response.
*/
url(): string;
/**
* @returns True if the response was successful (status in the range 200-299).
*/
ok(): boolean;
/**
* @returns The status code of the response (e.g., 200 for a success).
*/
status(): number;
/**
* @returns The status text of the response (e.g. usually an "OK" for a
* success).
*/
statusText(): string;
/**
* @returns An object with HTTP headers associated with the response. All
* header names are lower-case.
*/
headers(): Record<string, string>;
/**
* @returns {@link SecurityDetails} if the response was received over the
* secure connection, or `null` otherwise.
*/
securityDetails(): SecurityDetails | null;
/**
* @returns Timing information related to the response.
*/
timing(): Protocol.Network.ResourceTiming | null;
/**
* @returns Promise which resolves to a buffer with response body.
*/
buffer(): Promise<Buffer>;
/**
* @returns Promise which resolves to a text representation of response body.
*/
text(): Promise<string>;
/**
*
* @returns Promise which resolves to a JSON representation of response body.
*
* @remarks
*
* This method will throw if the response body is not parsable via
* `JSON.parse`.
*/
json(): Promise<any>;
/**
* @returns A matching {@link HTTPRequest} object.
*/
request(): HTTPRequest;
/**
* @returns True if the response was served from either the browser's disk
* cache or memory cache.
*/
fromCache(): boolean;
/**
* @returns True if the response was served by a service worker.
*/
fromServiceWorker(): boolean;
/**
* @returns A {@link Frame} that initiated this response, or `null` if
* navigating to error pages.
*/
frame(): Frame | null;
}
export {};
//# sourceMappingURL=HTTPResponse.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTTPResponse.d.ts","sourceRoot":"","sources":["../../../../src/common/HTTPResponse.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,UAAW,SAAQ,YAAY;IACvC,IAAI,CAAC,CAAC,SAAS,MAAM,eAAe,CAAC,QAAQ,EAC3C,MAAM,EAAE,CAAC,EACT,GAAG,SAAS,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GACtD,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;CACvD;AAED;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,kBAAkB,CAAwB;IAClD,OAAO,CAAC,yBAAyB,CAA8B;IAC/D,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,gBAAgB,CAAyB;IACjD,OAAO,CAAC,OAAO,CAAyC;IAExD;;OAEG;gBAED,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAC1C,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,8BAA8B,GAAG,IAAI;IA+BnE;;OAEG;IACH,4BAA4B,CAC1B,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,8BAA8B,GAAG,IAAI,GAChE,MAAM,GAAG,SAAS;IAWrB;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI;IAIrC;;;OAGG;IACH,aAAa,IAAI,aAAa;IAI9B;;OAEG;IACH,GAAG,IAAI,MAAM;IAIb;;OAEG;IACH,EAAE,IAAI,OAAO;IAKb;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;;OAGG;IACH,UAAU,IAAI,MAAM;IAIpB;;;OAGG;IACH,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIjC;;;OAGG;IACH,eAAe,IAAI,eAAe,GAAG,IAAI;IAIzC;;OAEG;IACH,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,cAAc,GAAG,IAAI;IAIhD;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IA6BzB;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAK7B;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC;IAK1B;;OAEG;IACH,OAAO,IAAI,WAAW;IAItB;;;OAGG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,iBAAiB,IAAI,OAAO;IAI5B;;;OAGG;IACH,KAAK,IAAI,KAAK,GAAG,IAAI;CAGtB"}

View File

@@ -0,0 +1,192 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HTTPResponse = void 0;
const SecurityDetails_js_1 = require("./SecurityDetails.js");
const Errors_js_1 = require("./Errors.js");
/**
* The HTTPResponse class represents responses which are received by the
* {@link Page} class.
*
* @public
*/
class HTTPResponse {
/**
* @internal
*/
constructor(client, request, responsePayload, extraInfo) {
this._contentPromise = null;
this._headers = {};
this._client = client;
this._request = request;
this._bodyLoadedPromise = new Promise((fulfill) => {
this._bodyLoadedPromiseFulfill = fulfill;
});
this._remoteAddress = {
ip: responsePayload.remoteIPAddress,
port: responsePayload.remotePort,
};
this._statusText =
this._parseStatusTextFromExtrInfo(extraInfo) ||
responsePayload.statusText;
this._url = request.url();
this._fromDiskCache = !!responsePayload.fromDiskCache;
this._fromServiceWorker = !!responsePayload.fromServiceWorker;
this._status = extraInfo ? extraInfo.statusCode : responsePayload.status;
const headers = extraInfo ? extraInfo.headers : responsePayload.headers;
for (const key of Object.keys(headers))
this._headers[key.toLowerCase()] = headers[key];
this._securityDetails = responsePayload.securityDetails
? new SecurityDetails_js_1.SecurityDetails(responsePayload.securityDetails)
: null;
this._timing = responsePayload.timing;
}
/**
* @internal
*/
_parseStatusTextFromExtrInfo(extraInfo) {
if (!extraInfo || !extraInfo.headersText)
return;
const firstLine = extraInfo.headersText.split('\r', 1)[0];
if (!firstLine)
return;
const match = firstLine.match(/[^ ]* [^ ]* (.*)/);
if (!match)
return;
const statusText = match[1];
if (!statusText)
return;
return statusText;
}
/**
* @internal
*/
_resolveBody(err) {
return this._bodyLoadedPromiseFulfill(err);
}
/**
* @returns The IP address and port number used to connect to the remote
* server.
*/
remoteAddress() {
return this._remoteAddress;
}
/**
* @returns The URL of the response.
*/
url() {
return this._url;
}
/**
* @returns True if the response was successful (status in the range 200-299).
*/
ok() {
// TODO: document === 0 case?
return this._status === 0 || (this._status >= 200 && this._status <= 299);
}
/**
* @returns The status code of the response (e.g., 200 for a success).
*/
status() {
return this._status;
}
/**
* @returns The status text of the response (e.g. usually an "OK" for a
* success).
*/
statusText() {
return this._statusText;
}
/**
* @returns An object with HTTP headers associated with the response. All
* header names are lower-case.
*/
headers() {
return this._headers;
}
/**
* @returns {@link SecurityDetails} if the response was received over the
* secure connection, or `null` otherwise.
*/
securityDetails() {
return this._securityDetails;
}
/**
* @returns Timing information related to the response.
*/
timing() {
return this._timing;
}
/**
* @returns Promise which resolves to a buffer with response body.
*/
buffer() {
if (!this._contentPromise) {
this._contentPromise = this._bodyLoadedPromise.then(async (error) => {
if (error)
throw error;
try {
const response = await this._client.send('Network.getResponseBody', {
requestId: this._request._requestId,
});
return Buffer.from(response.body, response.base64Encoded ? 'base64' : 'utf8');
}
catch (error) {
if (error instanceof Errors_js_1.ProtocolError &&
error.originalMessage === 'No resource with given identifier found') {
throw new Errors_js_1.ProtocolError('Could not load body for this request. This might happen if the request is a preflight request.');
}
throw error;
}
});
}
return this._contentPromise;
}
/**
* @returns Promise which resolves to a text representation of response body.
*/
async text() {
const content = await this.buffer();
return content.toString('utf8');
}
/**
*
* @returns Promise which resolves to a JSON representation of response body.
*
* @remarks
*
* This method will throw if the response body is not parsable via
* `JSON.parse`.
*/
async json() {
const content = await this.text();
return JSON.parse(content);
}
/**
* @returns A matching {@link HTTPRequest} object.
*/
request() {
return this._request;
}
/**
* @returns True if the response was served from either the browser's disk
* cache or memory cache.
*/
fromCache() {
return this._fromDiskCache || this._request._fromMemoryCache;
}
/**
* @returns True if the response was served by a service worker.
*/
fromServiceWorker() {
return this._fromServiceWorker;
}
/**
* @returns A {@link Frame} that initiated this response, or `null` if
* navigating to error pages.
*/
frame() {
return this._request.frame();
}
}
exports.HTTPResponse = HTTPResponse;
//# sourceMappingURL=HTTPResponse.js.map

Some files were not shown because too many files have changed in this diff Show More