* feat(chromium): roll Chromium to r856583
This corresponds to Chromium 90.0.4427.0
This roll includes:
- Add sourceScheme, sourcePort, and sameParty to DevTools backend (https://crbug.com/1170548, https://crbug.com/1142606)
We can use the new `Lowercase` util in TS4 to avoid duplicating the type
and instead lowercase it.
Note we still need to do the work so callbacks are typed correctly:
```ts
page.on('request', request => {
})
```
Right now `request` is `any`, whereas it should be a
`puppeteer.HTTPRequest`. You can manually set the type for now, and I
will work on adding types for events so that this is done automatically
by the compiler in a future release.
Fixes#6854.
This commit tidies up the quite confusing state of all the various types
required to launch a browser. As we saw when upgrading DevTools
(https://source.chromium.org/chromium/chromium/src/+/master:third_party/devtools-frontend/src/test/conductor/hooks.ts;l=77),
we had to define our launch options variable like so:
```ts
const opts: puppeteer.LaunchOptions & puppeteer.ChromeArgOptions & puppeteer.BrowserOptions = {
...
};
```
This commit fixes that by introducing `AllNodeLaunchOptions`, which is
defined as the intersection of all the above types.
Additionally, the types defined as `ChromeArgOptions` are actually used
for launching both Chrome and Firefox, so I have renamed them to
`BrowserArgOptions`, and therefore this change is breaking because
anyone using `ChromeArgOptions` in their types will need to switch.
BREAKING CHANGE: renamed type `ChromeArgOptions` to `BrowserLaunchArgumentOptions`
BREAKING CHANGE: renamed type `BrowserOptions` to `BrowserConnectOptions`
Also includes drive-by when I subbed `@default` (not valid) to
`@defaultValue` (valid!) in a few places and exposed types from
`Coverage.ts` so they get exposed too.
Fixes 6876.
During the migration to TS we changed `jsonValue` so it returned
`<Record<string, unknown>>`. This is only true if all the JSON values it
returns are objects; but it could return an array, a string, a number,
etc. Therefore we make the type generic, setting the default to
`unknown`, so the user has control over the type.
* fix: wider compat TS types and CI checks to ensure correct type defs
This PR improves our TS types further to make sure they are usable in a
TS environment where ES Modules are the target output. Our use of
`export =` is problematic this environment as TypeScript does not allow
`export =` to be used and it errors.
The fix for the type issues to avoid `export =` is to instead define the
functions that you gain access to when you import Puppeteer as top level
functions in our `types.d.ts` file. We can do this by declaring them
explicitly in `src/node.ts`. These are then rolled into `lib/types.d.ts`
at build time. The downside to this is that we have to keep those
declarations in sync with the Puppeteer API; should we add a new method
to the `Puppeteer` class, we must add it to the `nodes.ts` declarations.
However, this could easily be automated by a small script that walks the
AST and generates these. I will do that in a follow-up PR, but I
consider this low risk given how rarely the very top level API of
Puppeteer changes. The nice thing about this approach is we no longer
need our script that hacks on changes to `lib/types.d.ts`.
To avoid yet more releases to fix issues in one particular TS
environment, this PR also includes a suite of example setups that we
test on each CI run. Each sample folder contains `good.ts`, which should
have no TS errors, and `bad.ts`, which should have some errors. The test
first packs Puppeteer into a tar, and then installs it from that tar
into each project. This should replicate how the published package
behaves when it is installed. We then check that we get no errors on
`good.ts`, and the expected errors on `bad.ts`.
We have a variety of test projects that cover both TS and JS source
code, and CJS and ESM imports and outputs.
This PR aims to vastly improve our TS types and how we ship them.
Our previous attempt at shipping TypeScript was unfortunately flawed for
many reasons when compared to the @types/puppeteer package:
* It only worked if you needed the default export. If you wanted to
import a type that Puppeteer uses, you'd have to do `import type X
from 'puppeteer/lib/...'`. This is not something we want to encourage
because that means our internal file structure becomes almost public
API.
* It gave absolutely no help to CommonJS users in JS files because it
would warn people they needed to do `const pptr =
require('puppeteer').default, which is not correct.
* I found a bug in the `evaluate` types which mean't you couldn't
override the types to provide more info, and TS would insist the types
were all `unknown`.
The goal of this PR is to support:
1. In a `ts` file, `import puppeteer from 'puppeteer'`
1. In a `ts` file, `import type {ElementHandle} from 'puppeteer'`
1. In a `ts` file, referencing a type as `puppeteer.ElementHandle`
1. In a `ts` file, you can get good type inference when running
`foo.evaluate(x => x.clientHeight)`.
1. In a `js` file using CJS, you can do `const puppeteer =
require('puppeteer')` and get good type help from VSCode.
To test this I created a new empty repository with two test files in,
one `.ts` file with this in:
https://gist.github.com/jackfranklin/22ba2f390f97c7312cd70025a2096fc8,
and a `js` file with this in:
https://gist.github.com/jackfranklin/06bed136fdb22419cb7a8a9a4d4ef32f.
These files included enough code to check that the types were behaving
as I expected.
The fix for our types was to make use of API Extractor, which we already
use for our docs, to "rollup" all the disparate type files that TS
generates into one large `types.d.ts` which contains all the various
types that we define, such as:
```ts
export declare class ElementHandle {...}
export type EvaluateFn ...
```
If we then update our `package.json` `types` field to point to that file
in `lib/types.d.ts`, this then allows a developer to write:
```
import type {ElementHandle} from 'puppeteer'
```
And get the correct type definitions. However, what the `types.d.ts`
file doesn't do out of the box is declare the default export, so
importing Puppeteer's default export to call a method such as `launch`
on it will get you an error.
That's where the `script/add-default-export-to-types.ts` comes in. It
appends the following to the auto-generated `types.d.ts` file:
```ts
declare const puppeteer: PuppeteerNode;
export = puppeteer;
```
This tells TypeScript what the default export is, and by using the
`export =` syntax, we make sure TS understands both in a TS ESM
environment and in a JS CJS environment.
Now the `build` step, which is run by GitHub Actions when we release,
will generate the `.d.ts` file and then extend it with the default
export code.
To ensure that I was generating a valid package, I created a new
repository locally with the two code samples linked in Gists above. I
then ran:
```
npm init -y
npm install --save-dev typescript
npx tsc --init
```
Which gives me a base to test from. In Puppeteer, I ran `npm pack`,
which packs the module into a tar that's almost identical to what would
be published, so I can be confident that the .d.ts files in there are
what would be published.
I then installed it:
```
npm install --save-dev ../../puppeteer/puppeteer-7.0.1-post.tgz
```
And then reloaded VSCode in my dummy project. By deliberately making
typos and hovering over the code, I could confirm that all the goals
listed above were met, and this seems like a vast improvement on our
types.
* fix(launcher): output correct error message for browser
When running `npm run release` today I got this error logged:
```
Error: Could not find browser revision 848005. Run "PUPPETEER_PRODUCT=firefox npm install" or "PUPPETEER_PRODUCT=firefox yarn install" to download a supported Firefox browser binary.
at ChromeLauncher.launch (/Users/jacktfranklin/src/puppeteer/lib/cjs/puppeteer/node/Launcher.js:80:27)
```
The error is only partially correct; I did have the browser revision
missing, but I needed the Chromium browser, not Firefox. It turns out
the logic in `Launcher.ts` didn't take this into account; it mistakenly
had been hardcoded to always log out the error as if the Firefox binary
was missing.
This PR updates the message depending on the browser:
Chrome error:
> Error: Could not find expected browser (chrome) locally. Run npm
> install or yarn install to download the correct Chromium revision
> (848005).
Firefox error:
> Error: Could not find expected browser (firefox) locally. Run
> "PUPPETEER_PRODUCT=firefox npm install" or "PUPPETEER_PRODUCT=firefox
> yarn install" to download a supported Firefox browser binary.
* Update src/node/Launcher.ts
Co-authored-by: Mathias Bynens <mathias@qiwi.be>
Co-authored-by: Mathias Bynens <mathias@qiwi.be>
This corresponds to Chromium 90.0.4403.0
This roll includes:
- Cut screenshot by ViewPort size, not position (crrev.com/c/2643792)
BREAKING CHANGE:
- `page.screenshot` cuts screenshot content by the ViewPort size, not ViewPort position.
This corresponds to Chromium 89.0.4389.0.
This roll includes:
- Add `SameParty` attribute to cookies
https://crrev.com/c/2598846
- Anchor `target=_blank` implies `rel=noopener`
https://crrev.com/c/1630010
- Don’t expect ignored elements in the AXTree
https://crrev.com/c/2505362
BREAKING CHANGE: The built-in `aria/` selector query handler doesn’t return ignored elements anymore.
Issue: #6758
This PR replaces https://github.com/puppeteer/puppeteer/pull/6289 with a simpler approach to types where we compile them all alongside the compiled code (so for every `foo.js` that is generated, we generate `foo.d.ts`).
By default that's not enough, as when you `import puppeteer from 'puppeteer'` in Node land you import `cjs-entry.js`, so we also create `cjs-entry.d.ts` which TypeScript will then pick up. This type file tells TypeScript that the thing that `cjs-entry.js` exposes is an instance of the `Puppeteer` class, which then hooks all the types up.
The previous PR (https://github.com/puppeteer/puppeteer/pull/6289) tried to merge all our typedefs into one big file via API Extractor, but this isn't really necessary a good experience for the developer.
One important consideration is that you _could_ consider this a breaking change. I'm not sure how likely it is, but it could cause problems for:
* Projects that didn't have any type info for Puppeteer and treated all its exports as `any` may now start having legitimate type failures.
* Projects that depend on the `@types/puppeteer` package may have issues if they now swap to use this one and the types aren't quite aligned.
In addition, once we do ship a release with this change in, it will mean that we have to treat any changes to any type definitions as release-note-worthy, and any breaking changes to type definitions will need to be treated as breaking code changes (nearly always a breaking type def means a breaking change anyway), but it's worth considering that once we expose these typedefs we should treat them as first class citizens of the project just like we would with the actual source code.
I also fully expect to have some bugs with our types, or have users create issues/PRs to change our types, but I think that's a good thing and it should settle down.
I've tested this locally by creating a new package, linking Puppeteer via `npm link puppeteer` and then checking that VSCode correctly shows me the right things when I use `Go to Definition` on something that comes from the Puppeteer source code.
With `nodejs@15.0.1`, install puppeteer with `https_proxy` set causes an error like:
```
> puppeteer@5.4.1 install node_modules/puppeteer
> node install.js
ERROR: Failed to set up Chromium r809590! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to skip download.
TypeError [ERR_INVALID_PROTOCOL]: Protocol "https:" not supported. Expected "http:"
at new NodeError (node:internal/errors:258:15)
at new ClientRequest (node:_http_client:155:11)
at Object.request (node:https:313:10)
at httpRequest (node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserFetcher.js:488:17)
at downloadFile (node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserFetcher.js:357:21)
at BrowserFetcher.download (node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserFetcher.js:239:19)
at async downloadBrowser (node_modules/puppeteer/lib/cjs/puppeteer/node/install.js:48:5) {
code: 'ERR_INVALID_PROTOCOL'
}
```
The related issue is at https://github.com/TooTallNate/node-agent-base/pull/47, from package `agent-base` under `https-proxy-agent`
And the version bump is for `Refactor to TypeScript` is here: https://github.com/TooTallNate/node-https-proxy-agent/compare/4.0.0...5.0.0
`isNode` checks for the node version in which the process is running and it checks for the node key inside the versions. This is exactly the same as using `process.version` as they are set in the native code and `process.version` is just a shorthand for `process.versions.node`.
* chore: run unit tests on node 10.15
We saw in https://github.com/puppeteer/puppeteer/issues/6548 that the
`fs.promises` module was experimental in Node <10.17 and as such we
introduced issues for users on 10.15.
Until we can drop Node v10 (it's EOL is 30-04-20201
https://github.com/nodejs/Release#release-schedule) we should run our
tests on an old Node 10 to avoid regressing in this area.
* chore: helper for importing fs safely
This PR updates the socket transport code to swap between a Node web
socket transport or a web one based on the `isNode` environment. It also
adds unit tests to the browser tests that show we can connect in a
browser.
* chore(agnostification): common/helper.ts
The `readProtocolStream` method uses `fs` only if you want to write to a
file. So we gate at the start of the function and ensure that if we got
given a path we are not in a Node environment.
The `Puppeteer` class had two concerns:
* connect to an existing browser
* launch a new browser
The first of those concerns is needed in all environments, but the
second is only needed in Node.
https://github.com/puppeteer/puppeteer/pull/6484 landing enabled us to
pull the `Puppeteer` class apart into two:
1. `Puppeteer` which hosts the behaviour for connecting to existing
browsers.
2. `PuppeteerNode`, which extends `Puppeteer` and also adds the ability
to launch a new browser.
This is a non-breaking change, because Node users will still get an
instance of a class with all the methods they expect, but it'll be a
`PuppeteerNode` rather than `Puppeteer`. I don't expect this to cause
people any issues.
We also now have new files that are effectively the entry points for
Puppeteer:
* `node.ts`: the main entry point for Puppeteer on Node.
* `web.ts`: the main entry point for Puppeteer on the web.
* `node-puppeteer-core.ts`: for those using puppeteer-core (which only
exists in Node, not on the web).
Launching headless with a relative `userDataDir` hangs on Windows. Fix by calling `path.resolve` (idempotent) to add an absolute path instead in `defaultArgs`.
Issues: #3453
The `Launcher` class was serving two purposes:
1. Launch browsers
2. Connect to browsers
Number 1) only needs to be done in Node land, but 2) is agnostic; in a
browser version of Puppeteer we'll need the ability to connect over a
websocket to send commands back and forth.
As part of the agnostification work we needed to split the `Launcher` up
so that the connection part can be made agnostic. Additionally, I
removed dependencies on `https`, `http` and `URL` from Node, instead
leaning on fetch (via `node-fetch` if in Node land) and the browser
`URL` API (which was added to Node in Node 10).
* chore(agnostify): Create Node and Web initializer.
This PR splits `initialize.ts` into two files, one for web, and one for
Node. The Node initializer requires much more information as it needs to
know which browser(s) to download and where to store them, whereas the
web one does not.
A future PR that I'm working on will tidy up `src/common/Puppeteer.ts`
(as it contains a lot of Node specific logic around downloading and
installing browsers), but this change enables us to stop the browser
bundle attempting to use the `pkg-dir` dependency, which wouldn't work
within a browser, as well as keeping the size of the PRs down and
avoiding one mammoth PR.
This commit adds a new built-in handler for querying by accessible name and role (#6307).
Support for waitForSelector will be added in a follow-up commit.
In `src/common` we now use `fs.promises.X` which we can dynamically
`import`. In a browser environment this code will never run because it's
gated on `isNode` (in a future PR we will add tree-shaking to the bundle
step such that this code is eliminated). By using `import`, we ensure
TypeScript still can track types and give good type information.
In `src/node` we continue to use `util.promisify` but that's not a
concern as that code explicitly is never run in the browser.
This commit changes the internal representation of query handlers to contain Puppeteer-level code instead of page functions.
The interface `CustomQueryHandler` is introduced for user-defined query handlers. When a `CustomQueryHandler` is registered using `registerCustomQueryHandler` a corresponding Puppeteer-level handler is created through `makeQueryHandler` by wrapping the page functions as appropriate.
The internal query handlers (defined by the interface `QueryHandler`) contain two new functions: `waitFor` and `queryAllArray`.
- `waitFor` allows page-based handlers to make use of the `WaitTask`-backed implementation in `DOMWorld`, whereas purely Puppeteer-based handlers can define an alternative approach instead.
- `queryAllArray` is similar to `queryAll` but with a slightly different interface; it returns a `JSHandle` to an array with the results as opposed to an array of `ElementHandle`. It is used by `$$eval`.
After this change, we can introduce built-in query handlers that are not executed in the page context (#6307).
The logic for waitForXPath and waitForSelector is currently very tightly coupled. This commit tries to untangle that relationship. This is the first step towards introducing built-in query handlers that are not executed in the page context (#6307).
Debug message clarifying the problem like `Issue 1060080: Event Network.loadingFinished is not sent when a frame is loaded from another domain`: https://bugs.chromium.org/p/chromium/issues/detail?id=1060080).
It can help users to identify problem with OOPIF easier without digging into the CDP protocol implementation like in the bug `1060080` mentioned above.
To reproduce:
1. Run `DEBUG="puppeteer:frame" NODE_PATH=../ node examples/oopif.js`.
2. Verify the output contains the debug message:
`
puppeteer:frame The frame '...' moved to another session. Out-of-proccess
iframes (OOPIF) are not supported by Puppeteer yet.
https://github.com/puppeteer/puppeteer/issues/2548
`
* roll Chromium to version 86, r800071
* roll Chrome DevTools protocol version to 0.0.799653
* fix HTTPRequest.continue after
* CDP: accept post data in the binary form in Fetch.continueRequest.
https://chromium-review.googlesource.com/c/chromium/src/+/2315239
* update new-docs
By adding support for an environment variable `PUPPETEER_DOWNLOAD_PATH` it is possible to support downloading the browser binaries into a folder outside the `node_modules` folder. This makes it possible to preserve previously downloaded binaries in order to skip downloading them again.
This commit also removes our own custom type for defining the vision
deficiencies and uses the protocol's type. Now we generate docs for
those we get the docs generated for free for these. This is better than
us duplicating values for types in doc comments and having them become
outdated. If we use the protocol types directly then we ensure we're up
to date and in-sync.
Long term the docs will also link to the devtools-protocol viewer.
This corresponds to Chromium 85.0.4182.0.
This roll includes:
- Enable SameSiteByDefaultCookies and CookiesWithoutSameSiteMustBeSecure
https://crrev.com/c/2231445
- [FlexNG] Enable FlexNG by default
https://crrev.com/c/2216595Closes#6151.
The Node debug library uses the `DEBUG` environment variable to
configure what gets logged. Our browser version just logs everything;
this commit changes it to look for `window.__PUPPETEER_DEBUG` and matches the behaviour accordingly:
* If the value is not set, nothing is logged.
* If the value is set to `*` everything is logged.
* If the value is set to a string `foo`, messages with that prefix are
logged.
* If the value is set to a string ending in `*`, e.g. `foo*`, messages
with prefixes that start with `foo` are logged.
Also took the opportunity to pull out the PDF types into their own file
to clear up `Page.ts` slightly and give the PDF code a more natural
place to live.
* chore: vendor Mitt into src/common/third-party
As discussed in #6203 we need to vendor our common dependencies in so
that when we ship an ESM build all imports point to file paths and do
not rely on Node resolution (e.g. a browser does not understand `import
mitt from 'mitt'`).
* chore: enforce file extensions on imports
To make our output agnostic it should include file extensions in the
output, as per the ESM spec. It's a bit odd for Node packages but makes
it easier to publish a browser build.
* feat(chromium): roll Chromium to r768783
* fix: update unit test for crrev:2135046
* chore: update devtools-protocol revision
Co-authored-by: Changhao Han <changhaohan@chromium.org>
* chore: Use devtools-protocol package
Rather than maintain our own protocol we can instead use the devtools-protocol package and pin it to the version of Chromium that Puppeteer is shipping with.
The only changes are naming changes between the bespoke protocol that Puppeteer created and the devtools-protocol one.
Now the async hooks helper is gone api.ts was only used by the coverage
tools and by doclint.
DocLint is nearing the end of its lifespan with the TSDoc work, so I
focused on how best to define a list of modules for the coverage
tooling. They define an object of classes, and the path to that module.
They need the full path because we also check if the module exports any
events that need to be emitted - the coverage tool asserts that the
emitting of those events is also tested.
It's not _great_ that DocLint relies on a constant defined in the
coverage utils, but it should only be this way for a short period of
time and no one is actively working on DocLint (bar the effort to remove
it) so I don't think this is worth worrying about.
This change also broke the DocLint tests; based on the fact that DocLint is on its way out it doesn't feel worth fixing the tests, so this commit also removes them.
* chore: remove `installAsyncStackHooks` helper
This code was written when browsers/Node didn't support errors in async
functions very well. They now do a much better job of this, so we can
lose the additonal complexity from our codebase and leave it to the host
environment :)
* lazy launcher is private
* remove async stack test
This file is now deprecated and only used by the coverage tool and
DocLint - these tools will be updated to not rely on it in the future.
We now have events defined per class - e.g. all the events that `Page`
can emit are defined in the `PageEmittedEvents` enum, and similar. We
have to keep `Events.ts` around for the aforementioned tools, but don't
want its usage creeping back into our source code.
On a getter function you don't use `@returns` (as that's just for
methods). Instead we can just add to the general remarks to explain what
the property is providing.
This is part of the effort to remove `Events.ts` in favour of defining
events next to the class that emits them. In this case these events are
internal, so there's no docs changes, but it's still worth doing such
that we can remove the Events.ts file in the long term once all the
different events are migrated.
I noticed that DOMWorld was spitting a lot of warnings out when we
generated the docs. It was mostly easy tidy-ups and removing old JSDoc
comments and now the warnings are gone :)
* chore(docs): migrate & document all Page events
Rather than a generic `Events.ts` file we can instead document events as
an enum within each individual class. It's easier to document and work
with, and it's clearer where events originate from.