feat(logger): introduce context-level logger (#1896)

This commit is contained in:
Pavel Feldman 2020-04-20 23:24:53 -07:00 committed by GitHub
parent 2320d9cbf3
commit 5b085fdf03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 144 additions and 90 deletions

View file

@ -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"

View file

@ -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';

View file

@ -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;
} }

View file

@ -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);
} }
} }

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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;
} }

View file

@ -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';

View file

@ -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;

View file

@ -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 };

View file

@ -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();

View file

@ -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}>();

View file

@ -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)),

View file

@ -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 = {

View file

@ -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}>();

View file

@ -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;

View file

@ -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);

View file

@ -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
View 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();
});
});

View file

@ -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',
], ],

View file

@ -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);