chore: migrate away from Node's EventEmitter (#5979)
This commit is contained in:
parent
6e060ce0fd
commit
b659969a38
70
docs/api.md
70
docs/api.md
@ -336,6 +336,15 @@
|
||||
* [coverage.stopCSSCoverage()](#coveragestopcsscoverage)
|
||||
* [coverage.stopJSCoverage()](#coveragestopjscoverage)
|
||||
- [class: TimeoutError](#class-timeouterror)
|
||||
- [class: EventEmitter](#class-eventemitter)
|
||||
* [eventEmitter.addListener(event, handler)](#eventemitteraddlistenerevent-handler)
|
||||
* [eventEmitter.emit(event, [eventData])](#eventemitteremitevent-eventdata)
|
||||
* [eventEmitter.listenerCount(event)](#eventemitterlistenercountevent)
|
||||
* [eventEmitter.off(event, handler)](#eventemitteroffevent-handler)
|
||||
* [eventEmitter.on(event, handler)](#eventemitteronevent-handler)
|
||||
* [eventEmitter.once(event, handler)](#eventemitteronceevent-handler)
|
||||
* [eventEmitter.removeAllListeners([event])](#eventemitterremovealllistenersevent)
|
||||
* [eventEmitter.removeListener(event, handler)](#eventemitterremovelistenerevent-handler)
|
||||
<!-- GEN:stop -->
|
||||
|
||||
### Overview
|
||||
@ -657,7 +666,7 @@ The method initiates a GET request to download the revision from the host.
|
||||
|
||||
### class: Browser
|
||||
|
||||
* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
|
||||
* extends: [EventEmitter](#class-eventemitter)
|
||||
|
||||
A Browser is created when Puppeteer connects to a Chromium instance, either through [`puppeteer.launch`](#puppeteerlaunchoptions) or [`puppeteer.connect`](#puppeteerconnectoptions).
|
||||
|
||||
@ -819,7 +828,7 @@ You can find the `webSocketDebuggerUrl` from `http://${host}:${port}/json/versio
|
||||
|
||||
### class: BrowserContext
|
||||
|
||||
* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
|
||||
* extends: [EventEmitter](#class-eventemitter)
|
||||
|
||||
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 `browser.newPage()` creates a page in the default browser context.
|
||||
@ -949,7 +958,7 @@ const newWindowTarget = await browserContext.waitForTarget(target => target.url(
|
||||
|
||||
### class: Page
|
||||
|
||||
* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
|
||||
* extends: [EventEmitter](#class-eventemitter)
|
||||
|
||||
Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. One [Browser] instance might have multiple [Page] instances.
|
||||
|
||||
@ -966,14 +975,16 @@ const puppeteer = require('puppeteer');
|
||||
})();
|
||||
```
|
||||
|
||||
The Page class emits various events (described below) which can be handled using any of Node's native [`EventEmitter`](https://nodejs.org/api/events.html#events_class_eventemitter) methods, such as `on`, `once` or `removeListener`.
|
||||
The Page class emits various events (described below) which can be handled using
|
||||
any of the [`EventEmitter`](#class-eventemitter) methods, such as `on`, `once`
|
||||
or `off`.
|
||||
|
||||
This example logs a message for a single page `load` event:
|
||||
```js
|
||||
page.once('load', () => console.log('Page loaded!'));
|
||||
```
|
||||
|
||||
To unsubscribe from events use the `removeListener` method:
|
||||
To unsubscribe from events use the `off` method:
|
||||
|
||||
```js
|
||||
function logRequest(interceptedRequest) {
|
||||
@ -981,7 +992,7 @@ function logRequest(interceptedRequest) {
|
||||
}
|
||||
page.on('request', logRequest);
|
||||
// Sometime later...
|
||||
page.removeListener('request', logRequest);
|
||||
page.off('request', logRequest);
|
||||
```
|
||||
|
||||
#### event: 'close'
|
||||
@ -3869,7 +3880,7 @@ If the target is not of type `"service_worker"` or `"shared_worker"`, returns `n
|
||||
|
||||
### class: CDPSession
|
||||
|
||||
* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
|
||||
* extends: [EventEmitter](#class-eventemitter)
|
||||
|
||||
The `CDPSession` instances are used to talk raw Chrome Devtools Protocol:
|
||||
- protocol methods can be called with `session.send` method.
|
||||
@ -3975,7 +3986,51 @@ reported.
|
||||
|
||||
TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g. [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options) or [puppeteer.launch([options])](#puppeteerlaunchoptions).
|
||||
|
||||
### class: EventEmitter
|
||||
|
||||
A small EventEmitter class backed by [Mitt](https://github.com/developit/mitt/).
|
||||
|
||||
#### eventEmitter.addListener(event, handler)
|
||||
- `event` <[string]|[symbol]> the event to remove the handler from.
|
||||
- `handler` <[Function]> the event listener that will be added.
|
||||
- returns: `this` so you can chain method calls
|
||||
|
||||
This method is identical to `on` and maintained for compatibility with Node's EventEmitter. We recommend using `on` by default.
|
||||
|
||||
#### eventEmitter.emit(event, [eventData])
|
||||
- `event` <[string]|[symbol]> the event to trigger.
|
||||
- `eventData` <[Object]> additional data to send with the event.
|
||||
- returns: `boolean`; `true` if there are any listeners for the event, `false` if there are none.
|
||||
|
||||
#### eventEmitter.listenerCount(event)
|
||||
- `event` <[string]|[symbol]> the event to check for listeners.
|
||||
- returns: <[number]> the number of listeners for the given event.
|
||||
|
||||
#### eventEmitter.off(event, handler)
|
||||
- `event` <[string]|[symbol]> the event to remove the handler from.
|
||||
- `handler` <[Function]> the event listener that will be removed.
|
||||
- returns: `this` so you can chain method calls
|
||||
|
||||
#### eventEmitter.on(event, handler)
|
||||
- `event` <[string]|[symbol]> the event to add the handler to.
|
||||
- `handler` <[Function]> the event listener that will be added.
|
||||
- returns: `this` so you can chain method calls
|
||||
|
||||
#### eventEmitter.once(event, handler)
|
||||
- `event` <[string]|[symbol]> the event to add the handler to.
|
||||
- `handler` <[Function]> the event listener that will be added.
|
||||
- returns: `this` so you can chain method calls
|
||||
|
||||
#### eventEmitter.removeAllListeners([event])
|
||||
- `event` <[string]|[symbol]> optional argument to remove all listeners for the given event. If it's not given this method will remove all listeners for all events.
|
||||
- returns: `this` so you can chain method calls
|
||||
|
||||
#### eventEmitter.removeListener(event, handler)
|
||||
- `event` <[string]|[symbol]> the event to remove the handler from.
|
||||
- `handler` <[Function]> the event listener that will be removed.
|
||||
- returns: `this` so you can chain method calls
|
||||
|
||||
This method is identical to `off` and maintained for compatibility with Node's EventEmitter. We recommend using `off` by default.
|
||||
|
||||
[AXNode]: #accessibilitysnapshotoptions "AXNode"
|
||||
[Accessibility]: #class-accessibility "Accessibility"
|
||||
@ -4024,4 +4079,5 @@ TimeoutError is emitted whenever certain operations are terminated due to timeou
|
||||
[selector]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors "selector"
|
||||
[stream.Readable]: https://nodejs.org/api/stream.html#stream_class_stream_readable "stream.Readable"
|
||||
[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type "String"
|
||||
[symbol]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Symbol_type "Symbol"
|
||||
[xpath]: https://developer.mozilla.org/en-US/docs/Web/XPath "xpath"
|
||||
|
30
new-docs/puppeteer.eventemitter.addlistener.md
Normal file
30
new-docs/puppeteer.eventemitter.addlistener.md
Normal file
@ -0,0 +1,30 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [puppeteer](./puppeteer.md) > [EventEmitter](./puppeteer.eventemitter.md) > [addListener](./puppeteer.eventemitter.addlistener.md)
|
||||
|
||||
## EventEmitter.addListener() method
|
||||
|
||||
> Warning: This API is now obsolete.
|
||||
>
|
||||
> please use `on` instead.
|
||||
>
|
||||
|
||||
Add an event listener.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
addListener(event: EventType, handler: Handler): EventEmitter;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| event | EventType | |
|
||||
| handler | Handler | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[EventEmitter](./puppeteer.eventemitter.md)
|
||||
|
27
new-docs/puppeteer.eventemitter.emit.md
Normal file
27
new-docs/puppeteer.eventemitter.emit.md
Normal file
@ -0,0 +1,27 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [puppeteer](./puppeteer.md) > [EventEmitter](./puppeteer.eventemitter.md) > [emit](./puppeteer.eventemitter.emit.md)
|
||||
|
||||
## EventEmitter.emit() method
|
||||
|
||||
Emit an event and call any associated listeners.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
emit(event: EventType, eventData?: any): boolean;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| event | EventType | the event you'd like to emit |
|
||||
| eventData | any | any data you'd like to emit with the event |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
boolean
|
||||
|
||||
`true` if there are any listeners, `false` if there are not.
|
||||
|
26
new-docs/puppeteer.eventemitter.listenercount.md
Normal file
26
new-docs/puppeteer.eventemitter.listenercount.md
Normal file
@ -0,0 +1,26 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [puppeteer](./puppeteer.md) > [EventEmitter](./puppeteer.eventemitter.md) > [listenerCount](./puppeteer.eventemitter.listenercount.md)
|
||||
|
||||
## EventEmitter.listenerCount() method
|
||||
|
||||
Gets the number of listeners for a given event.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
listenerCount(event: EventType): number;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| event | EventType | the event to get the listener count for |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
number
|
||||
|
||||
the number of listeners bound to the given event
|
||||
|
33
new-docs/puppeteer.eventemitter.md
Normal file
33
new-docs/puppeteer.eventemitter.md
Normal file
@ -0,0 +1,33 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [puppeteer](./puppeteer.md) > [EventEmitter](./puppeteer.eventemitter.md)
|
||||
|
||||
## EventEmitter class
|
||||
|
||||
The EventEmitter class that many Puppeteer classes extend.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare class EventEmitter implements CommonEventEmitter
|
||||
```
|
||||
|
||||
## Remarks
|
||||
|
||||
This allows you to listen to events that Puppeteer classes fire and act accordingly. Therefore you'll mostly use [on](./puppeteer.eventemitter.on.md) and [off](./puppeteer.eventemitter.off.md) to bind and unbind to event listeners.
|
||||
|
||||
The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `EventEmitter` class.
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [addListener(event, handler)](./puppeteer.eventemitter.addlistener.md) | | Add an event listener. |
|
||||
| [emit(event, eventData)](./puppeteer.eventemitter.emit.md) | | Emit an event and call any associated listeners. |
|
||||
| [listenerCount(event)](./puppeteer.eventemitter.listenercount.md) | | Gets the number of listeners for a given event. |
|
||||
| [off(event, handler)](./puppeteer.eventemitter.off.md) | | Remove an event listener from firing. |
|
||||
| [on(event, handler)](./puppeteer.eventemitter.on.md) | | Bind an event listener to fire when an event occurs. |
|
||||
| [once(event, handler)](./puppeteer.eventemitter.once.md) | | Like <code>on</code> but the listener will only be fired once and then it will be removed. |
|
||||
| [removeAllListeners(event)](./puppeteer.eventemitter.removealllisteners.md) | | Removes all listeners. If given an event argument, it will remove only listeners for that event. |
|
||||
| [removeListener(event, handler)](./puppeteer.eventemitter.removelistener.md) | | Remove an event listener. |
|
||||
|
27
new-docs/puppeteer.eventemitter.off.md
Normal file
27
new-docs/puppeteer.eventemitter.off.md
Normal file
@ -0,0 +1,27 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [puppeteer](./puppeteer.md) > [EventEmitter](./puppeteer.eventemitter.md) > [off](./puppeteer.eventemitter.off.md)
|
||||
|
||||
## EventEmitter.off() method
|
||||
|
||||
Remove an event listener from firing.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
off(event: EventType, handler: Handler): EventEmitter;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| event | EventType | the event type you'd like to stop listening to. |
|
||||
| handler | Handler | the function that should be removed. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[EventEmitter](./puppeteer.eventemitter.md)
|
||||
|
||||
`this` to enable you to chain calls.
|
||||
|
27
new-docs/puppeteer.eventemitter.on.md
Normal file
27
new-docs/puppeteer.eventemitter.on.md
Normal file
@ -0,0 +1,27 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [puppeteer](./puppeteer.md) > [EventEmitter](./puppeteer.eventemitter.md) > [on](./puppeteer.eventemitter.on.md)
|
||||
|
||||
## EventEmitter.on() method
|
||||
|
||||
Bind an event listener to fire when an event occurs.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
on(event: EventType, handler: Handler): EventEmitter;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| event | EventType | the event type you'd like to listen to. Can be a string or symbol. |
|
||||
| handler | Handler | the function to be called when the event occurs. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[EventEmitter](./puppeteer.eventemitter.md)
|
||||
|
||||
`this` to enable you to chain calls.
|
||||
|
27
new-docs/puppeteer.eventemitter.once.md
Normal file
27
new-docs/puppeteer.eventemitter.once.md
Normal file
@ -0,0 +1,27 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [puppeteer](./puppeteer.md) > [EventEmitter](./puppeteer.eventemitter.md) > [once](./puppeteer.eventemitter.once.md)
|
||||
|
||||
## EventEmitter.once() method
|
||||
|
||||
Like `on` but the listener will only be fired once and then it will be removed.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
once(event: EventType, handler: Handler): EventEmitter;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| event | EventType | the event you'd like to listen to |
|
||||
| handler | Handler | the handler function to run when the event occurs |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[EventEmitter](./puppeteer.eventemitter.md)
|
||||
|
||||
`this` to enable you to chain calls.
|
||||
|
26
new-docs/puppeteer.eventemitter.removealllisteners.md
Normal file
26
new-docs/puppeteer.eventemitter.removealllisteners.md
Normal file
@ -0,0 +1,26 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [puppeteer](./puppeteer.md) > [EventEmitter](./puppeteer.eventemitter.md) > [removeAllListeners](./puppeteer.eventemitter.removealllisteners.md)
|
||||
|
||||
## EventEmitter.removeAllListeners() method
|
||||
|
||||
Removes all listeners. If given an event argument, it will remove only listeners for that event.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
removeAllListeners(event?: EventType): EventEmitter;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| event | EventType | the event to remove listeners for. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[EventEmitter](./puppeteer.eventemitter.md)
|
||||
|
||||
`this` to enable you to chain calls.
|
||||
|
30
new-docs/puppeteer.eventemitter.removelistener.md
Normal file
30
new-docs/puppeteer.eventemitter.removelistener.md
Normal file
@ -0,0 +1,30 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [puppeteer](./puppeteer.md) > [EventEmitter](./puppeteer.eventemitter.md) > [removeListener](./puppeteer.eventemitter.removelistener.md)
|
||||
|
||||
## EventEmitter.removeListener() method
|
||||
|
||||
> Warning: This API is now obsolete.
|
||||
>
|
||||
> please use `off` instead.
|
||||
>
|
||||
|
||||
Remove an event listener.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
removeListener(event: EventType, handler: Handler): EventEmitter;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| event | EventType | |
|
||||
| handler | Handler | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[EventEmitter](./puppeteer.eventemitter.md)
|
||||
|
@ -18,6 +18,7 @@
|
||||
| [Coverage](./puppeteer.coverage.md) | |
|
||||
| [Dialog](./puppeteer.dialog.md) | Dialog instances are dispatched by the [Page](./puppeteer.page.md) via the <code>dialog</code> event. |
|
||||
| [ElementHandle](./puppeteer.elementhandle.md) | |
|
||||
| [EventEmitter](./puppeteer.eventemitter.md) | The EventEmitter class that many Puppeteer classes extend. |
|
||||
| [ExecutionContext](./puppeteer.executioncontext.md) | |
|
||||
| [FileChooser](./puppeteer.filechooser.md) | |
|
||||
| [Frame](./puppeteer.frame.md) | |
|
||||
|
@ -32,7 +32,7 @@ const puppeteer = require('puppeteer');
|
||||
})();
|
||||
|
||||
```
|
||||
The Page class emits various events which are documented in the [PageEmittedEvents](./puppeteer.pageemittedevents.md) enum.
|
||||
The Page class extends from Puppeteer's [EventEmitter](./puppeteer.eventemitter.md) class and will emit various events which are documented in the [PageEmittedEvents](./puppeteer.pageemittedevents.md) enum.
|
||||
|
||||
## Example 2
|
||||
|
||||
|
@ -51,6 +51,7 @@
|
||||
"extract-zip": "^2.0.0",
|
||||
"https-proxy-agent": "^4.0.0",
|
||||
"mime": "^2.0.3",
|
||||
"mitt": "^2.0.1",
|
||||
"progress": "^2.0.1",
|
||||
"proxy-from-env": "^1.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import { helper, assert } from './helper';
|
||||
import { Target } from './Target';
|
||||
import * as EventEmitter from 'events';
|
||||
import { EventEmitter } from './EventEmitter';
|
||||
import { Events } from './Events';
|
||||
import Protocol from './protocol';
|
||||
import { Connection } from './Connection';
|
||||
|
@ -22,11 +22,11 @@ import * as childProcess from 'child_process';
|
||||
import * as https from 'https';
|
||||
import * as http from 'http';
|
||||
|
||||
import * as extractZip from 'extract-zip';
|
||||
import * as debug from 'debug';
|
||||
import * as removeRecursive from 'rimraf';
|
||||
import extractZip from 'extract-zip';
|
||||
import debug from 'debug';
|
||||
import removeRecursive from 'rimraf';
|
||||
import * as URL from 'url';
|
||||
import * as ProxyAgent from 'https-proxy-agent';
|
||||
import ProxyAgent from 'https-proxy-agent';
|
||||
import { getProxyForUrl } from 'proxy-from-env';
|
||||
|
||||
import { helper, assert } from './helper';
|
||||
|
@ -15,13 +15,13 @@
|
||||
*/
|
||||
import { assert } from './helper';
|
||||
import { Events } from './Events';
|
||||
import * as debug from 'debug';
|
||||
import debug from 'debug';
|
||||
const debugProtocolSend = debug('puppeteer:protocol:SEND ►');
|
||||
const debugProtocolReceive = debug('puppeteer:protocol:RECV ◀');
|
||||
|
||||
import Protocol from './protocol';
|
||||
import { ConnectionTransport } from './ConnectionTransport';
|
||||
import * as EventEmitter from 'events';
|
||||
import { EventEmitter } from './EventEmitter';
|
||||
|
||||
interface ConnectionCallback {
|
||||
resolve: Function;
|
||||
|
140
src/EventEmitter.ts
Normal file
140
src/EventEmitter.ts
Normal file
@ -0,0 +1,140 @@
|
||||
import mitt, { Emitter, EventType, Handler } from 'mitt';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface CommonEventEmitter {
|
||||
on(event: EventType, handler: Handler): CommonEventEmitter;
|
||||
off(event: EventType, handler: Handler): CommonEventEmitter;
|
||||
/* To maintain parity with the built in NodeJS event emitter which uses removeListener
|
||||
* rather than `off`.
|
||||
* If you're implementing new code you should use `off`.
|
||||
*/
|
||||
addListener(event: EventType, handler: Handler): CommonEventEmitter;
|
||||
removeListener(event: EventType, handler: Handler): CommonEventEmitter;
|
||||
emit(event: EventType, eventData?: any): 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 class EventEmitter implements CommonEventEmitter {
|
||||
private emitter: Emitter;
|
||||
private eventsMap = new Map<EventType, Handler[]>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor() {
|
||||
this.emitter = mitt(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 calls.
|
||||
*/
|
||||
on(event: EventType, handler: Handler): EventEmitter {
|
||||
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 calls.
|
||||
*/
|
||||
off(event: EventType, handler: Handler): EventEmitter {
|
||||
this.emitter.off(event, handler);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an event listener.
|
||||
* @deprecated please use `off` instead.
|
||||
*/
|
||||
removeListener(event: EventType, handler: Handler): EventEmitter {
|
||||
this.off(event, handler);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an event listener.
|
||||
* @deprecated please use `on` instead.
|
||||
*/
|
||||
addListener(event: EventType, handler: Handler): EventEmitter {
|
||||
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: EventType, eventData?: any): boolean {
|
||||
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 calls.
|
||||
*/
|
||||
once(event: EventType, handler: Handler): EventEmitter {
|
||||
const onceHandler: Handler = (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: EventType): number {
|
||||
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 calls.
|
||||
*/
|
||||
removeAllListeners(event?: EventType): EventEmitter {
|
||||
if (event) {
|
||||
this.eventsMap.delete(event);
|
||||
} else {
|
||||
this.eventsMap.clear();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private eventListenersCount(event: EventType): number {
|
||||
return this.eventsMap.has(event) ? this.eventsMap.get(event).length : 0;
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as EventEmitter from 'events';
|
||||
import { EventEmitter } from './EventEmitter';
|
||||
import { helper, assert, debugError } from './helper';
|
||||
import { Events } from './Events';
|
||||
import { ExecutionContext, EVALUATION_SCRIPT_URL } from './ExecutionContext';
|
||||
|
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import * as EventEmitter from 'events';
|
||||
import { EventEmitter } from './EventEmitter';
|
||||
import { helper, assert, debugError } from './helper';
|
||||
import Protocol from './protocol';
|
||||
import { Events } from './Events';
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as EventEmitter from 'events';
|
||||
import { EventEmitter } from './EventEmitter';
|
||||
import * as mime from 'mime';
|
||||
import { Events } from './Events';
|
||||
import { Connection, CDPSession } from './Connection';
|
||||
@ -183,7 +183,7 @@ class ScreenshotTaskQueue {
|
||||
* })();
|
||||
* ```
|
||||
*
|
||||
* The Page class emits various events which are documented in the {@link PageEmittedEvents} enum.
|
||||
* The Page class extends from Puppeteer's {@link EventEmitter } class and will emit various events which are documented in the {@link PageEmittedEvents} enum.
|
||||
*
|
||||
* @example
|
||||
* This example logs a message for a single page `load` event:
|
||||
|
@ -13,8 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import * as NodeWebSocket from 'ws';
|
||||
import { ConnectionTransport } from './ConnectionTransport';
|
||||
import NodeWebSocket from 'ws';
|
||||
|
||||
export class WebSocketTransport implements ConnectionTransport {
|
||||
static create(url: string): Promise<WebSocketTransport> {
|
||||
|
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { EventEmitter } from 'events';
|
||||
import { EventEmitter } from './EventEmitter';
|
||||
import { debugError } from './helper';
|
||||
import { ExecutionContext } from './ExecutionContext';
|
||||
import { JSHandle } from './JSHandle';
|
||||
|
@ -32,6 +32,7 @@ export * from './Coverage';
|
||||
export * from './Dialog';
|
||||
export * from './JSHandle';
|
||||
export * from './ExecutionContext';
|
||||
export * from './EventEmitter';
|
||||
export * from './FileChooser';
|
||||
export * from './FrameManager';
|
||||
export * from './JSHandle';
|
||||
|
@ -29,6 +29,7 @@ module.exports = {
|
||||
Dialog: require('./Dialog').Dialog,
|
||||
ElementHandle: require('./JSHandle').ElementHandle,
|
||||
ExecutionContext: require('./ExecutionContext').ExecutionContext,
|
||||
EventEmitter: require('./EventEmitter').EventEmitter,
|
||||
FileChooser: require('./FileChooser').FileChooser,
|
||||
Frame: require('./FrameManager').Frame,
|
||||
JSHandle: require('./JSHandle').JSHandle,
|
||||
|
@ -14,11 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { TimeoutError } from './Errors';
|
||||
import * as debug from 'debug';
|
||||
import debug from 'debug';
|
||||
import * as fs from 'fs';
|
||||
import { CDPSession } from './Connection';
|
||||
import { promisify } from 'util';
|
||||
import Protocol from './protocol';
|
||||
import { CommonEventEmitter } from './EventEmitter';
|
||||
|
||||
const openAsync = promisify(fs.open);
|
||||
const writeAsync = promisify(fs.write);
|
||||
@ -131,13 +132,13 @@ function installAsyncStackHooks(classType: AnyClass): void {
|
||||
}
|
||||
|
||||
export interface PuppeteerEventListener {
|
||||
emitter: NodeJS.EventEmitter;
|
||||
emitter: CommonEventEmitter;
|
||||
eventName: string | symbol;
|
||||
handler: (...args: any[]) => void;
|
||||
}
|
||||
|
||||
function addEventListener(
|
||||
emitter: NodeJS.EventEmitter,
|
||||
emitter: CommonEventEmitter,
|
||||
eventName: string | symbol,
|
||||
handler: (...args: any[]) => void
|
||||
): PuppeteerEventListener {
|
||||
@ -147,7 +148,7 @@ function addEventListener(
|
||||
|
||||
function removeEventListeners(
|
||||
listeners: Array<{
|
||||
emitter: NodeJS.EventEmitter;
|
||||
emitter: CommonEventEmitter;
|
||||
eventName: string | symbol;
|
||||
handler: (...args: any[]) => void;
|
||||
}>
|
||||
@ -166,7 +167,7 @@ function isNumber(obj: unknown): obj is number {
|
||||
}
|
||||
|
||||
async function waitForEvent<T extends any>(
|
||||
emitter: NodeJS.EventEmitter,
|
||||
emitter: CommonEventEmitter,
|
||||
eventName: string | symbol,
|
||||
predicate: (event: T) => boolean,
|
||||
timeout: number,
|
||||
|
@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as debug from 'debug';
|
||||
import debug from 'debug';
|
||||
|
||||
import * as removeFolder from 'rimraf';
|
||||
import removeFolder from 'rimraf';
|
||||
import * as childProcess from 'child_process';
|
||||
import { helper, assert, debugError } from '../helper';
|
||||
import { LaunchOptions } from './LaunchOptions';
|
||||
|
154
test/EventEmitter.spec.js
Normal file
154
test/EventEmitter.spec.js
Normal file
@ -0,0 +1,154 @@
|
||||
const { EventEmitter } = require('../lib/EventEmitter');
|
||||
const sinon = require('sinon');
|
||||
const expect = require('expect');
|
||||
|
||||
describe('EventEmitter', () => {
|
||||
let emitter;
|
||||
|
||||
beforeEach(() => {
|
||||
emitter = new EventEmitter();
|
||||
});
|
||||
|
||||
describe('on', () => {
|
||||
const onTests = (methodName) => {
|
||||
it(`${methodName}: adds an event listener that is fired when the event is emitted`, () => {
|
||||
const listener = sinon.spy();
|
||||
emitter[methodName]('foo', listener);
|
||||
emitter.emit('foo');
|
||||
expect(listener.callCount).toEqual(1);
|
||||
});
|
||||
|
||||
it(`${methodName} sends the event data to the handler`, () => {
|
||||
const listener = sinon.spy();
|
||||
const data = {};
|
||||
emitter[methodName]('foo', listener);
|
||||
emitter.emit('foo', data);
|
||||
expect(listener.callCount).toEqual(1);
|
||||
expect(listener.firstCall.args[0]).toBe(data);
|
||||
});
|
||||
|
||||
it(`${methodName}: supports chaining`, () => {
|
||||
const listener = sinon.spy();
|
||||
const returnValue = emitter[methodName]('foo', listener);
|
||||
expect(returnValue).toBe(emitter);
|
||||
});
|
||||
};
|
||||
onTests('on');
|
||||
// we support addListener for legacy reasons
|
||||
onTests('addListener');
|
||||
});
|
||||
|
||||
describe('off', () => {
|
||||
const offTests = (methodName) => {
|
||||
it(`${methodName}: removes the listener so it is no longer called`, () => {
|
||||
const listener = sinon.spy();
|
||||
emitter.on('foo', listener);
|
||||
emitter.emit('foo');
|
||||
expect(listener.callCount).toEqual(1);
|
||||
emitter.off('foo', listener);
|
||||
emitter.emit('foo');
|
||||
expect(listener.callCount).toEqual(1);
|
||||
});
|
||||
|
||||
it(`${methodName}: supports chaining`, () => {
|
||||
const listener = sinon.spy();
|
||||
emitter.on('foo', listener);
|
||||
const returnValue = emitter.off('foo', listener);
|
||||
expect(returnValue).toBe(emitter);
|
||||
});
|
||||
};
|
||||
offTests('off');
|
||||
// we support removeListener for legacy reasons
|
||||
offTests('removeListener');
|
||||
});
|
||||
|
||||
describe('once', () => {
|
||||
it('only calls the listener once and then removes it', () => {
|
||||
const listener = sinon.spy();
|
||||
emitter.once('foo', listener);
|
||||
emitter.emit('foo');
|
||||
expect(listener.callCount).toEqual(1);
|
||||
emitter.emit('foo');
|
||||
expect(listener.callCount).toEqual(1);
|
||||
});
|
||||
|
||||
it('supports chaining', () => {
|
||||
const listener = sinon.spy();
|
||||
const returnValue = emitter.once('foo', listener);
|
||||
expect(returnValue).toBe(emitter);
|
||||
});
|
||||
});
|
||||
|
||||
describe('emit', () => {
|
||||
it('calls all the listeners for an event', () => {
|
||||
const listener1 = sinon.spy();
|
||||
const listener2 = sinon.spy();
|
||||
const listener3 = sinon.spy();
|
||||
emitter.on('foo', listener1).on('foo', listener2).on('bar', listener3);
|
||||
|
||||
emitter.emit('foo');
|
||||
|
||||
expect(listener1.callCount).toEqual(1);
|
||||
expect(listener2.callCount).toEqual(1);
|
||||
expect(listener3.callCount).toEqual(0);
|
||||
});
|
||||
|
||||
it('passes data through to the listener', () => {
|
||||
const listener = sinon.spy();
|
||||
emitter.on('foo', listener);
|
||||
const data = {};
|
||||
|
||||
emitter.emit('foo', data);
|
||||
expect(listener.callCount).toEqual(1);
|
||||
expect(listener.firstCall.args[0]).toBe(data);
|
||||
});
|
||||
|
||||
it('returns true if the event has listeners', () => {
|
||||
const listener = sinon.spy();
|
||||
emitter.on('foo', listener);
|
||||
expect(emitter.emit('foo')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false if the event has listeners', () => {
|
||||
const listener = sinon.spy();
|
||||
emitter.on('foo', listener);
|
||||
expect(emitter.emit('notFoo')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('listenerCount', () => {
|
||||
it('returns the number of listeners for the given event', () => {
|
||||
emitter.on('foo', () => {});
|
||||
emitter.on('foo', () => {});
|
||||
emitter.on('bar', () => {});
|
||||
expect(emitter.listenerCount('foo')).toEqual(2);
|
||||
expect(emitter.listenerCount('bar')).toEqual(1);
|
||||
expect(emitter.listenerCount('noListeners')).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeAllListeners', () => {
|
||||
it('removes every listener from all events by default', () => {
|
||||
emitter.on('foo', () => {}).on('bar', () => {});
|
||||
|
||||
emitter.removeAllListeners();
|
||||
expect(emitter.emit('foo')).toBe(false);
|
||||
expect(emitter.emit('bar')).toBe(false);
|
||||
});
|
||||
|
||||
it('returns the emitter for chaining', () => {
|
||||
expect(emitter.removeAllListeners()).toBe(emitter);
|
||||
});
|
||||
|
||||
it('can filter to remove only listeners for a given event name', () => {
|
||||
emitter
|
||||
.on('foo', () => {})
|
||||
.on('bar', () => {})
|
||||
.on('bar', () => {});
|
||||
|
||||
emitter.removeAllListeners('bar');
|
||||
expect(emitter.emit('foo')).toBe(true);
|
||||
expect(emitter.emit('bar')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
@ -18,6 +18,7 @@ const path = require('path');
|
||||
const utils = require('./utils');
|
||||
const { waitEvent } = utils;
|
||||
const expect = require('expect');
|
||||
const sinon = require('sinon');
|
||||
const {
|
||||
getTestState,
|
||||
setupTestBrowserHooks,
|
||||
@ -130,6 +131,29 @@ describe('Page', function () {
|
||||
});
|
||||
});
|
||||
|
||||
// This test fails on Firefox on CI consistently but cannot be replicated
|
||||
// locally. Skipping for now to unblock the Mitt release and given FF support
|
||||
// isn't fully done yet but raising an issue to ask the FF folks to have a
|
||||
// look at this.
|
||||
describeFailsFirefox('removing and adding event handlers', () => {
|
||||
it('should correctly fire event handlers as they are added and then removed', async () => {
|
||||
const { page, server } = getTestState();
|
||||
|
||||
const handler = sinon.spy();
|
||||
page.on('response', handler);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(handler.callCount).toBe(1);
|
||||
page.off('response', handler);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
// Still one because we removed the handler.
|
||||
expect(handler.callCount).toBe(1);
|
||||
page.on('response', handler);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
// Two now because we added the handler back.
|
||||
expect(handler.callCount).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Page.Events.error', function () {
|
||||
it('should throw when page crashes', async () => {
|
||||
const { page } = getTestState();
|
||||
|
@ -7,7 +7,8 @@
|
||||
"moduleResolution": "node",
|
||||
"module": "CommonJS",
|
||||
"declaration": true,
|
||||
"declarationMap": true
|
||||
"declarationMap": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
|
@ -180,6 +180,27 @@ const expectedNonExistingMethods = new Map([
|
||||
['Page', new Set(['emulateMedia'])],
|
||||
]);
|
||||
|
||||
// All the methods from our EventEmitter that we don't document for each subclass.
|
||||
const EVENT_LISTENER_METHODS = new Set([
|
||||
'emit',
|
||||
'listenerCount',
|
||||
'off',
|
||||
'on',
|
||||
'once',
|
||||
'removeListener',
|
||||
'addListener',
|
||||
'removeAllListeners',
|
||||
]);
|
||||
|
||||
/* Methods that are defined in code but are not documented */
|
||||
const expectedNotFoundMethods = new Map([
|
||||
['Browser', EVENT_LISTENER_METHODS],
|
||||
['BrowserContext', EVENT_LISTENER_METHODS],
|
||||
['CDPSession', EVENT_LISTENER_METHODS],
|
||||
['Page', EVENT_LISTENER_METHODS],
|
||||
['WebWorker', EVENT_LISTENER_METHODS],
|
||||
]);
|
||||
|
||||
/**
|
||||
* @param {!Documentation} actual
|
||||
* @param {!Documentation} expected
|
||||
@ -205,14 +226,24 @@ function compareDocumentations(actual, expected) {
|
||||
const methodDiff = diff(actualMethods, expectedMethods);
|
||||
|
||||
for (const methodName of methodDiff.extra) {
|
||||
const missingMethodsForClass = expectedNonExistingMethods.get(className);
|
||||
if (missingMethodsForClass && missingMethodsForClass.has(methodName))
|
||||
const nonExistingMethodsForClass = expectedNonExistingMethods.get(
|
||||
className
|
||||
);
|
||||
if (
|
||||
nonExistingMethodsForClass &&
|
||||
nonExistingMethodsForClass.has(methodName)
|
||||
)
|
||||
continue;
|
||||
|
||||
errors.push(`Non-existing method found: ${className}.${methodName}()`);
|
||||
}
|
||||
for (const methodName of methodDiff.missing)
|
||||
|
||||
for (const methodName of methodDiff.missing) {
|
||||
const missingMethodsForClass = expectedNotFoundMethods.get(className);
|
||||
if (missingMethodsForClass && missingMethodsForClass.has(methodName))
|
||||
continue;
|
||||
errors.push(`Method not found: ${className}.${methodName}()`);
|
||||
}
|
||||
|
||||
for (const methodName of methodDiff.equal) {
|
||||
const actualMethod = actualClass.methods.get(methodName);
|
||||
@ -619,6 +650,62 @@ function compareDocumentations(actual, expected) {
|
||||
expectedName: 'SnapshotOptions',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method EventEmitter.emit() event',
|
||||
{
|
||||
actualName: 'string|symbol',
|
||||
expectedName: 'Object',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method EventEmitter.listenerCount() event',
|
||||
{
|
||||
actualName: 'string|symbol',
|
||||
expectedName: 'Object',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method EventEmitter.off() event',
|
||||
{
|
||||
actualName: 'string|symbol',
|
||||
expectedName: 'Object',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method EventEmitter.on() event',
|
||||
{
|
||||
actualName: 'string|symbol',
|
||||
expectedName: 'Object',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method EventEmitter.once() event',
|
||||
{
|
||||
actualName: 'string|symbol',
|
||||
expectedName: 'Object',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method EventEmitter.removeListener() event',
|
||||
{
|
||||
actualName: 'string|symbol',
|
||||
expectedName: 'Object',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method EventEmitter.addListener() event',
|
||||
{
|
||||
actualName: 'string|symbol',
|
||||
expectedName: 'Object',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method EventEmitter.removeAllListeners() event',
|
||||
{
|
||||
actualName: 'string|symbol',
|
||||
expectedName: 'Object',
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
const expectedForSource = expectedNamingMismatches.get(source);
|
||||
|
Loading…
Reference in New Issue
Block a user