feat(electron): expose ElectronApplication console events (#29322)

Fixes https://github.com/microsoft/playwright/issues/5905
This commit is contained in:
Max Schmitt 2024-02-05 21:30:54 +01:00 committed by GitHub
parent 2690e4c827
commit 47f8ba2a04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 300 additions and 43 deletions

View File

@ -106,7 +106,7 @@ The reason to be reported to the operations interrupted by the context closure.
- alias-java: consoleMessage
- argument: <[ConsoleMessage]>
Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also emitted if the page throws an error or a warning.
Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`.
The arguments passed into `console.log` and the page are available on the [ConsoleMessage] event handler argument.

View File

@ -41,6 +41,26 @@ const { _electron: electron } = require('playwright');
This event is issued when the application closes.
## event: ElectronApplication.console
* since: v1.42
- argument: <[ConsoleMessage]>
Emitted when JavaScript within the Electron main process calls one of console API methods, e.g. `console.log` or `console.dir`.
The arguments passed into `console.log` are available on the [ConsoleMessage] event handler argument.
**Usage**
```js
electronApp.on('console', async msg => {
const values = [];
for (const arg of msg.args())
values.push(await arg.jsonValue());
console.log(...values);
});
await electronApp.evaluate(() => console.log('hello', 5, { foo: 'bar' }));
```
## event: ElectronApplication.window
* since: v1.9
- argument: <[Page]>

View File

@ -163,7 +163,7 @@ Emitted when the page closes.
- alias-java: consoleMessage
- argument: <[ConsoleMessage]>
Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also emitted if the page throws an error or a warning.
Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`.
The arguments passed into `console.log` are available on the [ConsoleMessage] event handler argument.

View File

@ -25,10 +25,10 @@ type ConsoleMessageLocation = channels.BrowserContextConsoleEvent['location'];
export class ConsoleMessage implements api.ConsoleMessage {
private _page: Page | null;
private _event: channels.BrowserContextConsoleEvent;
private _event: channels.BrowserContextConsoleEvent | channels.ElectronApplicationConsoleEvent;
constructor(event: channels.BrowserContextConsoleEvent) {
this._page = event.page ? Page.from(event.page) : null;
constructor(event: channels.BrowserContextConsoleEvent | channels.ElectronApplicationConsoleEvent) {
this._page = ('page' in event && event.page) ? Page.from(event.page) : null;
this._event = event;
}

View File

@ -26,6 +26,7 @@ import { envObjectToArray } from './clientHelper';
import { Events } from './events';
import { JSHandle, parseResult, serializeArgument } from './jsHandle';
import type { Page } from './page';
import { ConsoleMessage } from './consoleMessage';
import type { Env, WaitForEventOptions, Headers, BrowserContextOptions } from './types';
import { Waiter } from './waiter';
import { TargetClosedError } from './errors';
@ -81,6 +82,10 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
this._isClosed = true;
this.emit(Events.ElectronApplication.Close);
});
this._channel.on('console', event => this.emit(Events.ElectronApplication.Console, new ConsoleMessage(event)));
this._setEventToSubscriptionMapping(new Map<string, channels.ElectronApplicationUpdateSubscriptionParams['event']>([
[Events.ElectronApplication.Console, 'console'],
]));
}
process(): childProcess.ChildProcess {

View File

@ -91,6 +91,7 @@ export const Events = {
ElectronApplication: {
Close: 'close',
Console: 'console',
Window: 'window',
},
};

View File

@ -765,7 +765,6 @@ scheme.BrowserContextBindingCallEvent = tObject({
binding: tChannel(['BindingCall']),
});
scheme.BrowserContextConsoleEvent = tObject({
page: tChannel(['Page']),
type: tString,
text: tString,
args: tArray(tChannel(['ElementHandle', 'JSHandle'])),
@ -774,6 +773,7 @@ scheme.BrowserContextConsoleEvent = tObject({
lineNumber: tNumber,
columnNumber: tNumber,
}),
page: tChannel(['Page']),
});
scheme.BrowserContextCloseEvent = tOptional(tObject({}));
scheme.BrowserContextDialogEvent = tObject({
@ -2258,6 +2258,16 @@ scheme.ElectronApplicationInitializer = tObject({
context: tChannel(['BrowserContext']),
});
scheme.ElectronApplicationCloseEvent = tOptional(tObject({}));
scheme.ElectronApplicationConsoleEvent = tObject({
type: tString,
text: tString,
args: tArray(tChannel(['ElementHandle', 'JSHandle'])),
location: tObject({
url: tString,
lineNumber: tNumber,
columnNumber: tNumber,
}),
});
scheme.ElectronApplicationBrowserWindowParams = tObject({
page: tChannel(['Page']),
});
@ -2280,6 +2290,11 @@ scheme.ElectronApplicationEvaluateExpressionHandleParams = tObject({
scheme.ElectronApplicationEvaluateExpressionHandleResult = tObject({
handle: tChannel(['ElementHandle', 'JSHandle']),
});
scheme.ElectronApplicationUpdateSubscriptionParams = tObject({
event: tEnum(['console']),
enabled: tBoolean,
});
scheme.ElectronApplicationUpdateSubscriptionResult = tOptional(tObject({}));
scheme.ElectronApplicationCloseParams = tOptional(tObject({}));
scheme.ElectronApplicationCloseResult = tOptional(tObject({}));
scheme.AndroidInitializer = tOptional(tObject({}));

View File

@ -14,20 +14,18 @@
* limitations under the License.
*/
import { SdkObject } from './instrumentation';
import type * as js from './javascript';
import type { ConsoleMessageLocation } from './types';
import type { Page } from './page';
export class ConsoleMessage extends SdkObject {
export class ConsoleMessage {
private _type: string;
private _text?: string;
private _args: js.JSHandle[];
private _location: ConsoleMessageLocation;
private _page: Page;
private _page: Page | null;
constructor(page: Page, type: string, text: string | undefined, args: js.JSHandle[], location?: ConsoleMessageLocation) {
super(page, 'console-message');
constructor(page: Page | null, type: string, text: string | undefined, args: js.JSHandle[], location?: ConsoleMessageLocation) {
this._page = page;
this._type = type;
this._text = text;

View File

@ -90,8 +90,9 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
this._dispatchEvent('pageError', { error: serializeError(error), page: PageDispatcher.from(this, page) });
});
this.addObjectListener(BrowserContext.Events.Console, (message: ConsoleMessage) => {
if (this._shouldDispatchEvent(message.page(), 'console')) {
const pageDispatcher = PageDispatcher.from(this, message.page());
const page = message.page()!;
if (this._shouldDispatchEvent(page, 'console')) {
const pageDispatcher = PageDispatcher.from(this, page);
this._dispatchEvent('console', {
page: pageDispatcher,
type: message.type(),

View File

@ -21,6 +21,7 @@ import { ElectronApplication } from '../electron/electron';
import type * as channels from '@protocol/channels';
import { BrowserContextDispatcher } from './browserContextDispatcher';
import type { PageDispatcher } from './pageDispatcher';
import type { ConsoleMessage } from '../console';
import { parseArgument, serializeResult } from './jsHandleDispatcher';
import { ElementHandleDispatcher } from './elementHandlerDispatcher';
@ -40,6 +41,7 @@ export class ElectronDispatcher extends Dispatcher<Electron, channels.ElectronCh
export class ElectronApplicationDispatcher extends Dispatcher<ElectronApplication, channels.ElectronApplicationChannel, ElectronDispatcher> implements channels.ElectronApplicationChannel {
_type_EventTarget = true;
_type_ElectronApplication = true;
private readonly _subscriptions = new Set<channels.ElectronApplicationUpdateSubscriptionParams['event']>();
constructor(scope: ElectronDispatcher, electronApplication: ElectronApplication) {
super(scope, electronApplication, 'ElectronApplication', {
@ -49,6 +51,16 @@ export class ElectronApplicationDispatcher extends Dispatcher<ElectronApplicatio
this._dispatchEvent('close');
this._dispose();
});
this.addObjectListener(ElectronApplication.Events.Console, (message: ConsoleMessage) => {
if (!this._subscriptions.has('console'))
return;
this._dispatchEvent('console', {
type: message.type(),
text: message.text(),
args: message.args().map(a => ElementHandleDispatcher.fromJSHandle(this, a)),
location: message.location()
});
});
}
async browserWindow(params: channels.ElectronApplicationBrowserWindowParams): Promise<channels.ElectronApplicationBrowserWindowResult> {
@ -67,6 +79,13 @@ export class ElectronApplicationDispatcher extends Dispatcher<ElectronApplicatio
return { handle: ElementHandleDispatcher.fromJSHandle(this, result) };
}
async updateSubscription(params: channels.ElectronApplicationUpdateSubscriptionParams): Promise<void> {
if (params.enabled)
this._subscriptions.add(params.event);
else
this._subscriptions.delete(params.event);
}
async close(): Promise<void> {
await this._object.close();
}

View File

@ -43,12 +43,15 @@ import * as readline from 'readline';
import { RecentLogsCollector } from '../../utils/debugLogger';
import { serverSideCallMetadata, SdkObject } from '../instrumentation';
import type * as channels from '@protocol/channels';
import { toConsoleMessageLocation } from '../chromium/crProtocolHelper';
import { ConsoleMessage } from '../console';
const ARTIFACTS_FOLDER = path.join(os.tmpdir(), 'playwright-artifacts-');
export class ElectronApplication extends SdkObject {
static Events = {
Close: 'close',
Console: 'console',
};
private _browserContext: CRBrowserContext;
@ -82,6 +85,7 @@ export class ElectronApplication extends SdkObject {
});
this._nodeElectronHandlePromise.resolve(new js.JSHandle(this._nodeExecutionContext!, 'object', 'ElectronModule', remoteObject.objectId!));
});
this._nodeSession.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
this._browserContext.setCustomCloseHandler(async () => {
await this._browserContext.stopVideoRecording();
const electronHandle = await this._nodeElectronHandlePromise;
@ -89,6 +93,30 @@ export class ElectronApplication extends SdkObject {
});
}
async _onConsoleAPI(event: Protocol.Runtime.consoleAPICalledPayload) {
if (event.executionContextId === 0) {
// DevTools protocol stores the last 1000 console messages. These
// messages are always reported even for removed execution contexts. In
// this case, they are marked with executionContextId = 0 and are
// reported upon enabling Runtime agent.
//
// Ignore these messages since:
// - there's no execution context we can use to operate with message
// arguments
// - these messages are reported before Playwright clients can subscribe
// to the 'console'
// page event.
//
// @see https://github.com/GoogleChrome/puppeteer/issues/3865
return;
}
if (!this._nodeExecutionContext)
return;
const args = event.args.map(arg => this._nodeExecutionContext!.createHandle(arg));
const message = new ConsoleMessage(null, event.type, undefined, args, toConsoleMessageLocation(event.stackTrace));
this.emit(ElectronApplication.Events.Console, message);
}
async initialize() {
await this._nodeSession.send('Runtime.enable', {});
// Delay loading the app until browser is started and the browser targets are configured to auto-attach.

View File

@ -450,7 +450,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
args: message.args().map(a => ({ preview: a.toString(), value: a.rawValue() })),
location: message.location(),
time: monotonicTime(),
pageId: message.page().guid,
pageId: message.page()?.guid,
};
this._appendTraceEvent(event);
}

View File

@ -901,8 +901,7 @@ export interface Page {
on(event: 'close', listener: (page: Page) => void): this;
/**
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also
* emitted if the page throws an error or a warning.
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`.
*
* The arguments passed into `console.log` are available on the {@link ConsoleMessage} event handler argument.
*
@ -1197,8 +1196,7 @@ export interface Page {
addListener(event: 'close', listener: (page: Page) => void): this;
/**
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also
* emitted if the page throws an error or a warning.
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`.
*
* The arguments passed into `console.log` are available on the {@link ConsoleMessage} event handler argument.
*
@ -1588,8 +1586,7 @@ export interface Page {
prependListener(event: 'close', listener: (page: Page) => void): this;
/**
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also
* emitted if the page throws an error or a warning.
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`.
*
* The arguments passed into `console.log` are available on the {@link ConsoleMessage} event handler argument.
*
@ -4340,8 +4337,7 @@ export interface Page {
waitForEvent(event: 'close', optionsOrPredicate?: { predicate?: (page: Page) => boolean | Promise<boolean>, timeout?: number } | ((page: Page) => boolean | Promise<boolean>)): Promise<Page>;
/**
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also
* emitted if the page throws an error or a warning.
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`.
*
* The arguments passed into `console.log` are available on the {@link ConsoleMessage} event handler argument.
*
@ -7663,8 +7659,7 @@ export interface BrowserContext {
on(event: 'close', listener: (browserContext: BrowserContext) => void): this;
/**
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also
* emitted if the page throws an error or a warning.
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`.
*
* The arguments passed into `console.log` and the page are available on the {@link ConsoleMessage} event handler
* argument.
@ -7855,8 +7850,7 @@ export interface BrowserContext {
addListener(event: 'close', listener: (browserContext: BrowserContext) => void): this;
/**
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also
* emitted if the page throws an error or a warning.
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`.
*
* The arguments passed into `console.log` and the page are available on the {@link ConsoleMessage} event handler
* argument.
@ -8102,8 +8096,7 @@ export interface BrowserContext {
prependListener(event: 'close', listener: (browserContext: BrowserContext) => void): this;
/**
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also
* emitted if the page throws an error or a warning.
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`.
*
* The arguments passed into `console.log` and the page are available on the {@link ConsoleMessage} event handler
* argument.
@ -8720,8 +8713,7 @@ export interface BrowserContext {
waitForEvent(event: 'close', optionsOrPredicate?: { predicate?: (browserContext: BrowserContext) => boolean | Promise<boolean>, timeout?: number } | ((browserContext: BrowserContext) => boolean | Promise<boolean>)): Promise<BrowserContext>;
/**
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. Also
* emitted if the page throws an error or a warning.
* Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`.
*
* The arguments passed into `console.log` and the page are available on the {@link ConsoleMessage} event handler
* argument.
@ -13931,6 +13923,27 @@ export interface ElectronApplication {
*/
on(event: 'close', listener: () => void): this;
/**
* Emitted when JavaScript within the Electron main process calls one of console API methods, e.g. `console.log` or
* `console.dir`.
*
* The arguments passed into `console.log` are available on the {@link ConsoleMessage} event handler argument.
*
* **Usage**
*
* ```js
* electronApp.on('console', async msg => {
* const values = [];
* for (const arg of msg.args())
* values.push(await arg.jsonValue());
* console.log(...values);
* });
* await electronApp.evaluate(() => console.log('hello', 5, { foo: 'bar' }));
* ```
*
*/
on(event: 'console', listener: (consoleMessage: ConsoleMessage) => void): this;
/**
* This event is issued for every window that is created **and loaded** in Electron. It contains a {@link Page} that
* can be used for Playwright automation.
@ -13942,6 +13955,11 @@ export interface ElectronApplication {
*/
once(event: 'close', listener: () => void): this;
/**
* Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event.
*/
once(event: 'console', listener: (consoleMessage: ConsoleMessage) => void): this;
/**
* Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event.
*/
@ -13952,6 +13970,27 @@ export interface ElectronApplication {
*/
addListener(event: 'close', listener: () => void): this;
/**
* Emitted when JavaScript within the Electron main process calls one of console API methods, e.g. `console.log` or
* `console.dir`.
*
* The arguments passed into `console.log` are available on the {@link ConsoleMessage} event handler argument.
*
* **Usage**
*
* ```js
* electronApp.on('console', async msg => {
* const values = [];
* for (const arg of msg.args())
* values.push(await arg.jsonValue());
* console.log(...values);
* });
* await electronApp.evaluate(() => console.log('hello', 5, { foo: 'bar' }));
* ```
*
*/
addListener(event: 'console', listener: (consoleMessage: ConsoleMessage) => void): this;
/**
* This event is issued for every window that is created **and loaded** in Electron. It contains a {@link Page} that
* can be used for Playwright automation.
@ -13963,6 +14002,11 @@ export interface ElectronApplication {
*/
removeListener(event: 'close', listener: () => void): this;
/**
* Removes an event listener added by `on` or `addListener`.
*/
removeListener(event: 'console', listener: (consoleMessage: ConsoleMessage) => void): this;
/**
* Removes an event listener added by `on` or `addListener`.
*/
@ -13973,6 +14017,11 @@ export interface ElectronApplication {
*/
off(event: 'close', listener: () => void): this;
/**
* Removes an event listener added by `on` or `addListener`.
*/
off(event: 'console', listener: (consoleMessage: ConsoleMessage) => void): this;
/**
* Removes an event listener added by `on` or `addListener`.
*/
@ -13983,6 +14032,27 @@ export interface ElectronApplication {
*/
prependListener(event: 'close', listener: () => void): this;
/**
* Emitted when JavaScript within the Electron main process calls one of console API methods, e.g. `console.log` or
* `console.dir`.
*
* The arguments passed into `console.log` are available on the {@link ConsoleMessage} event handler argument.
*
* **Usage**
*
* ```js
* electronApp.on('console', async msg => {
* const values = [];
* for (const arg of msg.args())
* values.push(await arg.jsonValue());
* console.log(...values);
* });
* await electronApp.evaluate(() => console.log('hello', 5, { foo: 'bar' }));
* ```
*
*/
prependListener(event: 'console', listener: (consoleMessage: ConsoleMessage) => void): this;
/**
* This event is issued for every window that is created **and loaded** in Electron. It contains a {@link Page} that
* can be used for Playwright automation.
@ -14039,6 +14109,27 @@ export interface ElectronApplication {
*/
waitForEvent(event: 'close', optionsOrPredicate?: { predicate?: () => boolean | Promise<boolean>, timeout?: number } | (() => boolean | Promise<boolean>)): Promise<void>;
/**
* Emitted when JavaScript within the Electron main process calls one of console API methods, e.g. `console.log` or
* `console.dir`.
*
* The arguments passed into `console.log` are available on the {@link ConsoleMessage} event handler argument.
*
* **Usage**
*
* ```js
* electronApp.on('console', async msg => {
* const values = [];
* for (const arg of msg.args())
* values.push(await arg.jsonValue());
* console.log(...values);
* });
* await electronApp.evaluate(() => console.log('hello', 5, { foo: 'bar' }));
* ```
*
*/
waitForEvent(event: 'console', optionsOrPredicate?: { predicate?: (consoleMessage: ConsoleMessage) => boolean | Promise<boolean>, timeout?: number } | ((consoleMessage: ConsoleMessage) => boolean | Promise<boolean>)): Promise<ConsoleMessage>;
/**
* This event is issued for every window that is created **and loaded** in Electron. It contains a {@link Page} that
* can be used for Playwright automation.

View File

@ -1453,7 +1453,6 @@ export type BrowserContextBindingCallEvent = {
binding: BindingCallChannel,
};
export type BrowserContextConsoleEvent = {
page: PageChannel,
type: string,
text: string,
args: JSHandleChannel[],
@ -1462,6 +1461,7 @@ export type BrowserContextConsoleEvent = {
lineNumber: number,
columnNumber: number,
},
page: PageChannel,
};
export type BrowserContextCloseEvent = {};
export type BrowserContextDialogEvent = {
@ -4082,15 +4082,27 @@ export type ElectronApplicationInitializer = {
};
export interface ElectronApplicationEventTarget {
on(event: 'close', callback: (params: ElectronApplicationCloseEvent) => void): this;
on(event: 'console', callback: (params: ElectronApplicationConsoleEvent) => void): this;
}
export interface ElectronApplicationChannel extends ElectronApplicationEventTarget, EventTargetChannel {
_type_ElectronApplication: boolean;
browserWindow(params: ElectronApplicationBrowserWindowParams, metadata?: CallMetadata): Promise<ElectronApplicationBrowserWindowResult>;
evaluateExpression(params: ElectronApplicationEvaluateExpressionParams, metadata?: CallMetadata): Promise<ElectronApplicationEvaluateExpressionResult>;
evaluateExpressionHandle(params: ElectronApplicationEvaluateExpressionHandleParams, metadata?: CallMetadata): Promise<ElectronApplicationEvaluateExpressionHandleResult>;
updateSubscription(params: ElectronApplicationUpdateSubscriptionParams, metadata?: CallMetadata): Promise<ElectronApplicationUpdateSubscriptionResult>;
close(params?: ElectronApplicationCloseParams, metadata?: CallMetadata): Promise<ElectronApplicationCloseResult>;
}
export type ElectronApplicationCloseEvent = {};
export type ElectronApplicationConsoleEvent = {
type: string,
text: string,
args: JSHandleChannel[],
location: {
url: string,
lineNumber: number,
columnNumber: number,
},
};
export type ElectronApplicationBrowserWindowParams = {
page: PageChannel,
};
@ -4122,12 +4134,21 @@ export type ElectronApplicationEvaluateExpressionHandleOptions = {
export type ElectronApplicationEvaluateExpressionHandleResult = {
handle: JSHandleChannel,
};
export type ElectronApplicationUpdateSubscriptionParams = {
event: 'console',
enabled: boolean,
};
export type ElectronApplicationUpdateSubscriptionOptions = {
};
export type ElectronApplicationUpdateSubscriptionResult = void;
export type ElectronApplicationCloseParams = {};
export type ElectronApplicationCloseOptions = {};
export type ElectronApplicationCloseResult = void;
export interface ElectronApplicationEvents {
'close': ElectronApplicationCloseEvent;
'console': ElectronApplicationConsoleEvent;
}
// ----------- Android -----------

View File

@ -970,6 +970,21 @@ Browser:
close:
ConsoleMessage:
type: mixin
properties:
type: string
text: string
args:
type: array
items: JSHandle
location:
type: object
properties:
url: string
lineNumber: number
columnNumber: number
EventTarget:
type: interface
@ -1175,18 +1190,8 @@ BrowserContext:
console:
parameters:
$mixin: ConsoleMessage
page: Page
type: string
text: string
args:
type: array
items: JSHandle
location:
type: object
properties:
url: string
lineNumber: number
columnNumber: number
close:
@ -3208,11 +3213,21 @@ ElectronApplication:
returns:
handle: JSHandle
updateSubscription:
parameters:
event:
type: enum
literals:
- console
enabled: boolean
close:
events:
close:
console:
parameters:
$mixin: ConsoleMessage
Android:
type: interface

View File

@ -18,6 +18,7 @@ import type { BrowserWindow } from 'electron';
import path from 'path';
import fs from 'fs';
import { electronTest as test, expect } from './electronTest';
import type { ConsoleMessage } from 'playwright';
test('should fire close event', async ({ launchElectronApp }) => {
const electronApp = await launchElectronApp('electron-app.js');
@ -31,6 +32,48 @@ test('should fire close event', async ({ launchElectronApp }) => {
expect(events.join('|')).toBe('context|application');
});
test('should fire console events', async ({ launchElectronApp }) => {
const electronApp = await launchElectronApp('electron-app.js');
const messages = [];
electronApp.on('console', message => messages.push({ type: message.type(), text: message.text() }));
await electronApp.evaluate(() => {
console.log('its type log');
console.debug('its type debug');
console.info('its type info');
console.error('its type error');
console.warn('its type warn');
});
await electronApp.close();
expect(messages).toEqual([
{ type: 'log', text: 'its type log' },
{ type: 'debug', text: 'its type debug' },
{ type: 'info', text: 'its type info' },
{ type: 'error', text: 'its type error' },
{ type: 'warning', text: 'its type warn' },
]);
});
test('should fire console events with handles and complex objects', async ({ launchElectronApp }) => {
const electronApp = await launchElectronApp('electron-app.js');
const messages: ConsoleMessage[] = [];
electronApp.on('console', message => messages.push(message));
await electronApp.evaluate(() => {
globalThis.complexObject = [{ a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }, { a: 7, b: 8, c: 9 }];
console.log(globalThis.complexObject[0], globalThis.complexObject[1], globalThis.complexObject[2]);
});
expect(messages.length).toBe(1);
const message = messages[0];
expect(message.text()).toBe('{a: 1, b: 2, c: 3} {a: 4, b: 5, c: 6} {a: 7, b: 8, c: 9}');
expect(message.args().length).toBe(3);
expect(await message.args()[0].jsonValue()).toEqual({ a: 1, b: 2, c: 3 });
expect(await message.args()[0].evaluate(part => part === globalThis.complexObject[0])).toBeTruthy();
expect(await message.args()[1].jsonValue()).toEqual({ a: 4, b: 5, c: 6 });
expect(await message.args()[1].evaluate(part => part === globalThis.complexObject[1])).toBeTruthy();
expect(await message.args()[2].jsonValue()).toEqual({ a: 7, b: 8, c: 9 });
expect(await message.args()[2].evaluate(part => part === globalThis.complexObject[2])).toBeTruthy();
await electronApp.close();
});
test('should dispatch ready event', async ({ launchElectronApp }) => {
const electronApp = await launchElectronApp('electron-app-ready-event.js');
const events = await electronApp.evaluate(() => globalThis.__playwrightLog);