Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/src/api/class-consolemessage.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ The page that produced this console message, if any.

The text of the console message.

## method: ConsoleMessage.timestamp
* since: v1.59
- returns: <[float]>

The timestamp of the console message in milliseconds since the Unix epoch.

## method: ConsoleMessage.type
* since: v1.8
* langs: js, python
Expand Down
5 changes: 5 additions & 0 deletions packages/playwright-client/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19267,6 +19267,11 @@ export interface ConsoleMessage {
*/
text(): string;

/**
* The timestamp of the console message in milliseconds since the Unix epoch.
*/
timestamp(): number;

type(): "log"|"debug"|"info"|"error"|"warning"|"dir"|"dirxml"|"table"|"trace"|"clear"|"startGroup"|"startGroupCollapsed"|"endGroup"|"assert"|"profile"|"profileEnd"|"count"|"time"|"timeEnd";

/**
Expand Down
4 changes: 4 additions & 0 deletions packages/playwright-core/src/client/consoleMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export class ConsoleMessage implements api.ConsoleMessage {
return this._event.location;
}

timestamp(): number {
return this._event.timestamp;
}

private _inspect() {
return this.text();
}
Expand Down
3 changes: 3 additions & 0 deletions packages/playwright-core/src/protocol/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,7 @@ scheme.BrowserContextConsoleEvent = tObject({
lineNumber: tInt,
columnNumber: tInt,
}),
timestamp: tFloat,
page: tOptional(tChannel(['Page'])),
worker: tOptional(tChannel(['Worker'])),
});
Expand Down Expand Up @@ -1227,6 +1228,7 @@ scheme.PageConsoleMessagesResult = tObject({
lineNumber: tInt,
columnNumber: tInt,
}),
timestamp: tFloat,
})),
});
scheme.PageEmulateMediaParams = tObject({
Expand Down Expand Up @@ -2604,6 +2606,7 @@ scheme.ElectronApplicationConsoleEvent = tObject({
lineNumber: tInt,
columnNumber: tInt,
}),
timestamp: tFloat,
});
scheme.ElectronApplicationBrowserWindowParams = tObject({
page: tChannel(['Page']),
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/src/server/bidi/bidiPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ export class BidiPage implements PageDelegate {

const callFrame = params.stackTrace?.callFrames[0];
const location = callFrame ?? { url: '', lineNumber: 1, columnNumber: 1 };
this._page.addConsoleMessage(null, entry.method, entry.args.map(arg => createHandle(context, arg)), location);
this._page.addConsoleMessage(null, entry.method, entry.args.map(arg => createHandle(context, arg)), location, undefined, params.timestamp);
}

private async _onFileDialogOpened(params: bidi.Input.FileDialogInfo) {
Expand Down
6 changes: 3 additions & 3 deletions packages/playwright-core/src/server/chromium/crPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ class FrameSession {
session.on('Target.detachedFromTarget', event => this._onDetachedFromTarget(event));
session.on('Runtime.consoleAPICalled', event => {
const args = event.args.map(o => createHandle(worker.existingExecutionContext!, o));
this._page.addConsoleMessage(worker, event.type, args, toConsoleMessageLocation(event.stackTrace));
this._page.addConsoleMessage(worker, event.type, args, toConsoleMessageLocation(event.stackTrace), undefined, event.timestamp);
});
session.on('Runtime.exceptionThrown', exception => this._page.addPageError(exceptionToError(exception.exceptionDetails)));
}
Expand Down Expand Up @@ -799,7 +799,7 @@ class FrameSession {
if (!context)
return;
const values = event.args.map(arg => createHandle(context, arg));
this._page.addConsoleMessage(null, event.type, values, toConsoleMessageLocation(event.stackTrace));
this._page.addConsoleMessage(null, event.type, values, toConsoleMessageLocation(event.stackTrace), undefined, event.timestamp);
}

async _onBindingCalled(event: Protocol.Runtime.bindingCalledPayload) {
Expand Down Expand Up @@ -846,7 +846,7 @@ class FrameSession {
lineNumber: lineNumber || 0,
columnNumber: 0,
};
this._page.addConsoleMessage(null, level, [], location, text);
this._page.addConsoleMessage(null, level, [], location, text, event.entry.timestamp);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class CRServiceWorker extends Worker {
if (!this.existingExecutionContext || process.env.PLAYWRIGHT_DISABLE_SERVICE_WORKER_CONSOLE)
return;
const args = event.args.map(o => createHandle(this.existingExecutionContext!, o));
const message = new ConsoleMessage(null, this, event.type, undefined, args, toConsoleMessageLocation(event.stackTrace));
const message = new ConsoleMessage(null, this, event.type, undefined, args, toConsoleMessageLocation(event.stackTrace), event.timestamp);
this.browserContext.emit(BrowserContext.Events.Console, message);
});

Expand Down
8 changes: 7 additions & 1 deletion packages/playwright-core/src/server/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@ export class ConsoleMessage {
private _location: ConsoleMessageLocation;
private _page: Page | null;
private _worker: Worker | null;
private _timestamp: number;

constructor(page: Page | null, worker: Worker | null, type: string, text: string | undefined, args: js.JSHandle[], location?: ConsoleMessageLocation) {
constructor(page: Page | null, worker: Worker | null, type: string, text: string | undefined, args: js.JSHandle[], location: ConsoleMessageLocation, timestamp: number) {
this._page = page;
this._worker = worker;
this._type = type;
this._text = text;
this._args = args;
this._location = location || { url: '', lineNumber: 0, columnNumber: 0 };
this._timestamp = timestamp;
}

page() {
Expand Down Expand Up @@ -60,4 +62,8 @@ export class ConsoleMessage {
location(): ConsoleMessageLocation {
return this._location;
}

timestamp(): number {
return this._timestamp;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
return JSHandleDispatcher.fromJSHandle(jsScope, a);
}),
location: message.location(),
timestamp: message.timestamp(),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ export class ElectronApplicationDispatcher extends Dispatcher<ElectronApplicatio
type: message.type(),
text: message.text(),
args: message.args().map(a => JSHandleDispatcher.fromJSHandle(this, a)),
location: message.location()
location: message.location(),
timestamp: message.timestamp(),
});
});
}
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/src/server/electron/electron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export class ElectronApplication extends SdkObject {
if (!this._nodeExecutionContext)
return;
const args = event.args.map(arg => createHandle(this._nodeExecutionContext!, arg));
const message = new ConsoleMessage(null, null, event.type, undefined, args, toConsoleMessageLocation(event.stackTrace));
const message = new ConsoleMessage(null, null, event.type, undefined, args, toConsoleMessageLocation(event.stackTrace), event.timestamp);
this.emit(ElectronApplication.Events.Console, message);
}

Expand Down
5 changes: 3 additions & 2 deletions packages/playwright-core/src/server/firefox/ffPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,9 @@ export class FFPage implements PageDelegate {
const context = this._contextIdToContext.get(executionContextId);
if (!context)
return;
const timestamp = Date.now();
// Juggler reports 'warn' for some internal messages generated by the browser.
this._page.addConsoleMessage(null, type === 'warn' ? 'warning' : type, args.map(arg => createHandle(context, arg)), location);
this._page.addConsoleMessage(null, type === 'warn' ? 'warning' : type, args.map(arg => createHandle(context, arg)), location, undefined, timestamp);
}

_onDialogOpened(params: Protocol.Page.dialogOpenedPayload) {
Expand Down Expand Up @@ -284,7 +285,7 @@ export class FFPage implements PageDelegate {
workerSession.on('Runtime.console', event => {
const { type, args, location } = event;
const context = worker.existingExecutionContext!;
this._page.addConsoleMessage(worker, type, args.map(arg => createHandle(context, arg)), location);
this._page.addConsoleMessage(worker, type, args.map(arg => createHandle(context, arg)), location, undefined, Date.now());
});
// Note: we receive worker exceptions directly from the page.
}
Expand Down
4 changes: 2 additions & 2 deletions packages/playwright-core/src/server/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,8 @@ export class Page extends SdkObject<PageEventMap> {
await PageBinding.dispatch(this, payload, context);
}

addConsoleMessage(worker: Worker | null, type: string, args: js.JSHandle[], location: types.ConsoleMessageLocation, text?: string) {
const message = new ConsoleMessage(this, worker, type, text, args, location);
addConsoleMessage(worker: Worker | null, type: string, args: js.JSHandle[], location: types.ConsoleMessageLocation, text: string | undefined, timestamp: number) {
const message = new ConsoleMessage(this, worker, type, text, args, location, timestamp);
const intercepted = this.frameManager.interceptConsoleMessage(message);
if (intercepted) {
args.forEach(arg => arg.dispose());
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/src/server/webkit/wkPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ export class WKPage implements PageDelegate {
location
} = this._lastConsoleMessage;
for (let i = count; i < event.count; ++i)
this._page.addConsoleMessage(null, derivedType, handles, location, handles.length ? undefined : text);
this._page.addConsoleMessage(null, derivedType, handles, location, handles.length ? undefined : text, event.timestamp ?? Date.now());
this._lastConsoleMessage.count = event.count;
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/src/server/webkit/wkWorkers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,6 @@ export class WKWorkers {
lineNumber: (lineNumber || 1) - 1,
columnNumber: (columnNumber || 1) - 1
};
this._page.addConsoleMessage(worker, derivedType, handles, location, handles.length ? undefined : text);
this._page.addConsoleMessage(worker, derivedType, handles, location, handles.length ? undefined : text, event.message.timestamp ?? Date.now());
}
}
5 changes: 5 additions & 0 deletions packages/playwright-core/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19267,6 +19267,11 @@ export interface ConsoleMessage {
*/
text(): string;

/**
* The timestamp of the console message in milliseconds since the Unix epoch.
*/
timestamp(): number;

type(): "log"|"debug"|"info"|"error"|"warning"|"dir"|"dirxml"|"table"|"trace"|"clear"|"startGroup"|"startGroupCollapsed"|"endGroup"|"assert"|"profile"|"profileEnd"|"count"|"time"|"timeEnd";

/**
Expand Down
3 changes: 3 additions & 0 deletions packages/protocol/src/channels.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1637,6 +1637,7 @@ export type BrowserContextConsoleEvent = {
lineNumber: number,
columnNumber: number,
},
timestamp: number,
page?: PageChannel,
worker?: WorkerChannel,
};
Expand Down Expand Up @@ -2173,6 +2174,7 @@ export type PageConsoleMessagesResult = {
lineNumber: number,
columnNumber: number,
},
timestamp: number,
}[],
};
export type PageEmulateMediaParams = {
Expand Down Expand Up @@ -4567,6 +4569,7 @@ export type ElectronApplicationConsoleEvent = {
lineNumber: number,
columnNumber: number,
},
timestamp: number,
};
export type ElectronApplicationBrowserWindowParams = {
page: PageChannel,
Expand Down
1 change: 1 addition & 0 deletions packages/protocol/src/protocol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,7 @@ ConsoleMessage:
url: string
lineNumber: int
columnNumber: int
timestamp: float


EventTarget:
Expand Down
36 changes: 36 additions & 0 deletions tests/page/page-event-console.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,42 @@ it('do not update console count on unhandled rejections', async ({ page }) => {
await expect.poll(() => messages).toEqual(['begin', 'end']);
});

it('should have timestamp', async ({ page }) => {
const before = Date.now();
const [message] = await Promise.all([
page.waitForEvent('console'),
page.evaluate(() => console.log('timestamp test')),
]);
const after = Date.now();
expect(message.timestamp()).toBeGreaterThanOrEqual(before);
expect(message.timestamp()).toBeLessThanOrEqual(after);
});

it('should have increasing timestamps', async ({ page }) => {
const messages = [];
page.on('console', msg => messages.push(msg));
await page.evaluate(() => {
console.log('first');
console.log('second');
console.log('third');
});
expect(messages.length).toBe(3);
for (let i = 1; i < messages.length; i++)
expect(messages[i].timestamp()).toBeGreaterThanOrEqual(messages[i - 1].timestamp());
});

it('should have timestamp in consoleMessages', async ({ page }) => {
const before = Date.now();
await page.evaluate(() => console.log('stored message'));
const after = Date.now();
const messages = await page.consoleMessages();
expect(messages.length).toBeGreaterThanOrEqual(1);
const last = messages[messages.length - 1];
expect(last.text()).toBe('stored message');
expect(last.timestamp()).toBeGreaterThanOrEqual(before);
expect(last.timestamp()).toBeLessThanOrEqual(after);
});

it('consoleMessages should work', async ({ page }) => {
await page.evaluate(() => {
for (let i = 0; i < 301; i++)
Expand Down
12 changes: 12 additions & 0 deletions tests/page/workers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ it('should report console logs', async function({ page }) {
expect(page.url()).not.toContain('blob');
});

it('should have timestamp on worker console messages', async function({ page }) {
const before = Date.now();
const [message] = await Promise.all([
page.waitForEvent('console'),
page.evaluate(() => new Worker(URL.createObjectURL(new Blob(['console.log("ts")'], { type: 'application/javascript' })))),
]);
const after = Date.now();
expect(message.text()).toBe('ts');
expect(message.timestamp()).toBeGreaterThanOrEqual(before);
expect(message.timestamp()).toBeLessThanOrEqual(after);
});

it('should not report console logs from workers twice', async function({ page }) {
const messages = [];
page.on('console', msg => messages.push(msg.text()));
Expand Down
Loading