diff --git a/lib/DOMWorld.js b/lib/DOMWorld.js index e00d6662..1668fad0 100644 --- a/lib/DOMWorld.js +++ b/lib/DOMWorld.js @@ -70,6 +70,13 @@ class DOMWorld { } } + /** + * @return {boolean} + */ + _hasContext() { + return !this._contextResolveCallback; + } + _detach() { this._detached = true; for (const waitTask of this._waitTasks) diff --git a/lib/FrameManager.js b/lib/FrameManager.js index 5f42e4f4..818bf37b 100644 --- a/lib/FrameManager.js +++ b/lib/FrameManager.js @@ -306,10 +306,14 @@ class FrameManager extends EventEmitter { const frame = this._frames.get(frameId) || null; let world = null; if (frame) { - if (contextPayload.auxData && !!contextPayload.auxData['isDefault']) + if (contextPayload.auxData && !!contextPayload.auxData['isDefault']) { world = frame._mainWorld; - else if (contextPayload.name === UTILITY_WORLD_NAME) + } else if (contextPayload.name === UTILITY_WORLD_NAME && !frame._secondaryWorld._hasContext()) { + // In case of multiple sessions to the same target, there's a race between + // connections so we might end up creating multiple isolated worlds. + // We can use either. world = frame._secondaryWorld; + } } if (contextPayload.auxData && contextPayload.auxData['type'] === 'isolated') this._isolatedWorlds.add(contextPayload.name); diff --git a/test/launcher.spec.js b/test/launcher.spec.js index 8533f204..b573dc7b 100644 --- a/test/launcher.spec.js +++ b/test/launcher.spec.js @@ -316,6 +316,19 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p expect(await restoredPage.evaluate(() => 7 * 8)).toBe(56); await browser.close(); }); + // @see https://github.com/GoogleChrome/puppeteer/issues/4197#issuecomment-481793410 + it('should be able to connect to the same page simultaneously', async({server}) => { + const browserOne = await puppeteer.launch(); + const browserTwo = await puppeteer.connect({ browserWSEndpoint: browserOne.wsEndpoint() }); + const [page1, page2] = await Promise.all([ + new Promise(x => browserOne.once('targetcreated', target => x(target.page()))), + browserTwo.newPage(), + ]); + expect(await page1.evaluate(() => 7 * 8)).toBe(56); + expect(await page2.evaluate(() => 7 * 6)).toBe(42); + await browserOne.close(); + }); + }); describe('Puppeteer.executablePath', function() { it('should work', async({server}) => {