feat(logger): introduce context-level logger (#1896)
This commit is contained in:
parent
2320d9cbf3
commit
5b085fdf03
26
docs/api.md
26
docs/api.md
|
|
@ -27,7 +27,7 @@
|
||||||
- [class: Worker](#class-worker)
|
- [class: Worker](#class-worker)
|
||||||
- [class: BrowserServer](#class-browserserver)
|
- [class: BrowserServer](#class-browserserver)
|
||||||
- [class: BrowserType](#class-browsertype)
|
- [class: BrowserType](#class-browsertype)
|
||||||
- [class: LoggerSink](#class-loggersink)
|
- [class: Logger](#class-logger)
|
||||||
- [class: ChromiumBrowser](#class-chromiumbrowser)
|
- [class: ChromiumBrowser](#class-chromiumbrowser)
|
||||||
- [class: ChromiumBrowserContext](#class-chromiumbrowsercontext)
|
- [class: ChromiumBrowserContext](#class-chromiumbrowsercontext)
|
||||||
- [class: ChromiumCoverage](#class-chromiumcoverage)
|
- [class: ChromiumCoverage](#class-chromiumcoverage)
|
||||||
|
|
@ -218,6 +218,7 @@ Indicates that the browser is connected.
|
||||||
- `username` <[string]>
|
- `username` <[string]>
|
||||||
- `password` <[string]>
|
- `password` <[string]>
|
||||||
- `colorScheme` <"dark"|"light"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'.
|
- `colorScheme` <"dark"|"light"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'.
|
||||||
|
- `logger` <[Logger]> Logger sink for Playwright logging.
|
||||||
- returns: <[Promise]<[BrowserContext]>>
|
- returns: <[Promise]<[BrowserContext]>>
|
||||||
|
|
||||||
Creates a new browser context. It won't share cookies/cache with other browser contexts.
|
Creates a new browser context. It won't share cookies/cache with other browser contexts.
|
||||||
|
|
@ -259,6 +260,7 @@ Creates a new browser context. It won't share cookies/cache with other browser c
|
||||||
- `username` <[string]>
|
- `username` <[string]>
|
||||||
- `password` <[string]>
|
- `password` <[string]>
|
||||||
- `colorScheme` <"dark"|"light"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'.
|
- `colorScheme` <"dark"|"light"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'.
|
||||||
|
- `logger` <[Logger]> Logger sink for Playwright logging.
|
||||||
- returns: <[Promise]<[Page]>>
|
- returns: <[Promise]<[Page]>>
|
||||||
|
|
||||||
Creates a new page in a new browser context. Closing this page will close the context as well.
|
Creates a new page in a new browser context. Closing this page will close the context as well.
|
||||||
|
|
@ -3757,7 +3759,7 @@ const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.
|
||||||
- `options` <[Object]>
|
- `options` <[Object]>
|
||||||
- `wsEndpoint` <[string]> A browser websocket endpoint to connect to. **required**
|
- `wsEndpoint` <[string]> A browser websocket endpoint to connect to. **required**
|
||||||
- `slowMo` <[number]> Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on. Defaults to 0.
|
- `slowMo` <[number]> Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on. Defaults to 0.
|
||||||
- `loggerSink` <[LoggerSink]> Sink for log messages.
|
- `logger` <[Logger]> Logger sink for Playwright logging.
|
||||||
- returns: <[Promise]<[Browser]>>
|
- returns: <[Promise]<[Browser]>>
|
||||||
|
|
||||||
This methods attaches Playwright to an existing browser instance.
|
This methods attaches Playwright to an existing browser instance.
|
||||||
|
|
@ -3774,7 +3776,7 @@ This methods attaches Playwright to an existing browser instance.
|
||||||
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
|
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
|
||||||
- `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`.
|
- `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`.
|
||||||
- `handleSIGHUP` <[boolean]> Close the browser process on SIGHUP. Defaults to `true`.
|
- `handleSIGHUP` <[boolean]> Close the browser process on SIGHUP. Defaults to `true`.
|
||||||
- `loggerSink` <[LoggerSink]> Sink for log messages.
|
- `logger` <[Logger]> Logger sink for Playwright logging.
|
||||||
- `timeout` <[number]> Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
|
- `timeout` <[number]> Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
|
||||||
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
|
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
|
||||||
- `devtools` <[boolean]> **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
|
- `devtools` <[boolean]> **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
|
||||||
|
|
@ -3807,7 +3809,7 @@ const browser = await chromium.launch({ // Or 'firefox' or 'webkit'.
|
||||||
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
|
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
|
||||||
- `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`.
|
- `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`.
|
||||||
- `handleSIGHUP` <[boolean]> Close the browser process on SIGHUP. Defaults to `true`.
|
- `handleSIGHUP` <[boolean]> Close the browser process on SIGHUP. Defaults to `true`.
|
||||||
- `loggerSink` <[LoggerSink]> Sink for log messages.
|
- `logger` <[Logger]> Logger sink for Playwright logging.
|
||||||
- `timeout` <[number]> Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
|
- `timeout` <[number]> Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
|
||||||
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
|
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
|
||||||
- `devtools` <[boolean]> **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
|
- `devtools` <[boolean]> **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
|
||||||
|
|
@ -3826,7 +3828,7 @@ Launches browser instance that uses persistent storage located at `userDataDir`.
|
||||||
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
|
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
|
||||||
- `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`.
|
- `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`.
|
||||||
- `handleSIGHUP` <[boolean]> Close the browser process on SIGHUP. Defaults to `true`.
|
- `handleSIGHUP` <[boolean]> Close the browser process on SIGHUP. Defaults to `true`.
|
||||||
- `loggerSink` <[LoggerSink]> Sink for log messages.
|
- `logger` <[Logger]> Logger sink for Playwright logging.
|
||||||
- `timeout` <[number]> Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
|
- `timeout` <[number]> Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
|
||||||
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
|
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
|
||||||
- `devtools` <[boolean]> **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
|
- `devtools` <[boolean]> **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
|
||||||
|
|
@ -3853,7 +3855,7 @@ const { chromium } = require('playwright'); // Or 'webkit' or 'firefox'.
|
||||||
|
|
||||||
Returns browser name. For example: `'chromium'`, `'webkit'` or `'firefox'`.
|
Returns browser name. For example: `'chromium'`, `'webkit'` or `'firefox'`.
|
||||||
|
|
||||||
### class: LoggerSink
|
### class: Logger
|
||||||
|
|
||||||
Playwright generates a lot of logs and they are accessible via the pluggable logger sink.
|
Playwright generates a lot of logs and they are accessible via the pluggable logger sink.
|
||||||
|
|
||||||
|
|
@ -3862,7 +3864,7 @@ const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const browser = await chromium.launch({
|
const browser = await chromium.launch({
|
||||||
loggerSink: {
|
logger: {
|
||||||
isEnabled: (name, severity) => name === 'browser',
|
isEnabled: (name, severity) => name === 'browser',
|
||||||
log: (name, severity, message, args) => console.log(`${name} ${message}`)
|
log: (name, severity, message, args) => console.log(`${name} ${message}`)
|
||||||
}
|
}
|
||||||
|
|
@ -3872,18 +3874,18 @@ const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- GEN:toc -->
|
<!-- GEN:toc -->
|
||||||
- [loggerSink.isEnabled(name, severity)](#loggersinkisenabledname-severity)
|
- [logger.isEnabled(name, severity)](#loggerisenabledname-severity)
|
||||||
- [loggerSink.log(name, severity, message, args, hints)](#loggersinklogname-severity-message-args-hints)
|
- [logger.log(name, severity, message, args, hints)](#loggerlogname-severity-message-args-hints)
|
||||||
<!-- GEN:stop -->
|
<!-- GEN:stop -->
|
||||||
|
|
||||||
#### loggerSink.isEnabled(name, severity)
|
#### logger.isEnabled(name, severity)
|
||||||
- `name` <[string]> logger name
|
- `name` <[string]> logger name
|
||||||
- `severity` <"verbose"|"info"|"warning"|"error">
|
- `severity` <"verbose"|"info"|"warning"|"error">
|
||||||
- returns: <[boolean]>
|
- returns: <[boolean]>
|
||||||
|
|
||||||
Determines whether sink is interested in the logger with the given name and severity.
|
Determines whether sink is interested in the logger with the given name and severity.
|
||||||
|
|
||||||
#### loggerSink.log(name, severity, message, args, hints)
|
#### logger.log(name, severity, message, args, hints)
|
||||||
- `name` <[string]> logger name
|
- `name` <[string]> logger name
|
||||||
- `severity` <"verbose"|"info"|"warning"|"error">
|
- `severity` <"verbose"|"info"|"warning"|"error">
|
||||||
- `message` <[string]|[Error]> log message format
|
- `message` <[string]|[Error]> log message format
|
||||||
|
|
@ -4247,7 +4249,7 @@ const { chromium } = require('playwright');
|
||||||
[Frame]: #class-frame "Frame"
|
[Frame]: #class-frame "Frame"
|
||||||
[JSHandle]: #class-jshandle "JSHandle"
|
[JSHandle]: #class-jshandle "JSHandle"
|
||||||
[Keyboard]: #class-keyboard "Keyboard"
|
[Keyboard]: #class-keyboard "Keyboard"
|
||||||
[LoggerSink]: #class-loggersink "LoggerSink"
|
[Logger]: #class-logger "Logger"
|
||||||
[Map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map "Map"
|
[Map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map "Map"
|
||||||
[Mouse]: #class-mouse "Mouse"
|
[Mouse]: #class-mouse "Mouse"
|
||||||
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object "Object"
|
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object "Object"
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ export { Dialog } from './dialog';
|
||||||
export { Download } from './download';
|
export { Download } from './download';
|
||||||
export { ElementHandle } from './dom';
|
export { ElementHandle } from './dom';
|
||||||
export { FileChooser } from './fileChooser';
|
export { FileChooser } from './fileChooser';
|
||||||
export { LoggerSink } from './logger';
|
export { Logger } from './logger';
|
||||||
export { TimeoutError } from './errors';
|
export { TimeoutError } from './errors';
|
||||||
export { Frame } from './frames';
|
export { Frame } from './frames';
|
||||||
export { Keyboard, Mouse } from './input';
|
export { Keyboard, Mouse } from './input';
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import { EventEmitter } from 'events';
|
||||||
import { Download } from './download';
|
import { Download } from './download';
|
||||||
import type { BrowserServer } from './server/browserServer';
|
import type { BrowserServer } from './server/browserServer';
|
||||||
import { Events } from './events';
|
import { Events } from './events';
|
||||||
import { Logger, Log } from './logger';
|
import { InnerLogger, Log } from './logger';
|
||||||
|
|
||||||
export interface Browser extends EventEmitter {
|
export interface Browser extends EventEmitter {
|
||||||
newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
|
newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
|
||||||
|
|
@ -30,13 +30,13 @@ export interface Browser extends EventEmitter {
|
||||||
close(): Promise<void>;
|
close(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class BrowserBase extends EventEmitter implements Browser, Logger {
|
export abstract class BrowserBase extends EventEmitter implements Browser, InnerLogger {
|
||||||
_downloadsPath: string = '';
|
_downloadsPath: string = '';
|
||||||
private _downloads = new Map<string, Download>();
|
private _downloads = new Map<string, Download>();
|
||||||
_ownedServer: BrowserServer | null = null;
|
_ownedServer: BrowserServer | null = null;
|
||||||
readonly _logger: Logger;
|
readonly _logger: InnerLogger;
|
||||||
|
|
||||||
constructor(logger: Logger) {
|
constructor(logger: InnerLogger) {
|
||||||
super();
|
super();
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import { Events } from './events';
|
||||||
import { ExtendedEventEmitter } from './extendedEventEmitter';
|
import { ExtendedEventEmitter } from './extendedEventEmitter';
|
||||||
import { Download } from './download';
|
import { Download } from './download';
|
||||||
import { BrowserBase } from './browser';
|
import { BrowserBase } from './browser';
|
||||||
import { Log, Logger } from './logger';
|
import { Log, InnerLogger, Logger, RootLogger } from './logger';
|
||||||
|
|
||||||
export type BrowserContextOptions = {
|
export type BrowserContextOptions = {
|
||||||
viewport?: types.Size | null,
|
viewport?: types.Size | null,
|
||||||
|
|
@ -43,10 +43,11 @@ export type BrowserContextOptions = {
|
||||||
isMobile?: boolean,
|
isMobile?: boolean,
|
||||||
hasTouch?: boolean,
|
hasTouch?: boolean,
|
||||||
colorScheme?: types.ColorScheme,
|
colorScheme?: types.ColorScheme,
|
||||||
acceptDownloads?: boolean
|
acceptDownloads?: boolean,
|
||||||
|
logger?: Logger,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface BrowserContext extends Logger {
|
export interface BrowserContext extends InnerLogger {
|
||||||
setDefaultNavigationTimeout(timeout: number): void;
|
setDefaultNavigationTimeout(timeout: number): void;
|
||||||
setDefaultTimeout(timeout: number): void;
|
setDefaultTimeout(timeout: number): void;
|
||||||
pages(): Page[];
|
pages(): Page[];
|
||||||
|
|
@ -79,11 +80,13 @@ export abstract class BrowserContextBase extends ExtendedEventEmitter implements
|
||||||
readonly _permissions = new Map<string, string[]>();
|
readonly _permissions = new Map<string, string[]>();
|
||||||
readonly _downloads = new Set<Download>();
|
readonly _downloads = new Set<Download>();
|
||||||
readonly _browserBase: BrowserBase;
|
readonly _browserBase: BrowserBase;
|
||||||
|
private _logger: InnerLogger;
|
||||||
|
|
||||||
constructor(browserBase: BrowserBase, options: BrowserContextOptions) {
|
constructor(browserBase: BrowserBase, options: BrowserContextOptions) {
|
||||||
super();
|
super();
|
||||||
this._browserBase = browserBase;
|
this._browserBase = browserBase;
|
||||||
this._options = options;
|
this._options = options;
|
||||||
|
this._logger = options.logger ? new RootLogger(options.logger) : browserBase;
|
||||||
this._closePromise = new Promise(fulfill => this._closePromiseFulfill = fulfill);
|
this._closePromise = new Promise(fulfill => this._closePromiseFulfill = fulfill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,11 +158,11 @@ export abstract class BrowserContextBase extends ExtendedEventEmitter implements
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLogEnabled(log: Log): boolean {
|
_isLogEnabled(log: Log): boolean {
|
||||||
return this._browserBase._isLogEnabled(log);
|
return this._logger._isLogEnabled(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
_log(log: Log, message: string | Error, ...args: any[]) {
|
_log(log: Log, message: string | Error, ...args: any[]) {
|
||||||
return this._browserBase._log(log, message, ...args);
|
return this._logger._log(log, message, ...args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import { readProtocolStream } from './crProtocolHelper';
|
||||||
import { Events } from './events';
|
import { Events } from './events';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import { CRExecutionContext } from './crExecutionContext';
|
import { CRExecutionContext } from './crExecutionContext';
|
||||||
import { Logger, logError } from '../logger';
|
import { InnerLogger, logError } from '../logger';
|
||||||
|
|
||||||
export class CRBrowser extends BrowserBase {
|
export class CRBrowser extends BrowserBase {
|
||||||
readonly _connection: CRConnection;
|
readonly _connection: CRConnection;
|
||||||
|
|
@ -47,7 +47,7 @@ export class CRBrowser extends BrowserBase {
|
||||||
private _tracingPath: string | null = '';
|
private _tracingPath: string | null = '';
|
||||||
private _tracingClient: CRSession | undefined;
|
private _tracingClient: CRSession | undefined;
|
||||||
|
|
||||||
static async connect(transport: ConnectionTransport, isPersistent: boolean, logger: Logger, slowMo?: number): Promise<CRBrowser> {
|
static async connect(transport: ConnectionTransport, isPersistent: boolean, logger: InnerLogger, slowMo?: number): Promise<CRBrowser> {
|
||||||
const connection = new CRConnection(SlowMoTransport.wrap(transport, slowMo), logger);
|
const connection = new CRConnection(SlowMoTransport.wrap(transport, slowMo), logger);
|
||||||
const browser = new CRBrowser(connection, logger, isPersistent);
|
const browser = new CRBrowser(connection, logger, isPersistent);
|
||||||
const session = connection.rootSession;
|
const session = connection.rootSession;
|
||||||
|
|
@ -84,7 +84,7 @@ export class CRBrowser extends BrowserBase {
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(connection: CRConnection, logger: Logger, isPersistent: boolean) {
|
constructor(connection: CRConnection, logger: InnerLogger, isPersistent: boolean) {
|
||||||
super(logger);
|
super(logger);
|
||||||
this._connection = connection;
|
this._connection = connection;
|
||||||
this._session = this._connection.rootSession;
|
this._session = this._connection.rootSession;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import { assert } from '../helper';
|
||||||
import { ConnectionTransport, ProtocolRequest, ProtocolResponse, protocolLog } from '../transport';
|
import { ConnectionTransport, ProtocolRequest, ProtocolResponse, protocolLog } from '../transport';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { Logger } from '../logger';
|
import { InnerLogger } from '../logger';
|
||||||
|
|
||||||
export const ConnectionEvents = {
|
export const ConnectionEvents = {
|
||||||
Disconnected: Symbol('ConnectionEvents.Disconnected')
|
Disconnected: Symbol('ConnectionEvents.Disconnected')
|
||||||
|
|
@ -35,9 +35,9 @@ export class CRConnection extends EventEmitter {
|
||||||
private readonly _sessions = new Map<string, CRSession>();
|
private readonly _sessions = new Map<string, CRSession>();
|
||||||
readonly rootSession: CRSession;
|
readonly rootSession: CRSession;
|
||||||
_closed = false;
|
_closed = false;
|
||||||
private _logger: Logger;
|
private _logger: InnerLogger;
|
||||||
|
|
||||||
constructor(transport: ConnectionTransport, logger: Logger) {
|
constructor(transport: ConnectionTransport, logger: InnerLogger) {
|
||||||
super();
|
super();
|
||||||
this._transport = transport;
|
this._transport = transport;
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import { Protocol } from './protocol';
|
||||||
|
|
||||||
import { EVALUATION_SCRIPT_URL } from './crExecutionContext';
|
import { EVALUATION_SCRIPT_URL } from './crExecutionContext';
|
||||||
import * as types from '../types';
|
import * as types from '../types';
|
||||||
import { logError, Logger } from '../logger';
|
import { logError, InnerLogger } from '../logger';
|
||||||
|
|
||||||
type JSRange = {
|
type JSRange = {
|
||||||
startOffset: number,
|
startOffset: number,
|
||||||
|
|
@ -51,7 +51,7 @@ export class CRCoverage {
|
||||||
private _jsCoverage: JSCoverage;
|
private _jsCoverage: JSCoverage;
|
||||||
private _cssCoverage: CSSCoverage;
|
private _cssCoverage: CSSCoverage;
|
||||||
|
|
||||||
constructor(client: CRSession, logger: Logger) {
|
constructor(client: CRSession, logger: InnerLogger) {
|
||||||
this._jsCoverage = new JSCoverage(client, logger);
|
this._jsCoverage = new JSCoverage(client, logger);
|
||||||
this._cssCoverage = new CSSCoverage(client, logger);
|
this._cssCoverage = new CSSCoverage(client, logger);
|
||||||
}
|
}
|
||||||
|
|
@ -81,9 +81,9 @@ class JSCoverage {
|
||||||
_eventListeners: RegisteredListener[];
|
_eventListeners: RegisteredListener[];
|
||||||
_resetOnNavigation: boolean;
|
_resetOnNavigation: boolean;
|
||||||
_reportAnonymousScripts = false;
|
_reportAnonymousScripts = false;
|
||||||
private _logger: Logger;
|
private _logger: InnerLogger;
|
||||||
|
|
||||||
constructor(client: CRSession, logger: Logger) {
|
constructor(client: CRSession, logger: InnerLogger) {
|
||||||
this._client = client;
|
this._client = client;
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
this._enabled = false;
|
this._enabled = false;
|
||||||
|
|
@ -175,9 +175,9 @@ class CSSCoverage {
|
||||||
_stylesheetSources: Map<string, string>;
|
_stylesheetSources: Map<string, string>;
|
||||||
_eventListeners: RegisteredListener[];
|
_eventListeners: RegisteredListener[];
|
||||||
_resetOnNavigation: boolean;
|
_resetOnNavigation: boolean;
|
||||||
private _logger: Logger;
|
private _logger: InnerLogger;
|
||||||
|
|
||||||
constructor(client: CRSession, logger: Logger) {
|
constructor(client: CRSession, logger: InnerLogger) {
|
||||||
this._client = client;
|
this._client = client;
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
this._enabled = false;
|
this._enabled = false;
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import { ConnectionEvents, FFConnection } from './ffConnection';
|
||||||
import { headersArray } from './ffNetworkManager';
|
import { headersArray } from './ffNetworkManager';
|
||||||
import { FFPage } from './ffPage';
|
import { FFPage } from './ffPage';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import { Logger } from '../logger';
|
import { InnerLogger } from '../logger';
|
||||||
|
|
||||||
export class FFBrowser extends BrowserBase {
|
export class FFBrowser extends BrowserBase {
|
||||||
_connection: FFConnection;
|
_connection: FFConnection;
|
||||||
|
|
@ -38,14 +38,14 @@ export class FFBrowser extends BrowserBase {
|
||||||
readonly _firstPagePromise: Promise<void>;
|
readonly _firstPagePromise: Promise<void>;
|
||||||
private _firstPageCallback = () => {};
|
private _firstPageCallback = () => {};
|
||||||
|
|
||||||
static async connect(transport: ConnectionTransport, logger: Logger, attachToDefaultContext: boolean, slowMo?: number): Promise<FFBrowser> {
|
static async connect(transport: ConnectionTransport, logger: InnerLogger, attachToDefaultContext: boolean, slowMo?: number): Promise<FFBrowser> {
|
||||||
const connection = new FFConnection(SlowMoTransport.wrap(transport, slowMo), logger);
|
const connection = new FFConnection(SlowMoTransport.wrap(transport, slowMo), logger);
|
||||||
const browser = new FFBrowser(connection, logger, attachToDefaultContext);
|
const browser = new FFBrowser(connection, logger, attachToDefaultContext);
|
||||||
await connection.send('Browser.enable', { attachToDefaultContext });
|
await connection.send('Browser.enable', { attachToDefaultContext });
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(connection: FFConnection, logger: Logger, isPersistent: boolean) {
|
constructor(connection: FFConnection, logger: InnerLogger, isPersistent: boolean) {
|
||||||
super(logger);
|
super(logger);
|
||||||
this._connection = connection;
|
this._connection = connection;
|
||||||
this._ffPages = new Map();
|
this._ffPages = new Map();
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import { EventEmitter } from 'events';
|
||||||
import { assert } from '../helper';
|
import { assert } from '../helper';
|
||||||
import { ConnectionTransport, ProtocolRequest, ProtocolResponse, protocolLog } from '../transport';
|
import { ConnectionTransport, ProtocolRequest, ProtocolResponse, protocolLog } from '../transport';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import { Logger } from '../logger';
|
import { InnerLogger } from '../logger';
|
||||||
|
|
||||||
export const ConnectionEvents = {
|
export const ConnectionEvents = {
|
||||||
Disconnected: Symbol('Disconnected'),
|
Disconnected: Symbol('Disconnected'),
|
||||||
|
|
@ -33,7 +33,7 @@ export class FFConnection extends EventEmitter {
|
||||||
private _lastId: number;
|
private _lastId: number;
|
||||||
private _callbacks: Map<number, {resolve: Function, reject: Function, error: Error, method: string}>;
|
private _callbacks: Map<number, {resolve: Function, reject: Function, error: Error, method: string}>;
|
||||||
private _transport: ConnectionTransport;
|
private _transport: ConnectionTransport;
|
||||||
private _logger: Logger;
|
private _logger: InnerLogger;
|
||||||
readonly _sessions: Map<string, FFSession>;
|
readonly _sessions: Map<string, FFSession>;
|
||||||
_closed: boolean;
|
_closed: boolean;
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ export class FFConnection extends EventEmitter {
|
||||||
removeListener: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
removeListener: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
||||||
once: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
once: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
||||||
|
|
||||||
constructor(transport: ConnectionTransport, logger: Logger) {
|
constructor(transport: ConnectionTransport, logger: InnerLogger) {
|
||||||
super();
|
super();
|
||||||
this._transport = transport;
|
this._transport = transport;
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
import * as types from './types';
|
import * as types from './types';
|
||||||
import * as dom from './dom';
|
import * as dom from './dom';
|
||||||
import { helper } from './helper';
|
import { helper } from './helper';
|
||||||
import { Logger } from './logger';
|
import { InnerLogger } from './logger';
|
||||||
|
|
||||||
export interface ExecutionContextDelegate {
|
export interface ExecutionContextDelegate {
|
||||||
evaluate(context: ExecutionContext, returnByValue: boolean, pageFunction: string | Function, ...args: any[]): Promise<any>;
|
evaluate(context: ExecutionContext, returnByValue: boolean, pageFunction: string | Function, ...args: any[]): Promise<any>;
|
||||||
|
|
@ -29,9 +29,9 @@ export interface ExecutionContextDelegate {
|
||||||
|
|
||||||
export class ExecutionContext {
|
export class ExecutionContext {
|
||||||
readonly _delegate: ExecutionContextDelegate;
|
readonly _delegate: ExecutionContextDelegate;
|
||||||
readonly _logger: Logger;
|
readonly _logger: InnerLogger;
|
||||||
|
|
||||||
constructor(delegate: ExecutionContextDelegate, logger: Logger) {
|
constructor(delegate: ExecutionContextDelegate, logger: InnerLogger) {
|
||||||
this._delegate = delegate;
|
this._delegate = delegate;
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,26 +25,26 @@ export type Log = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface Logger {
|
export interface Logger {
|
||||||
_isLogEnabled(log: Log): boolean;
|
|
||||||
_log(log: Log, message: string | Error, ...args: any[]): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LoggerSink {
|
|
||||||
isEnabled(name: string, severity: LoggerSeverity): boolean;
|
isEnabled(name: string, severity: LoggerSeverity): boolean;
|
||||||
log(name: string, severity: LoggerSeverity, message: string | Error, args: any[], hints: { color?: string }): void;
|
log(name: string, severity: LoggerSeverity, message: string | Error, args: any[], hints: { color?: string }): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InnerLogger {
|
||||||
|
_isLogEnabled(log: Log): boolean;
|
||||||
|
_log(log: Log, message: string | Error, ...args: any[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
export const errorLog: Log = { name: 'generic', severity: 'error' };
|
export const errorLog: Log = { name: 'generic', severity: 'error' };
|
||||||
|
|
||||||
export function logError(logger: Logger): (error: Error) => void {
|
export function logError(logger: InnerLogger): (error: Error) => void {
|
||||||
return error => logger._log(errorLog, error, []);
|
return error => logger._log(errorLog, error, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RootLogger implements Logger {
|
export class RootLogger implements InnerLogger {
|
||||||
private _userSink: LoggerSink | undefined;
|
private _userSink: Logger | undefined;
|
||||||
private _debugSink: DebugLoggerSink;
|
private _debugSink: DebugLoggerSink;
|
||||||
|
|
||||||
constructor(userSink: LoggerSink | undefined) {
|
constructor(userSink: Logger | undefined) {
|
||||||
this._userSink = userSink;
|
this._userSink = userSink;
|
||||||
this._debugSink = new DebugLoggerSink();
|
this._debugSink = new DebugLoggerSink();
|
||||||
}
|
}
|
||||||
|
|
@ -72,17 +72,17 @@ const colorMap = new Map<string, number>([
|
||||||
['reset', 0],
|
['reset', 0],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
class DebugLoggerSink implements LoggerSink {
|
class DebugLoggerSink implements Logger {
|
||||||
private _debuggers = new Map<string, debug.IDebugger>();
|
private _debuggers = new Map<string, debug.IDebugger>();
|
||||||
|
|
||||||
isEnabled(name: string, severity: LoggerSeverity): boolean {
|
isEnabled(name: string, severity: LoggerSeverity): boolean {
|
||||||
return debug.enabled('pw:' + name);
|
return debug.enabled(`pw:${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
log(name: string, severity: LoggerSeverity, message: string | Error, args: any[], hints: { color?: string }) {
|
log(name: string, severity: LoggerSeverity, message: string | Error, args: any[], hints: { color?: string }) {
|
||||||
let cachedDebugger = this._debuggers.get(name);
|
let cachedDebugger = this._debuggers.get(name);
|
||||||
if (!cachedDebugger) {
|
if (!cachedDebugger) {
|
||||||
cachedDebugger = debug('pw:' + name);
|
cachedDebugger = debug(`pw:${name}`);
|
||||||
this._debuggers.set(name, cachedDebugger);
|
this._debuggers.set(name, cachedDebugger);
|
||||||
|
|
||||||
let color = hints.color || 'reset';
|
let color = hints.color || 'reset';
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import * as accessibility from './accessibility';
|
||||||
import { ExtendedEventEmitter } from './extendedEventEmitter';
|
import { ExtendedEventEmitter } from './extendedEventEmitter';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { FileChooser } from './fileChooser';
|
import { FileChooser } from './fileChooser';
|
||||||
import { logError, Logger, Log } from './logger';
|
import { logError, InnerLogger, Log } from './logger';
|
||||||
|
|
||||||
export interface PageDelegate {
|
export interface PageDelegate {
|
||||||
readonly rawMouse: input.RawMouse;
|
readonly rawMouse: input.RawMouse;
|
||||||
|
|
@ -87,7 +87,7 @@ type PageState = {
|
||||||
extraHTTPHeaders: network.Headers | null;
|
extraHTTPHeaders: network.Headers | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Page extends ExtendedEventEmitter implements Logger {
|
export class Page extends ExtendedEventEmitter implements InnerLogger {
|
||||||
private _closed = false;
|
private _closed = false;
|
||||||
private _closedCallback: () => void;
|
private _closedCallback: () => void;
|
||||||
private _closedPromise: Promise<void>;
|
private _closedPromise: Promise<void>;
|
||||||
|
|
@ -537,13 +537,13 @@ export class Page extends ExtendedEventEmitter implements Logger {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Worker extends EventEmitter {
|
export class Worker extends EventEmitter {
|
||||||
private _logger: Logger;
|
private _logger: InnerLogger;
|
||||||
private _url: string;
|
private _url: string;
|
||||||
private _executionContextPromise: Promise<js.ExecutionContext>;
|
private _executionContextPromise: Promise<js.ExecutionContext>;
|
||||||
private _executionContextCallback: (value?: js.ExecutionContext) => void;
|
private _executionContextCallback: (value?: js.ExecutionContext) => void;
|
||||||
_existingExecutionContext: js.ExecutionContext | null = null;
|
_existingExecutionContext: js.ExecutionContext | null = null;
|
||||||
|
|
||||||
constructor(logger: Logger, url: string) {
|
constructor(logger: InnerLogger, url: string) {
|
||||||
super();
|
super();
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
this._url = url;
|
this._url = url;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import { BrowserContext } from '../browserContext';
|
import { BrowserContext } from '../browserContext';
|
||||||
import { BrowserServer } from './browserServer';
|
import { BrowserServer } from './browserServer';
|
||||||
import { LoggerSink } from '../logger';
|
import { Logger } from '../logger';
|
||||||
|
|
||||||
export type BrowserArgOptions = {
|
export type BrowserArgOptions = {
|
||||||
headless?: boolean,
|
headless?: boolean,
|
||||||
|
|
@ -31,14 +31,14 @@ type LaunchOptionsBase = BrowserArgOptions & {
|
||||||
handleSIGTERM?: boolean,
|
handleSIGTERM?: boolean,
|
||||||
handleSIGHUP?: boolean,
|
handleSIGHUP?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
loggerSink?: LoggerSink,
|
logger?: Logger,
|
||||||
env?: {[key: string]: string} | undefined
|
env?: {[key: string]: string} | undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ConnectOptions = {
|
export type ConnectOptions = {
|
||||||
wsEndpoint: string,
|
wsEndpoint: string,
|
||||||
slowMo?: number,
|
slowMo?: number,
|
||||||
loggerSink?: LoggerSink,
|
logger?: Logger,
|
||||||
};
|
};
|
||||||
export type LaunchOptions = LaunchOptionsBase & { slowMo?: number };
|
export type LaunchOptions = LaunchOptionsBase & { slowMo?: number };
|
||||||
export type LaunchServerOptions = LaunchOptionsBase & { port?: number };
|
export type LaunchServerOptions = LaunchOptionsBase & { port?: number };
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import { BrowserServer, WebSocketWrapper } from './browserServer';
|
||||||
import { Events } from '../events';
|
import { Events } from '../events';
|
||||||
import { ConnectionTransport, ProtocolRequest, WebSocketTransport } from '../transport';
|
import { ConnectionTransport, ProtocolRequest, WebSocketTransport } from '../transport';
|
||||||
import { BrowserContext } from '../browserContext';
|
import { BrowserContext } from '../browserContext';
|
||||||
import { Logger, logError, RootLogger } from '../logger';
|
import { InnerLogger, logError, RootLogger } from '../logger';
|
||||||
|
|
||||||
export class Chromium implements BrowserType<CRBrowser> {
|
export class Chromium implements BrowserType<CRBrowser> {
|
||||||
private _executablePath: (string|undefined);
|
private _executablePath: (string|undefined);
|
||||||
|
|
@ -71,7 +71,7 @@ export class Chromium implements BrowserType<CRBrowser> {
|
||||||
return browser._defaultContext!;
|
return browser._defaultContext!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _launchServer(options: LaunchServerOptions, launchType: LaunchType, userDataDir?: string): Promise<{ browserServer: BrowserServer, transport?: ConnectionTransport, downloadsPath: string, logger: Logger }> {
|
private async _launchServer(options: LaunchServerOptions, launchType: LaunchType, userDataDir?: string): Promise<{ browserServer: BrowserServer, transport?: ConnectionTransport, downloadsPath: string, logger: InnerLogger }> {
|
||||||
const {
|
const {
|
||||||
ignoreDefaultArgs = false,
|
ignoreDefaultArgs = false,
|
||||||
args = [],
|
args = [],
|
||||||
|
|
@ -83,7 +83,7 @@ export class Chromium implements BrowserType<CRBrowser> {
|
||||||
port = 0,
|
port = 0,
|
||||||
} = options;
|
} = options;
|
||||||
assert(!port || launchType === 'server', 'Cannot specify a port without launching as a server.');
|
assert(!port || launchType === 'server', 'Cannot specify a port without launching as a server.');
|
||||||
const logger = new RootLogger(options.loggerSink);
|
const logger = new RootLogger(options.logger);
|
||||||
|
|
||||||
let temporaryUserDataDir: string | null = null;
|
let temporaryUserDataDir: string | null = null;
|
||||||
if (!userDataDir) {
|
if (!userDataDir) {
|
||||||
|
|
@ -137,7 +137,7 @@ export class Chromium implements BrowserType<CRBrowser> {
|
||||||
|
|
||||||
async connect(options: ConnectOptions): Promise<CRBrowser> {
|
async connect(options: ConnectOptions): Promise<CRBrowser> {
|
||||||
return await WebSocketTransport.connect(options.wsEndpoint, transport => {
|
return await WebSocketTransport.connect(options.wsEndpoint, transport => {
|
||||||
return CRBrowser.connect(transport, false, new RootLogger(options.loggerSink), options.slowMo);
|
return CRBrowser.connect(transport, false, new RootLogger(options.logger), options.slowMo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,7 +179,7 @@ export class Chromium implements BrowserType<CRBrowser> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapTransportWithWebSocket(transport: ConnectionTransport, logger: Logger, port: number): WebSocketWrapper {
|
function wrapTransportWithWebSocket(transport: ConnectionTransport, logger: InnerLogger, port: number): WebSocketWrapper {
|
||||||
const server = new ws.Server({ port });
|
const server = new ws.Server({ port });
|
||||||
const guid = helper.guid();
|
const guid = helper.guid();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import { BrowserServer, WebSocketWrapper } from './browserServer';
|
||||||
import { BrowserArgOptions, BrowserType, LaunchOptions, LaunchServerOptions, ConnectOptions } from './browserType';
|
import { BrowserArgOptions, BrowserType, LaunchOptions, LaunchServerOptions, ConnectOptions } from './browserType';
|
||||||
import { launchProcess, waitForLine } from './processLauncher';
|
import { launchProcess, waitForLine } from './processLauncher';
|
||||||
import { ConnectionTransport, SequenceNumberMixer, WebSocketTransport } from '../transport';
|
import { ConnectionTransport, SequenceNumberMixer, WebSocketTransport } from '../transport';
|
||||||
import { RootLogger, Logger, logError } from '../logger';
|
import { RootLogger, InnerLogger, logError } from '../logger';
|
||||||
|
|
||||||
const mkdtempAsync = util.promisify(fs.mkdtemp);
|
const mkdtempAsync = util.promisify(fs.mkdtemp);
|
||||||
|
|
||||||
|
|
@ -79,7 +79,7 @@ export class Firefox implements BrowserType<FFBrowser> {
|
||||||
return browserContext;
|
return browserContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _launchServer(options: LaunchServerOptions, launchType: LaunchType, userDataDir?: string): Promise<{ browserServer: BrowserServer, downloadsPath: string, logger: Logger }> {
|
private async _launchServer(options: LaunchServerOptions, launchType: LaunchType, userDataDir?: string): Promise<{ browserServer: BrowserServer, downloadsPath: string, logger: InnerLogger }> {
|
||||||
const {
|
const {
|
||||||
ignoreDefaultArgs = false,
|
ignoreDefaultArgs = false,
|
||||||
args = [],
|
args = [],
|
||||||
|
|
@ -92,7 +92,7 @@ export class Firefox implements BrowserType<FFBrowser> {
|
||||||
port = 0,
|
port = 0,
|
||||||
} = options;
|
} = options;
|
||||||
assert(!port || launchType === 'server', 'Cannot specify a port without launching as a server.');
|
assert(!port || launchType === 'server', 'Cannot specify a port without launching as a server.');
|
||||||
const logger = new RootLogger(options.loggerSink);
|
const logger = new RootLogger(options.logger);
|
||||||
|
|
||||||
const firefoxArguments = [];
|
const firefoxArguments = [];
|
||||||
|
|
||||||
|
|
@ -153,7 +153,7 @@ export class Firefox implements BrowserType<FFBrowser> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(options: ConnectOptions): Promise<FFBrowser> {
|
async connect(options: ConnectOptions): Promise<FFBrowser> {
|
||||||
const logger = new RootLogger(options.loggerSink);
|
const logger = new RootLogger(options.logger);
|
||||||
return await WebSocketTransport.connect(options.wsEndpoint, transport => {
|
return await WebSocketTransport.connect(options.wsEndpoint, transport => {
|
||||||
return FFBrowser.connect(transport, logger, false, options.slowMo);
|
return FFBrowser.connect(transport, logger, false, options.slowMo);
|
||||||
});
|
});
|
||||||
|
|
@ -198,7 +198,7 @@ export class Firefox implements BrowserType<FFBrowser> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapTransportWithWebSocket(transport: ConnectionTransport, logger: Logger, port: number): WebSocketWrapper {
|
function wrapTransportWithWebSocket(transport: ConnectionTransport, logger: InnerLogger, port: number): WebSocketWrapper {
|
||||||
const server = new ws.Server({ port });
|
const server = new ws.Server({ port });
|
||||||
const guid = helper.guid();
|
const guid = helper.guid();
|
||||||
const idMixer = new SequenceNumberMixer<{id: number, socket: ws}>();
|
const idMixer = new SequenceNumberMixer<{id: number, socket: ws}>();
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
import { helper, RegisteredListener } from '../helper';
|
import { helper, RegisteredListener } from '../helper';
|
||||||
import { ConnectionTransport, ProtocolRequest, ProtocolResponse } from '../transport';
|
import { ConnectionTransport, ProtocolRequest, ProtocolResponse } from '../transport';
|
||||||
import { logError, Logger } from '../logger';
|
import { logError, InnerLogger } from '../logger';
|
||||||
|
|
||||||
export class PipeTransport implements ConnectionTransport {
|
export class PipeTransport implements ConnectionTransport {
|
||||||
private _pipeWrite: NodeJS.WritableStream | null;
|
private _pipeWrite: NodeJS.WritableStream | null;
|
||||||
|
|
@ -28,7 +28,7 @@ export class PipeTransport implements ConnectionTransport {
|
||||||
onmessage?: (message: ProtocolResponse) => void;
|
onmessage?: (message: ProtocolResponse) => void;
|
||||||
onclose?: () => void;
|
onclose?: () => void;
|
||||||
|
|
||||||
constructor(pipeWrite: NodeJS.WritableStream, pipeRead: NodeJS.ReadableStream, logger: Logger) {
|
constructor(pipeWrite: NodeJS.WritableStream, pipeRead: NodeJS.ReadableStream, logger: InnerLogger) {
|
||||||
this._pipeWrite = pipeWrite;
|
this._pipeWrite = pipeWrite;
|
||||||
this._eventListeners = [
|
this._eventListeners = [
|
||||||
helper.addEventListener(pipeRead, 'data', buffer => this._dispatch(buffer)),
|
helper.addEventListener(pipeRead, 'data', buffer => this._dispatch(buffer)),
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as childProcess from 'child_process';
|
import * as childProcess from 'child_process';
|
||||||
import { Log, Logger } from '../logger';
|
import { Log, InnerLogger } from '../logger';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
@ -59,7 +59,7 @@ export type LaunchProcessOptions = {
|
||||||
// Note: attemptToGracefullyClose should reject if it does not close the browser.
|
// Note: attemptToGracefullyClose should reject if it does not close the browser.
|
||||||
attemptToGracefullyClose: () => Promise<any>,
|
attemptToGracefullyClose: () => Promise<any>,
|
||||||
onkill: (exitCode: number | null, signal: string | null) => void,
|
onkill: (exitCode: number | null, signal: string | null) => void,
|
||||||
logger: Logger,
|
logger: InnerLogger,
|
||||||
};
|
};
|
||||||
|
|
||||||
type LaunchResult = {
|
type LaunchResult = {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import { LaunchType } from '../browser';
|
||||||
import { BrowserServer, WebSocketWrapper } from './browserServer';
|
import { BrowserServer, WebSocketWrapper } from './browserServer';
|
||||||
import { Events } from '../events';
|
import { Events } from '../events';
|
||||||
import { BrowserContext } from '../browserContext';
|
import { BrowserContext } from '../browserContext';
|
||||||
import { Logger, logError, RootLogger } from '../logger';
|
import { InnerLogger, logError, RootLogger } from '../logger';
|
||||||
|
|
||||||
export class WebKit implements BrowserType<WKBrowser> {
|
export class WebKit implements BrowserType<WKBrowser> {
|
||||||
private _executablePath: (string|undefined);
|
private _executablePath: (string|undefined);
|
||||||
|
|
@ -71,7 +71,7 @@ export class WebKit implements BrowserType<WKBrowser> {
|
||||||
return browser._defaultContext!;
|
return browser._defaultContext!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _launchServer(options: LaunchServerOptions, launchType: LaunchType, userDataDir?: string): Promise<{ browserServer: BrowserServer, transport?: ConnectionTransport, downloadsPath: string, logger: Logger }> {
|
private async _launchServer(options: LaunchServerOptions, launchType: LaunchType, userDataDir?: string): Promise<{ browserServer: BrowserServer, transport?: ConnectionTransport, downloadsPath: string, logger: InnerLogger }> {
|
||||||
const {
|
const {
|
||||||
ignoreDefaultArgs = false,
|
ignoreDefaultArgs = false,
|
||||||
args = [],
|
args = [],
|
||||||
|
|
@ -83,7 +83,7 @@ export class WebKit implements BrowserType<WKBrowser> {
|
||||||
port = 0,
|
port = 0,
|
||||||
} = options;
|
} = options;
|
||||||
assert(!port || launchType === 'server', 'Cannot specify a port without launching as a server.');
|
assert(!port || launchType === 'server', 'Cannot specify a port without launching as a server.');
|
||||||
const logger = new RootLogger(options.loggerSink);
|
const logger = new RootLogger(options.logger);
|
||||||
|
|
||||||
let temporaryUserDataDir: string | null = null;
|
let temporaryUserDataDir: string | null = null;
|
||||||
if (!userDataDir) {
|
if (!userDataDir) {
|
||||||
|
|
@ -137,7 +137,7 @@ export class WebKit implements BrowserType<WKBrowser> {
|
||||||
|
|
||||||
async connect(options: ConnectOptions): Promise<WKBrowser> {
|
async connect(options: ConnectOptions): Promise<WKBrowser> {
|
||||||
return await WebSocketTransport.connect(options.wsEndpoint, transport => {
|
return await WebSocketTransport.connect(options.wsEndpoint, transport => {
|
||||||
return WKBrowser.connect(transport, new RootLogger(options.loggerSink), options.slowMo);
|
return WKBrowser.connect(transport, new RootLogger(options.logger), options.slowMo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,7 +170,7 @@ const mkdtempAsync = util.promisify(fs.mkdtemp);
|
||||||
|
|
||||||
const WEBKIT_PROFILE_PATH = path.join(os.tmpdir(), 'playwright_dev_profile-');
|
const WEBKIT_PROFILE_PATH = path.join(os.tmpdir(), 'playwright_dev_profile-');
|
||||||
|
|
||||||
function wrapTransportWithWebSocket(transport: ConnectionTransport, logger: Logger, port: number): WebSocketWrapper {
|
function wrapTransportWithWebSocket(transport: ConnectionTransport, logger: InnerLogger, port: number): WebSocketWrapper {
|
||||||
const server = new ws.Server({ port });
|
const server = new ws.Server({ port });
|
||||||
const guid = helper.guid();
|
const guid = helper.guid();
|
||||||
const idMixer = new SequenceNumberMixer<{id: number, socket: ws}>();
|
const idMixer = new SequenceNumberMixer<{id: number, socket: ws}>();
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import * as types from '../types';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import { kPageProxyMessageReceived, PageProxyMessageReceivedPayload, WKConnection, WKSession } from './wkConnection';
|
import { kPageProxyMessageReceived, PageProxyMessageReceivedPayload, WKConnection, WKSession } from './wkConnection';
|
||||||
import { WKPage } from './wkPage';
|
import { WKPage } from './wkPage';
|
||||||
import { Logger } from '../logger';
|
import { InnerLogger } from '../logger';
|
||||||
|
|
||||||
const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Safari/605.1.15';
|
const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Safari/605.1.15';
|
||||||
|
|
||||||
|
|
@ -41,12 +41,12 @@ export class WKBrowser extends BrowserBase {
|
||||||
private _firstPageCallback: () => void = () => {};
|
private _firstPageCallback: () => void = () => {};
|
||||||
private readonly _firstPagePromise: Promise<void>;
|
private readonly _firstPagePromise: Promise<void>;
|
||||||
|
|
||||||
static async connect(transport: ConnectionTransport, logger: Logger, slowMo: number = 0, attachToDefaultContext: boolean = false): Promise<WKBrowser> {
|
static async connect(transport: ConnectionTransport, logger: InnerLogger, slowMo: number = 0, attachToDefaultContext: boolean = false): Promise<WKBrowser> {
|
||||||
const browser = new WKBrowser(SlowMoTransport.wrap(transport, slowMo), logger, attachToDefaultContext);
|
const browser = new WKBrowser(SlowMoTransport.wrap(transport, slowMo), logger, attachToDefaultContext);
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(transport: ConnectionTransport, logger: Logger, attachToDefaultContext: boolean) {
|
constructor(transport: ConnectionTransport, logger: InnerLogger, attachToDefaultContext: boolean) {
|
||||||
super(logger);
|
super(logger);
|
||||||
this._connection = new WKConnection(transport, logger, this._onDisconnect.bind(this));
|
this._connection = new WKConnection(transport, logger, this._onDisconnect.bind(this));
|
||||||
this._browserSession = this._connection.browserSession;
|
this._browserSession = this._connection.browserSession;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import { EventEmitter } from 'events';
|
||||||
import { assert } from '../helper';
|
import { assert } from '../helper';
|
||||||
import { ConnectionTransport, ProtocolRequest, ProtocolResponse, protocolLog } from '../transport';
|
import { ConnectionTransport, ProtocolRequest, ProtocolResponse, protocolLog } from '../transport';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import { Logger } from '../logger';
|
import { InnerLogger } from '../logger';
|
||||||
|
|
||||||
// WKPlaywright uses this special id to issue Browser.close command which we
|
// WKPlaywright uses this special id to issue Browser.close command which we
|
||||||
// should ignore.
|
// should ignore.
|
||||||
|
|
@ -37,9 +37,9 @@ export class WKConnection {
|
||||||
private _closed = false;
|
private _closed = false;
|
||||||
|
|
||||||
readonly browserSession: WKSession;
|
readonly browserSession: WKSession;
|
||||||
private _logger: Logger;
|
private _logger: InnerLogger;
|
||||||
|
|
||||||
constructor(transport: ConnectionTransport, logger: Logger, onDisconnect: () => void) {
|
constructor(transport: ConnectionTransport, logger: InnerLogger, onDisconnect: () => void) {
|
||||||
this._transport = transport;
|
this._transport = transport;
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
this._transport.onmessage = this._dispatchMessage.bind(this);
|
this._transport.onmessage = this._dispatchMessage.bind(this);
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@ const {FFOX, CHROMIUM, WEBKIT, WIN, LINUX} = require('./utils').testOptions(brow
|
||||||
|
|
||||||
async function testSignal(state, action, exitOnClose) {
|
async function testSignal(state, action, exitOnClose) {
|
||||||
const options = Object.assign({}, state.defaultBrowserOptions, {
|
const options = Object.assign({}, state.defaultBrowserOptions, {
|
||||||
// Disable DUMPIO to cleanly read stdout.
|
|
||||||
dumpio: false,
|
|
||||||
handleSIGINT: true,
|
handleSIGINT: true,
|
||||||
handleSIGTERM: true,
|
handleSIGTERM: true,
|
||||||
handleSIGHUP: true,
|
handleSIGHUP: true,
|
||||||
|
|
|
||||||
50
test/logger.spec.js
Normal file
50
test/logger.spec.js
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT} = require('./utils').testOptions(browserType);
|
||||||
|
|
||||||
|
describe('Logger', function() {
|
||||||
|
it('should log', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const log = [];
|
||||||
|
const browser = await browserType.launch({...defaultBrowserOptions, logger: {
|
||||||
|
log: (name, severity, message) => log.push({name, severity, message}),
|
||||||
|
isEnabled: (name, severity) => severity !== 'verbose'
|
||||||
|
}});
|
||||||
|
await browser.close();
|
||||||
|
expect(log.length > 0).toBeTruthy();
|
||||||
|
expect(log.filter(item => item.name.includes('browser')).length > 0).toBeTruthy();
|
||||||
|
expect(log.filter(item => item.severity === 'info').length > 0).toBeTruthy();
|
||||||
|
expect(log.filter(item => item.message.includes('<launching>')).length > 0).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should log context-level', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const log = [];
|
||||||
|
const browser = await browserType.launch(defaultBrowserOptions);
|
||||||
|
const page = await browser.newPage({
|
||||||
|
logger: {
|
||||||
|
log: (name, severity, message) => log.push({name, severity, message}),
|
||||||
|
isEnabled: (name, severity) => severity !== 'verbose'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await page.setContent('<button>Button</button>');
|
||||||
|
await page.click('button');
|
||||||
|
await browser.close();
|
||||||
|
|
||||||
|
expect(log.length > 0).toBeTruthy();
|
||||||
|
expect(log.filter(item => item.message.includes('waiting for element')).length > 0).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -210,6 +210,7 @@ module.exports = {
|
||||||
'./defaultbrowsercontext.spec.js',
|
'./defaultbrowsercontext.spec.js',
|
||||||
'./fixtures.spec.js',
|
'./fixtures.spec.js',
|
||||||
'./launcher.spec.js',
|
'./launcher.spec.js',
|
||||||
|
'./logger.spec.js',
|
||||||
'./headful.spec.js',
|
'./headful.spec.js',
|
||||||
'./multiclient.spec.js',
|
'./multiclient.spec.js',
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ function collect(browserNames) {
|
||||||
const browserEnvironment = new Environment(browserName);
|
const browserEnvironment = new Environment(browserName);
|
||||||
browserEnvironment.beforeAll(async state => {
|
browserEnvironment.beforeAll(async state => {
|
||||||
state._logger = null;
|
state._logger = null;
|
||||||
state.browser = await state.browserType.launch({...launchOptions, loggerSink: {
|
state.browser = await state.browserType.launch({...launchOptions, logger: {
|
||||||
isEnabled: (name, severity) => {
|
isEnabled: (name, severity) => {
|
||||||
return name === 'browser' ||
|
return name === 'browser' ||
|
||||||
(name === 'protocol' && config.dumpProtocolOnFailure);
|
(name === 'protocol' && config.dumpProtocolOnFailure);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue