diff --git a/lib/Page.js b/lib/Page.js index dc4c2f44e0859..a8001c1b00580 100644 --- a/lib/Page.js +++ b/lib/Page.js @@ -508,6 +508,17 @@ class Page extends EventEmitter { * @param {!Protocol.Runtime.consoleAPICalledPayload} event */ async _onConsoleAPI(event) { + if (event.executionContextId === 0) { + // DevTools protocol stores 1000 last console messages. These messages are + // reported even for removed execution contexts - in this case, they are marked with + // executionContextId = 0 and 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 Puppeteer clients can subscribe to the 'console' page event. + // + // @see https://github.com/GoogleChrome/puppeteer/issues/3865 + return; + } const context = this._frameManager.executionContextById(event.executionContextId); const values = event.args.map(arg => createJSHandle(context, arg)); this._addConsoleMessage(event.type, values, event.stackTrace); diff --git a/test/page.spec.js b/test/page.spec.js index 335d64a4d22ee..4374a52a478fb 100644 --- a/test/page.spec.js +++ b/test/page.spec.js @@ -349,6 +349,24 @@ module.exports.addTests = function({testRunner, expect, headless}) { columnNumber: 14, }); }); + // @see https://github.com/GoogleChrome/puppeteer/issues/3865 + fit('should not throw when there are console messages in detached iframes', async({browser, page, server}) => { + await page.goto(server.EMPTY_PAGE); + await page.evaluate(async () => { + // 1. Create a popup that Puppeteer is not connected to. + var win = window.open(window.location.href, "Title", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=780,height=200,top=0,left=0"); + await new Promise(x => win.onload = x); + // 2. In this popup, create an iframe that console.logs a message. + win.document.body.innerHTML = ``; + const frame = win.document.querySelector('iframe'); + await new Promise(x => frame.onload = x); + // 3. After that, remove the iframe. + frame.remove(); + }); + const popupTarget = page.browserContext().targets().find(target => target !== page.target()); + // 4. Connect to the popup and make sure it doesn't throw. + const popup = await popupTarget.page(); + }); }); describe('Page.Events.DOMContentLoaded', function() {