From ebe17371b0dc84760a5685e510f14182b73a1c77 Mon Sep 17 00:00:00 2001 From: Yaniv Efraim Date: Thu, 29 Mar 2018 20:42:23 +0300 Subject: [PATCH] chore: break page.spec.js to smaller files (#2257) Break some large chunks into smaller files. This change will remove ~600 lines from `page.spec.js` --- test/CDPSession.spec.js | 73 +++++ test/cookies.spec.js | 233 +++++++++++++++ test/coverage.spec.js | 179 ++++++++++++ test/frame.spec.js | 85 +++++- test/page.spec.js | 618 +--------------------------------------- test/target.spec.js | 134 +++++++++ 6 files changed, 708 insertions(+), 614 deletions(-) create mode 100644 test/CDPSession.spec.js create mode 100644 test/cookies.spec.js create mode 100644 test/coverage.spec.js create mode 100644 test/target.spec.js diff --git a/test/CDPSession.spec.js b/test/CDPSession.spec.js new file mode 100644 index 0000000000000..d5a78f065110f --- /dev/null +++ b/test/CDPSession.spec.js @@ -0,0 +1,73 @@ +/** + * Copyright 2018 Google Inc. All rights reserved. + * + * 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 {waitForEvents} = require('./utils'); + +module.exports.addTests = function({testRunner, expect}) { + const {describe, xdescribe, fdescribe} = testRunner; + const {it, fit, xit} = testRunner; + const {beforeAll, beforeEach, afterAll, afterEach} = testRunner; + + describe('Target.createCDPSession', function() { + it('should work', async function({page, server}) { + const client = await page.target().createCDPSession(); + + await Promise.all([ + client.send('Runtime.enable'), + client.send('Runtime.evaluate', { expression: 'window.foo = "bar"' }) + ]); + const foo = await page.evaluate(() => window.foo); + expect(foo).toBe('bar'); + }); + it('should send events', async function({page, server}) { + const client = await page.target().createCDPSession(); + await client.send('Network.enable'); + const events = []; + client.on('Network.requestWillBeSent', event => events.push(event)); + await page.goto(server.EMPTY_PAGE); + expect(events.length).toBe(1); + }); + it('should enable and disable domains independently', async function({page, server}) { + const client = await page.target().createCDPSession(); + await client.send('Runtime.enable'); + await client.send('Debugger.enable'); + // JS coverage enables and then disables Debugger domain. + await page.coverage.startJSCoverage(); + await page.coverage.stopJSCoverage(); + // generate a script in page and wait for the event. + const [event] = await Promise.all([ + waitForEvents(client, 'Debugger.scriptParsed'), + page.evaluate('//# sourceURL=foo.js') + ]); + // expect events to be dispatched. + expect(event.url).toBe('foo.js'); + }); + it('should be able to detach session', async function({page, server}) { + const client = await page.target().createCDPSession(); + await client.send('Runtime.enable'); + const evalResponse = await client.send('Runtime.evaluate', {expression: '1 + 2', returnByValue: true}); + expect(evalResponse.result.value).toBe(3); + await client.detach(); + let error = null; + try { + await client.send('Runtime.evaluate', {expression: '3 + 1', returnByValue: true}); + } catch (e) { + error = e; + } + expect(error.message).toContain('Session closed.'); + }); + }); +}; \ No newline at end of file diff --git a/test/cookies.spec.js b/test/cookies.spec.js new file mode 100644 index 0000000000000..d57ccc17e961e --- /dev/null +++ b/test/cookies.spec.js @@ -0,0 +1,233 @@ +/** + * Copyright 2018 Google Inc. All rights reserved. + * + * 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. + */ + +module.exports.addTests = function({testRunner, expect}) { + const {describe, xdescribe, fdescribe} = testRunner; + const {it, fit, xit} = testRunner; + const {beforeAll, beforeEach, afterAll, afterEach} = testRunner; + + describe('Cookies', function() { + afterEach(async({page, server}) => { + const cookies = await page.cookies(server.PREFIX + '/grid.html', server.CROSS_PROCESS_PREFIX); + for (const cookie of cookies) + await page.deleteCookie(cookie); + }); + it('should set and get cookies', async({page, server}) => { + await page.goto(server.PREFIX + '/grid.html'); + expect(await page.cookies()).toEqual([]); + await page.evaluate(() => { + document.cookie = 'username=John Doe'; + }); + expect(await page.cookies()).toEqual([{ + name: 'username', + value: 'John Doe', + domain: 'localhost', + path: '/', + expires: -1, + size: 16, + httpOnly: false, + secure: false, + session: true } + ]); + await page.setCookie({ + name: 'password', + value: '123456' + }); + expect(await page.evaluate('document.cookie')).toBe('username=John Doe; password=123456'); + const cookies = await page.cookies(); + expect(cookies.sort((a, b) => a.name.localeCompare(b.name))).toEqual([{ + name: 'password', + value: '123456', + domain: 'localhost', + path: '/', + expires: -1, + size: 14, + httpOnly: false, + secure: false, + session: true + }, { + name: 'username', + value: 'John Doe', + domain: 'localhost', + path: '/', + expires: -1, + size: 16, + httpOnly: false, + secure: false, + session: true + }]); + }); + + it('should set a cookie with a path', async({page, server}) => { + await page.goto(server.PREFIX + '/grid.html'); + await page.setCookie({ + name: 'gridcookie', + value: 'GRID', + path: '/grid.html' + }); + expect(await page.cookies()).toEqual([{ + name: 'gridcookie', + value: 'GRID', + domain: 'localhost', + path: '/grid.html', + expires: -1, + size: 14, + httpOnly: false, + secure: false, + session: true + }]); + expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID'); + await page.goto(server.PREFIX + '/empty.html'); + expect(await page.cookies()).toEqual([]); + expect(await page.evaluate('document.cookie')).toBe(''); + await page.goto(server.PREFIX + '/grid.html'); + expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID'); + }); + + + it('should delete a cookie', async({page, server}) => { + await page.goto(server.PREFIX + '/grid.html'); + await page.setCookie({ + name: 'cookie1', + value: '1' + }, { + name: 'cookie2', + value: '2' + }, { + name: 'cookie3', + value: '3' + }); + expect(await page.evaluate('document.cookie')).toBe('cookie1=1; cookie2=2; cookie3=3'); + await page.deleteCookie({name: 'cookie2'}); + expect(await page.evaluate('document.cookie')).toBe('cookie1=1; cookie3=3'); + }); + + it('should not set a cookie on a blank page', async function({page}) { + let error = null; + await page.goto('about:blank'); + try { + await page.setCookie({name: 'example-cookie', value: 'best'}); + } catch (e) { + error = e; + } + expect(error).toBeTruthy(); + expect(error.message).toEqual('Protocol error (Network.deleteCookies): At least one of the url and domain needs to be specified undefined'); + }); + + it('should not set a cookie with blank page URL', async function({page, server}) { + let error = null; + await page.goto(server.PREFIX + '/grid.html'); + try { + await page.setCookie( + {name: 'example-cookie', value: 'best'}, + {url: 'about:blank', name: 'example-cookie-blank', value: 'best'} + ); + } catch (e) { + error = e; + } + expect(error).toBeTruthy(); + expect(error.message).toEqual( + `Blank page can not have cookie "example-cookie-blank"` + ); + }); + + it('should not set a cookie on a data URL page', async function({page}) { + let error = null; + await page.goto('data:,Hello%2C%20World!'); + try { + await page.setCookie({name: 'example-cookie', value: 'best'}); + } catch (e) { + error = e; + } + expect(error).toBeTruthy(); + expect(error.message).toEqual( + 'Protocol error (Network.deleteCookies): At least one of the url and domain needs to be specified undefined' + ); + }); + + it('should not set a cookie with blank page URL', async function({page, server}) { + let error = null; + await page.goto(server.PREFIX + '/grid.html'); + try { + await page.setCookie({name: 'example-cookie', value: 'best'}, {url: 'about:blank', name: 'example-cookie-blank', value: 'best'}); + } catch (e) { + error = e; + } + expect(error).toBeTruthy(); + expect(error.message).toEqual(`Blank page can not have cookie "example-cookie-blank"`); + }); + + it('should set a cookie on a different domain', async({page, server}) => { + await page.goto(server.PREFIX + '/grid.html'); + await page.setCookie({name: 'example-cookie', value: 'best', url: 'https://www.example.com'}); + expect(await page.evaluate('document.cookie')).toBe(''); + expect(await page.cookies()).toEqual([]); + expect(await page.cookies('https://www.example.com')).toEqual([{ + name: 'example-cookie', + value: 'best', + domain: 'www.example.com', + path: '/', + expires: -1, + size: 18, + httpOnly: false, + secure: true, + session: true + }]); + }); + + it('should set cookies from a frame', async({page, server}) => { + await page.goto(server.PREFIX + '/grid.html'); + await page.setCookie({name: 'localhost-cookie', value: 'best'}); + await page.evaluate(src => { + let fulfill; + const promise = new Promise(x => fulfill = x); + const iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + iframe.onload = fulfill; + iframe.src = src; + return promise; + }, server.CROSS_PROCESS_PREFIX); + await page.setCookie({name: '127-cookie', value: 'worst', url: server.CROSS_PROCESS_PREFIX}); + expect(await page.evaluate('document.cookie')).toBe('localhost-cookie=best'); + expect(await page.frames()[1].evaluate('document.cookie')).toBe('127-cookie=worst'); + + expect(await page.cookies()).toEqual([{ + name: 'localhost-cookie', + value: 'best', + domain: 'localhost', + path: '/', + expires: -1, + size: 20, + httpOnly: false, + secure: false, + session: true + }]); + + expect(await page.cookies(server.CROSS_PROCESS_PREFIX)).toEqual([{ + name: '127-cookie', + value: 'worst', + domain: '127.0.0.1', + path: '/', + expires: -1, + size: 15, + httpOnly: false, + secure: false, + session: true + }]); + + }); + }); +}; \ No newline at end of file diff --git a/test/coverage.spec.js b/test/coverage.spec.js new file mode 100644 index 0000000000000..8fcd9f3a7bd7f --- /dev/null +++ b/test/coverage.spec.js @@ -0,0 +1,179 @@ +/** + * Copyright 2018 Google Inc. All rights reserved. + * + * 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. + */ + +module.exports.addTests = function({testRunner, expect}) { + const {describe, xdescribe, fdescribe} = testRunner; + const {it, fit, xit} = testRunner; + const {beforeAll, beforeEach, afterAll, afterEach} = testRunner; + + describe('JSCoverage', function() { + it('should work', async function({page, server}) { + await page.coverage.startJSCoverage(); + await page.goto(server.PREFIX + '/jscoverage/simple.html'); + const coverage = await page.coverage.stopJSCoverage(); + expect(coverage.length).toBe(1); + expect(coverage[0].url).toContain('/jscoverage/simple.html'); + expect(coverage[0].ranges).toEqual([ + { start: 0, end: 17 }, + { start: 35, end: 61 }, + ]); + }); + it('should report sourceURLs', async function({page, server}) { + await page.coverage.startJSCoverage(); + await page.goto(server.PREFIX + '/jscoverage/sourceurl.html'); + const coverage = await page.coverage.stopJSCoverage(); + expect(coverage.length).toBe(1); + expect(coverage[0].url).toBe('nicename.js'); + }); + it('should ignore anonymous scripts', async function({page, server}) { + await page.coverage.startJSCoverage(); + await page.goto(server.EMPTY_PAGE); + await page.evaluate(() => console.log(1)); + const coverage = await page.coverage.stopJSCoverage(); + expect(coverage.length).toBe(0); + }); + it('should report multiple scripts', async function({page, server}) { + await page.coverage.startJSCoverage(); + await page.goto(server.PREFIX + '/jscoverage/multiple.html'); + const coverage = await page.coverage.stopJSCoverage(); + expect(coverage.length).toBe(2); + coverage.sort((a, b) => a.url.localeCompare(b.url)); + expect(coverage[0].url).toContain('/jscoverage/script1.js'); + expect(coverage[1].url).toContain('/jscoverage/script2.js'); + }); + it('should report right ranges', async function({page, server}) { + await page.coverage.startJSCoverage(); + await page.goto(server.PREFIX + '/jscoverage/ranges.html'); + const coverage = await page.coverage.stopJSCoverage(); + expect(coverage.length).toBe(1); + const entry = coverage[0]; + expect(entry.ranges.length).toBe(1); + const range = entry.ranges[0]; + expect(entry.text.substring(range.start, range.end)).toBe(`console.log('used!');`); + }); + it('should report scripts that have no coverage', async function({page, server}) { + await page.coverage.startJSCoverage(); + await page.goto(server.PREFIX + '/jscoverage/unused.html'); + const coverage = await page.coverage.stopJSCoverage(); + expect(coverage.length).toBe(1); + const entry = coverage[0]; + expect(entry.url).toContain('unused.html'); + expect(entry.ranges.length).toBe(0); + }); + it('should work with conditionals', async function({page, server}) { + await page.coverage.startJSCoverage(); + await page.goto(server.PREFIX + '/jscoverage/involved.html'); + const coverage = await page.coverage.stopJSCoverage(); + expect(JSON.stringify(coverage, null, 2).replace(/:\d{4}\//g, ':/')).toBeGolden('jscoverage-involved.txt'); + }); + describe('resetOnNavigation', function() { + it('should report scripts across navigations when disabled', async function({page, server}) { + await page.coverage.startJSCoverage({resetOnNavigation: false}); + await page.goto(server.PREFIX + '/jscoverage/multiple.html'); + await page.goto(server.EMPTY_PAGE); + const coverage = await page.coverage.stopJSCoverage(); + expect(coverage.length).toBe(2); + }); + it('should NOT report scripts across navigations when enabled', async function({page, server}) { + await page.coverage.startJSCoverage(); // Enabled by default. + await page.goto(server.PREFIX + '/jscoverage/multiple.html'); + await page.goto(server.EMPTY_PAGE); + const coverage = await page.coverage.stopJSCoverage(); + expect(coverage.length).toBe(0); + }); + }); + }); + + describe('CSSCoverage', function() { + it('should work', async function({page, server}) { + await page.coverage.startCSSCoverage(); + await page.goto(server.PREFIX + '/csscoverage/simple.html'); + const coverage = await page.coverage.stopCSSCoverage(); + expect(coverage.length).toBe(1); + expect(coverage[0].url).toContain('/csscoverage/simple.html'); + expect(coverage[0].ranges).toEqual([ + {start: 1, end: 22} + ]); + const range = coverage[0].ranges[0]; + expect(coverage[0].text.substring(range.start, range.end)).toBe('div { color: green; }'); + }); + it('should report sourceURLs', async function({page, server}) { + await page.coverage.startCSSCoverage(); + await page.goto(server.PREFIX + '/csscoverage/sourceurl.html'); + const coverage = await page.coverage.stopCSSCoverage(); + expect(coverage.length).toBe(1); + expect(coverage[0].url).toBe('nicename.css'); + }); + it('should report multiple stylesheets', async function({page, server}) { + await page.coverage.startCSSCoverage(); + await page.goto(server.PREFIX + '/csscoverage/multiple.html'); + const coverage = await page.coverage.stopCSSCoverage(); + expect(coverage.length).toBe(2); + coverage.sort((a, b) => a.url.localeCompare(b.url)); + expect(coverage[0].url).toContain('/csscoverage/stylesheet1.css'); + expect(coverage[1].url).toContain('/csscoverage/stylesheet2.css'); + }); + it('should report stylesheets that have no coverage', async function({page, server}) { + await page.coverage.startCSSCoverage(); + await page.goto(server.PREFIX + '/csscoverage/unused.html'); + const coverage = await page.coverage.stopCSSCoverage(); + expect(coverage.length).toBe(1); + expect(coverage[0].url).toBe('unused.css'); + expect(coverage[0].ranges.length).toBe(0); + }); + it('should work with media queries', async function({page, server}) { + await page.coverage.startCSSCoverage(); + await page.goto(server.PREFIX + '/csscoverage/media.html'); + const coverage = await page.coverage.stopCSSCoverage(); + expect(coverage.length).toBe(1); + expect(coverage[0].url).toContain('/csscoverage/media.html'); + expect(coverage[0].ranges).toEqual([ + {start: 17, end: 38} + ]); + }); + it('should work with complicated usecases', async function({page, server}) { + await page.coverage.startCSSCoverage(); + await page.goto(server.PREFIX + '/csscoverage/involved.html'); + const coverage = await page.coverage.stopCSSCoverage(); + expect(JSON.stringify(coverage, null, 2).replace(/:\d{4}\//g, ':/')).toBeGolden('csscoverage-involved.txt'); + }); + it('should ignore injected stylesheets', async function({page, server}) { + await page.coverage.startCSSCoverage(); + await page.addStyleTag({content: 'body { margin: 10px;}'}); + // trigger style recalc + const margin = await page.evaluate(() => window.getComputedStyle(document.body).margin); + expect(margin).toBe('10px'); + const coverage = await page.coverage.stopCSSCoverage(); + expect(coverage.length).toBe(0); + }); + describe('resetOnNavigation', function() { + it('should report stylesheets across navigations', async function({page, server}) { + await page.coverage.startCSSCoverage({resetOnNavigation: false}); + await page.goto(server.PREFIX + '/csscoverage/multiple.html'); + await page.goto(server.EMPTY_PAGE); + const coverage = await page.coverage.stopCSSCoverage(); + expect(coverage.length).toBe(2); + }); + it('should NOT report scripts across navigations', async function({page, server}) { + await page.coverage.startCSSCoverage(); // Enabled by default. + await page.goto(server.PREFIX + '/csscoverage/multiple.html'); + await page.goto(server.EMPTY_PAGE); + const coverage = await page.coverage.stopCSSCoverage(); + expect(coverage.length).toBe(0); + }); + }); + }); +}; \ No newline at end of file diff --git a/test/frame.spec.js b/test/frame.spec.js index a77794bb2e430..072ad49df64a7 100644 --- a/test/frame.spec.js +++ b/test/frame.spec.js @@ -1,5 +1,5 @@ /** - * Copyright 2017 Google Inc. All rights reserved. + * Copyright 2018 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -374,4 +374,87 @@ module.exports.addTests = function({testRunner, expect}) { expect(await page.evaluate(x => x.textContent, await waitForXPath)).toBe('some text'); }); }); + + describe('Frame Management', function() { + it('should handle nested frames', async({page, server}) => { + await page.goto(server.PREFIX + '/frames/nested-frames.html'); + expect(utils.dumpFrames(page.mainFrame())).toBeGolden('nested-frames.txt'); + }); + it('should send events when frames are manipulated dynamically', async({page, server}) => { + await page.goto(server.EMPTY_PAGE); + // validate frameattached events + const attachedFrames = []; + page.on('frameattached', frame => attachedFrames.push(frame)); + await utils.attachFrame(page, 'frame1', './assets/frame.html'); + expect(attachedFrames.length).toBe(1); + expect(attachedFrames[0].url()).toContain('/assets/frame.html'); + + // validate framenavigated events + const navigatedFrames = []; + page.on('framenavigated', frame => navigatedFrames.push(frame)); + await utils.navigateFrame(page, 'frame1', './empty.html'); + expect(navigatedFrames.length).toBe(1); + expect(navigatedFrames[0].url()).toBe(server.EMPTY_PAGE); + + // validate framedetached events + const detachedFrames = []; + page.on('framedetached', frame => detachedFrames.push(frame)); + await utils.detachFrame(page, 'frame1'); + expect(detachedFrames.length).toBe(1); + expect(detachedFrames[0].isDetached()).toBe(true); + }); + it('should persist mainFrame on cross-process navigation', async({page, server}) => { + await page.goto(server.EMPTY_PAGE); + const mainFrame = page.mainFrame(); + await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html'); + expect(page.mainFrame() === mainFrame).toBeTruthy(); + }); + it('should not send attach/detach events for main frame', async({page, server}) => { + let hasEvents = false; + page.on('frameattached', frame => hasEvents = true); + page.on('framedetached', frame => hasEvents = true); + await page.goto(server.EMPTY_PAGE); + expect(hasEvents).toBe(false); + }); + it('should detach child frames on navigation', async({page, server}) => { + let attachedFrames = []; + let detachedFrames = []; + let navigatedFrames = []; + page.on('frameattached', frame => attachedFrames.push(frame)); + page.on('framedetached', frame => detachedFrames.push(frame)); + page.on('framenavigated', frame => navigatedFrames.push(frame)); + await page.goto(server.PREFIX + '/frames/nested-frames.html'); + expect(attachedFrames.length).toBe(4); + expect(detachedFrames.length).toBe(0); + expect(navigatedFrames.length).toBe(5); + + attachedFrames = []; + detachedFrames = []; + navigatedFrames = []; + await page.goto(server.EMPTY_PAGE); + expect(attachedFrames.length).toBe(0); + expect(detachedFrames.length).toBe(4); + expect(navigatedFrames.length).toBe(1); + }); + it('should report frame.name()', async({page, server}) => { + await utils.attachFrame(page, 'theFrameId', server.EMPTY_PAGE); + await page.evaluate(url => { + const frame = document.createElement('iframe'); + frame.name = 'theFrameName'; + frame.src = url; + document.body.appendChild(frame); + return new Promise(x => frame.onload = x); + }, server.EMPTY_PAGE); + expect(page.frames()[0].name()).toBe(''); + expect(page.frames()[1].name()).toBe('theFrameId'); + expect(page.frames()[2].name()).toBe('theFrameName'); + }); + it('should report frame.parent()', async({page, server}) => { + await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); + await utils.attachFrame(page, 'frame2', server.EMPTY_PAGE); + expect(page.frames()[0].parentFrame()).toBe(null); + expect(page.frames()[1].parentFrame()).toBe(page.mainFrame()); + expect(page.frames()[2].parentFrame()).toBe(page.mainFrame()); + }); + }); }; \ No newline at end of file diff --git a/test/page.spec.js b/test/page.spec.js index d40fedc7adea4..f000045a9860c 100644 --- a/test/page.spec.js +++ b/test/page.spec.js @@ -53,7 +53,11 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p 'tracing.spec.js', 'frame.spec.js', 'input.spec.js', - 'network.spec.js' + 'network.spec.js', + 'cookies.spec.js', + 'target.spec.js', + 'CDPSession.spec.js', + 'coverage.spec.js' ]; testFiles @@ -1086,89 +1090,6 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p }); }); - describe('Frame Management', function() { - it('should handle nested frames', async({page, server}) => { - await page.goto(server.PREFIX + '/frames/nested-frames.html'); - expect(utils.dumpFrames(page.mainFrame())).toBeGolden('nested-frames.txt'); - }); - it('should send events when frames are manipulated dynamically', async({page, server}) => { - await page.goto(server.EMPTY_PAGE); - // validate frameattached events - const attachedFrames = []; - page.on('frameattached', frame => attachedFrames.push(frame)); - await utils.attachFrame(page, 'frame1', './assets/frame.html'); - expect(attachedFrames.length).toBe(1); - expect(attachedFrames[0].url()).toContain('/assets/frame.html'); - - // validate framenavigated events - const navigatedFrames = []; - page.on('framenavigated', frame => navigatedFrames.push(frame)); - await utils.navigateFrame(page, 'frame1', './empty.html'); - expect(navigatedFrames.length).toBe(1); - expect(navigatedFrames[0].url()).toBe(server.EMPTY_PAGE); - - // validate framedetached events - const detachedFrames = []; - page.on('framedetached', frame => detachedFrames.push(frame)); - await utils.detachFrame(page, 'frame1'); - expect(detachedFrames.length).toBe(1); - expect(detachedFrames[0].isDetached()).toBe(true); - }); - it('should persist mainFrame on cross-process navigation', async({page, server}) => { - await page.goto(server.EMPTY_PAGE); - const mainFrame = page.mainFrame(); - await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html'); - expect(page.mainFrame() === mainFrame).toBeTruthy(); - }); - it('should not send attach/detach events for main frame', async({page, server}) => { - let hasEvents = false; - page.on('frameattached', frame => hasEvents = true); - page.on('framedetached', frame => hasEvents = true); - await page.goto(server.EMPTY_PAGE); - expect(hasEvents).toBe(false); - }); - it('should detach child frames on navigation', async({page, server}) => { - let attachedFrames = []; - let detachedFrames = []; - let navigatedFrames = []; - page.on('frameattached', frame => attachedFrames.push(frame)); - page.on('framedetached', frame => detachedFrames.push(frame)); - page.on('framenavigated', frame => navigatedFrames.push(frame)); - await page.goto(server.PREFIX + '/frames/nested-frames.html'); - expect(attachedFrames.length).toBe(4); - expect(detachedFrames.length).toBe(0); - expect(navigatedFrames.length).toBe(5); - - attachedFrames = []; - detachedFrames = []; - navigatedFrames = []; - await page.goto(server.EMPTY_PAGE); - expect(attachedFrames.length).toBe(0); - expect(detachedFrames.length).toBe(4); - expect(navigatedFrames.length).toBe(1); - }); - it('should report frame.name()', async({page, server}) => { - await utils.attachFrame(page, 'theFrameId', server.EMPTY_PAGE); - await page.evaluate(url => { - const frame = document.createElement('iframe'); - frame.name = 'theFrameName'; - frame.src = url; - document.body.appendChild(frame); - return new Promise(x => frame.onload = x); - }, server.EMPTY_PAGE); - expect(page.frames()[0].name()).toBe(''); - expect(page.frames()[1].name()).toBe('theFrameId'); - expect(page.frames()[2].name()).toBe('theFrameName'); - }); - it('should report frame.parent()', async({page, server}) => { - await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); - await utils.attachFrame(page, 'frame2', server.EMPTY_PAGE); - expect(page.frames()[0].parentFrame()).toBe(null); - expect(page.frames()[1].parentFrame()).toBe(page.mainFrame()); - expect(page.frames()[2].parentFrame()).toBe(page.mainFrame()); - }); - }); - describe('Page.$eval', function() { it('should work', async({page, server}) => { await page.setContent('
43543
'); @@ -1857,329 +1778,6 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p }); }); - describe('Cookies', function() { - afterEach(async({page, server}) => { - const cookies = await page.cookies(server.PREFIX + '/grid.html', server.CROSS_PROCESS_PREFIX); - for (const cookie of cookies) - await page.deleteCookie(cookie); - }); - it('should set and get cookies', async({page, server}) => { - await page.goto(server.PREFIX + '/grid.html'); - expect(await page.cookies()).toEqual([]); - await page.evaluate(() => { - document.cookie = 'username=John Doe'; - }); - expect(await page.cookies()).toEqual([{ - name: 'username', - value: 'John Doe', - domain: 'localhost', - path: '/', - expires: -1, - size: 16, - httpOnly: false, - secure: false, - session: true } - ]); - await page.setCookie({ - name: 'password', - value: '123456' - }); - expect(await page.evaluate('document.cookie')).toBe('username=John Doe; password=123456'); - const cookies = await page.cookies(); - expect(cookies.sort((a, b) => a.name.localeCompare(b.name))).toEqual([{ - name: 'password', - value: '123456', - domain: 'localhost', - path: '/', - expires: -1, - size: 14, - httpOnly: false, - secure: false, - session: true - }, { - name: 'username', - value: 'John Doe', - domain: 'localhost', - path: '/', - expires: -1, - size: 16, - httpOnly: false, - secure: false, - session: true - }]); - }); - - it('should set a cookie with a path', async({page, server}) => { - await page.goto(server.PREFIX + '/grid.html'); - await page.setCookie({ - name: 'gridcookie', - value: 'GRID', - path: '/grid.html' - }); - expect(await page.cookies()).toEqual([{ - name: 'gridcookie', - value: 'GRID', - domain: 'localhost', - path: '/grid.html', - expires: -1, - size: 14, - httpOnly: false, - secure: false, - session: true - }]); - expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID'); - await page.goto(server.PREFIX + '/empty.html'); - expect(await page.cookies()).toEqual([]); - expect(await page.evaluate('document.cookie')).toBe(''); - await page.goto(server.PREFIX + '/grid.html'); - expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID'); - }); - - - it('should delete a cookie', async({page, server}) => { - await page.goto(server.PREFIX + '/grid.html'); - await page.setCookie({ - name: 'cookie1', - value: '1' - }, { - name: 'cookie2', - value: '2' - }, { - name: 'cookie3', - value: '3' - }); - expect(await page.evaluate('document.cookie')).toBe('cookie1=1; cookie2=2; cookie3=3'); - await page.deleteCookie({name: 'cookie2'}); - expect(await page.evaluate('document.cookie')).toBe('cookie1=1; cookie3=3'); - }); - - it('should not set a cookie on a blank page', async function({page}) { - let error = null; - await page.goto('about:blank'); - try { - await page.setCookie({name: 'example-cookie', value: 'best'}); - } catch (e) { - error = e; - } - expect(error).toBeTruthy(); - expect(error.message).toEqual('Protocol error (Network.deleteCookies): At least one of the url and domain needs to be specified undefined'); - }); - - it('should not set a cookie with blank page URL', async function({page, server}) { - let error = null; - await page.goto(server.PREFIX + '/grid.html'); - try { - await page.setCookie( - {name: 'example-cookie', value: 'best'}, - {url: 'about:blank', name: 'example-cookie-blank', value: 'best'} - ); - } catch (e) { - error = e; - } - expect(error).toBeTruthy(); - expect(error.message).toEqual( - `Blank page can not have cookie "example-cookie-blank"` - ); - }); - - it('should not set a cookie on a data URL page', async function({page}) { - let error = null; - await page.goto('data:,Hello%2C%20World!'); - try { - await page.setCookie({name: 'example-cookie', value: 'best'}); - } catch (e) { - error = e; - } - expect(error).toBeTruthy(); - expect(error.message).toEqual( - 'Protocol error (Network.deleteCookies): At least one of the url and domain needs to be specified undefined' - ); - }); - - it('should not set a cookie with blank page URL', async function({page, server}) { - let error = null; - await page.goto(server.PREFIX + '/grid.html'); - try { - await page.setCookie({name: 'example-cookie', value: 'best'}, {url: 'about:blank', name: 'example-cookie-blank', value: 'best'}); - } catch (e) { - error = e; - } - expect(error).toBeTruthy(); - expect(error.message).toEqual(`Blank page can not have cookie "example-cookie-blank"`); - }); - - it('should set a cookie on a different domain', async({page, server}) => { - await page.goto(server.PREFIX + '/grid.html'); - await page.setCookie({name: 'example-cookie', value: 'best', url: 'https://www.example.com'}); - expect(await page.evaluate('document.cookie')).toBe(''); - expect(await page.cookies()).toEqual([]); - expect(await page.cookies('https://www.example.com')).toEqual([{ - name: 'example-cookie', - value: 'best', - domain: 'www.example.com', - path: '/', - expires: -1, - size: 18, - httpOnly: false, - secure: true, - session: true - }]); - }); - - it('should set cookies from a frame', async({page, server}) => { - await page.goto(server.PREFIX + '/grid.html'); - await page.setCookie({name: 'localhost-cookie', value: 'best'}); - await page.evaluate(src => { - let fulfill; - const promise = new Promise(x => fulfill = x); - const iframe = document.createElement('iframe'); - document.body.appendChild(iframe); - iframe.onload = fulfill; - iframe.src = src; - return promise; - }, server.CROSS_PROCESS_PREFIX); - await page.setCookie({name: '127-cookie', value: 'worst', url: server.CROSS_PROCESS_PREFIX}); - expect(await page.evaluate('document.cookie')).toBe('localhost-cookie=best'); - expect(await page.frames()[1].evaluate('document.cookie')).toBe('127-cookie=worst'); - - expect(await page.cookies()).toEqual([{ - name: 'localhost-cookie', - value: 'best', - domain: 'localhost', - path: '/', - expires: -1, - size: 20, - httpOnly: false, - secure: false, - session: true - }]); - - expect(await page.cookies(server.CROSS_PROCESS_PREFIX)).toEqual([{ - name: '127-cookie', - value: 'worst', - domain: '127.0.0.1', - path: '/', - expires: -1, - size: 15, - httpOnly: false, - secure: false, - session: true - }]); - - }); - }); - - describe('Target', function() { - it('Browser.targets should return all of the targets', async({page, server, browser}) => { - // The pages will be the testing page and the original newtab page - const targets = browser.targets(); - expect(targets.some(target => target.type() === 'page' && - target.url() === 'about:blank')).toBeTruthy('Missing blank page'); - expect(targets.some(target => target.type() === 'browser')).toBeTruthy('Missing browser target'); - }); - it('Browser.pages should return all of the pages', async({page, server, browser}) => { - // The pages will be the testing page and the original newtab page - const allPages = await browser.pages(); - expect(allPages.length).toBe(2); - expect(allPages).toContain(page); - expect(allPages[0]).not.toBe(allPages[1]); - }); - it('should contain browser target', async({browser}) => { - const targets = browser.targets(); - const browserTarget = targets.find(target => target.type() === 'browser'); - expect(browserTarget).toBeTruthy(); - }); - it('should be able to use the default page in the browser', async({page, server, browser}) => { - // The pages will be the testing page and the original newtab page - const allPages = await browser.pages(); - const originalPage = allPages.find(p => p !== page); - expect(await originalPage.evaluate(() => ['Hello', 'world'].join(' '))).toBe('Hello world'); - expect(await originalPage.$('body')).toBeTruthy(); - }); - it('should report when a new page is created and closed', async({page, server, browser}) => { - const otherPagePromise = new Promise(fulfill => browser.once('targetcreated', target => fulfill(target.page()))); - await page.evaluate(url => window.open(url), server.CROSS_PROCESS_PREFIX); - const otherPage = await otherPagePromise; - expect(otherPage.url()).toContain(server.CROSS_PROCESS_PREFIX); - - expect(await otherPage.evaluate(() => ['Hello', 'world'].join(' '))).toBe('Hello world'); - expect(await otherPage.$('body')).toBeTruthy(); - - let allPages = await browser.pages(); - expect(allPages).toContain(page); - expect(allPages).toContain(otherPage); - - const closePagePromise = new Promise(fulfill => browser.once('targetdestroyed', target => fulfill(target.page()))); - await otherPage.close(); - expect(await closePagePromise).toBe(otherPage); - - allPages = await Promise.all(browser.targets().map(target => target.page())); - expect(allPages).toContain(page); - expect(allPages).not.toContain(otherPage); - }); - it('should report when a service worker is created and destroyed', async({page, server, browser}) => { - await page.goto(server.EMPTY_PAGE); - const createdTarget = new Promise(fulfill => browser.once('targetcreated', target => fulfill(target))); - - await page.goto(server.PREFIX + '/serviceworkers/empty/sw.html'); - - expect((await createdTarget).type()).toBe('service_worker'); - expect((await createdTarget).url()).toBe(server.PREFIX + '/serviceworkers/empty/sw.js'); - - const destroyedTarget = new Promise(fulfill => browser.once('targetdestroyed', target => fulfill(target))); - await page.evaluate(() => window.registrationPromise.then(registration => registration.unregister())); - expect(await destroyedTarget).toBe(await createdTarget); - }); - it('should report when a target url changes', async({page, server, browser}) => { - await page.goto(server.EMPTY_PAGE); - let changedTarget = new Promise(fulfill => browser.once('targetchanged', target => fulfill(target))); - await page.goto(server.CROSS_PROCESS_PREFIX + '/'); - expect((await changedTarget).url()).toBe(server.CROSS_PROCESS_PREFIX + '/'); - - changedTarget = new Promise(fulfill => browser.once('targetchanged', target => fulfill(target))); - await page.goto(server.EMPTY_PAGE); - expect((await changedTarget).url()).toBe(server.EMPTY_PAGE); - }); - it('should not report uninitialized pages', async({page, server, browser}) => { - let targetChanged = false; - const listener = () => targetChanged = true; - browser.on('targetchanged', listener); - const targetPromise = new Promise(fulfill => browser.once('targetcreated', target => fulfill(target))); - const newPagePromise = browser.newPage(); - const target = await targetPromise; - expect(target.url()).toBe('about:blank'); - - const newPage = await newPagePromise; - const targetPromise2 = new Promise(fulfill => browser.once('targetcreated', target => fulfill(target))); - const evaluatePromise = newPage.evaluate(() => window.open('about:blank')); - const target2 = await targetPromise2; - expect(target2.url()).toBe('about:blank'); - await evaluatePromise; - await newPage.close(); - expect(targetChanged).toBe(false, 'target should not be reported as changed'); - browser.removeListener('targetchanged', listener); - }); - it('should not crash while redirecting if original request was missed', async({page, server, browser}) => { - let serverResponse = null; - server.setRoute('/one-style.css', (req, res) => serverResponse = res); - // Open a new page. Use window.open to connect to the page later. - await Promise.all([ - page.evaluate(url => window.open(url), server.PREFIX + '/one-style.html'), - server.waitForRequest('/one-style.css') - ]); - // Connect to the opened page. - const target = browser.targets().find(target => target.url().includes('one-style.html')); - const newPage = await target.page(); - // Issue a redirect. - serverResponse.writeHead(302, { location: '/injectedstyle.css' }); - serverResponse.end(); - // Wait for the new page to load. - await waitForEvents(newPage, 'load'); - // Cleanup. - await newPage.close(); - }); - }); - describe('Connection', function() { it('should throw nice errors', async function({page}) { const error = await theSourceOfTheProblems().catch(error => error); @@ -2191,212 +1789,6 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p }); }); - describe('Target.createCDPSession', function() { - it('should work', async function({page, server}) { - const client = await page.target().createCDPSession(); - - await Promise.all([ - client.send('Runtime.enable'), - client.send('Runtime.evaluate', { expression: 'window.foo = "bar"' }) - ]); - const foo = await page.evaluate(() => window.foo); - expect(foo).toBe('bar'); - }); - it('should send events', async function({page, server}) { - const client = await page.target().createCDPSession(); - await client.send('Network.enable'); - const events = []; - client.on('Network.requestWillBeSent', event => events.push(event)); - await page.goto(server.EMPTY_PAGE); - expect(events.length).toBe(1); - }); - it('should enable and disable domains independently', async function({page, server}) { - const client = await page.target().createCDPSession(); - await client.send('Runtime.enable'); - await client.send('Debugger.enable'); - // JS coverage enables and then disables Debugger domain. - await page.coverage.startJSCoverage(); - await page.coverage.stopJSCoverage(); - // generate a script in page and wait for the event. - const [event] = await Promise.all([ - waitForEvents(client, 'Debugger.scriptParsed'), - page.evaluate('//# sourceURL=foo.js') - ]); - // expect events to be dispatched. - expect(event.url).toBe('foo.js'); - }); - it('should be able to detach session', async function({page, server}) { - const client = await page.target().createCDPSession(); - await client.send('Runtime.enable'); - const evalResponse = await client.send('Runtime.evaluate', {expression: '1 + 2', returnByValue: true}); - expect(evalResponse.result.value).toBe(3); - await client.detach(); - let error = null; - try { - await client.send('Runtime.evaluate', {expression: '3 + 1', returnByValue: true}); - } catch (e) { - error = e; - } - expect(error.message).toContain('Session closed.'); - }); - }); - - describe('JSCoverage', function() { - it('should work', async function({page, server}) { - await page.coverage.startJSCoverage(); - await page.goto(server.PREFIX + '/jscoverage/simple.html'); - const coverage = await page.coverage.stopJSCoverage(); - expect(coverage.length).toBe(1); - expect(coverage[0].url).toContain('/jscoverage/simple.html'); - expect(coverage[0].ranges).toEqual([ - { start: 0, end: 17 }, - { start: 35, end: 61 }, - ]); - }); - it('should report sourceURLs', async function({page, server}) { - await page.coverage.startJSCoverage(); - await page.goto(server.PREFIX + '/jscoverage/sourceurl.html'); - const coverage = await page.coverage.stopJSCoverage(); - expect(coverage.length).toBe(1); - expect(coverage[0].url).toBe('nicename.js'); - }); - it('should ignore anonymous scripts', async function({page, server}) { - await page.coverage.startJSCoverage(); - await page.goto(server.EMPTY_PAGE); - await page.evaluate(() => console.log(1)); - const coverage = await page.coverage.stopJSCoverage(); - expect(coverage.length).toBe(0); - }); - it('should report multiple scripts', async function({page, server}) { - await page.coverage.startJSCoverage(); - await page.goto(server.PREFIX + '/jscoverage/multiple.html'); - const coverage = await page.coverage.stopJSCoverage(); - expect(coverage.length).toBe(2); - coverage.sort((a, b) => a.url.localeCompare(b.url)); - expect(coverage[0].url).toContain('/jscoverage/script1.js'); - expect(coverage[1].url).toContain('/jscoverage/script2.js'); - }); - it('should report right ranges', async function({page, server}) { - await page.coverage.startJSCoverage(); - await page.goto(server.PREFIX + '/jscoverage/ranges.html'); - const coverage = await page.coverage.stopJSCoverage(); - expect(coverage.length).toBe(1); - const entry = coverage[0]; - expect(entry.ranges.length).toBe(1); - const range = entry.ranges[0]; - expect(entry.text.substring(range.start, range.end)).toBe(`console.log('used!');`); - }); - it('should report scripts that have no coverage', async function({page, server}) { - await page.coverage.startJSCoverage(); - await page.goto(server.PREFIX + '/jscoverage/unused.html'); - const coverage = await page.coverage.stopJSCoverage(); - expect(coverage.length).toBe(1); - const entry = coverage[0]; - expect(entry.url).toContain('unused.html'); - expect(entry.ranges.length).toBe(0); - }); - it('should work with conditionals', async function({page, server}) { - await page.coverage.startJSCoverage(); - await page.goto(server.PREFIX + '/jscoverage/involved.html'); - const coverage = await page.coverage.stopJSCoverage(); - expect(JSON.stringify(coverage, null, 2).replace(/:\d{4}\//g, ':/')).toBeGolden('jscoverage-involved.txt'); - }); - describe('resetOnNavigation', function() { - it('should report scripts across navigations when disabled', async function({page, server}) { - await page.coverage.startJSCoverage({resetOnNavigation: false}); - await page.goto(server.PREFIX + '/jscoverage/multiple.html'); - await page.goto(server.EMPTY_PAGE); - const coverage = await page.coverage.stopJSCoverage(); - expect(coverage.length).toBe(2); - }); - it('should NOT report scripts across navigations when enabled', async function({page, server}) { - await page.coverage.startJSCoverage(); // Enabled by default. - await page.goto(server.PREFIX + '/jscoverage/multiple.html'); - await page.goto(server.EMPTY_PAGE); - const coverage = await page.coverage.stopJSCoverage(); - expect(coverage.length).toBe(0); - }); - }); - }); - describe('CSSCoverage', function() { - it('should work', async function({page, server}) { - await page.coverage.startCSSCoverage(); - await page.goto(server.PREFIX + '/csscoverage/simple.html'); - const coverage = await page.coverage.stopCSSCoverage(); - expect(coverage.length).toBe(1); - expect(coverage[0].url).toContain('/csscoverage/simple.html'); - expect(coverage[0].ranges).toEqual([ - {start: 1, end: 22} - ]); - const range = coverage[0].ranges[0]; - expect(coverage[0].text.substring(range.start, range.end)).toBe('div { color: green; }'); - }); - it('should report sourceURLs', async function({page, server}) { - await page.coverage.startCSSCoverage(); - await page.goto(server.PREFIX + '/csscoverage/sourceurl.html'); - const coverage = await page.coverage.stopCSSCoverage(); - expect(coverage.length).toBe(1); - expect(coverage[0].url).toBe('nicename.css'); - }); - it('should report multiple stylesheets', async function({page, server}) { - await page.coverage.startCSSCoverage(); - await page.goto(server.PREFIX + '/csscoverage/multiple.html'); - const coverage = await page.coverage.stopCSSCoverage(); - expect(coverage.length).toBe(2); - coverage.sort((a, b) => a.url.localeCompare(b.url)); - expect(coverage[0].url).toContain('/csscoverage/stylesheet1.css'); - expect(coverage[1].url).toContain('/csscoverage/stylesheet2.css'); - }); - it('should report stylesheets that have no coverage', async function({page, server}) { - await page.coverage.startCSSCoverage(); - await page.goto(server.PREFIX + '/csscoverage/unused.html'); - const coverage = await page.coverage.stopCSSCoverage(); - expect(coverage.length).toBe(1); - expect(coverage[0].url).toBe('unused.css'); - expect(coverage[0].ranges.length).toBe(0); - }); - it('should work with media queries', async function({page, server}) { - await page.coverage.startCSSCoverage(); - await page.goto(server.PREFIX + '/csscoverage/media.html'); - const coverage = await page.coverage.stopCSSCoverage(); - expect(coverage.length).toBe(1); - expect(coverage[0].url).toContain('/csscoverage/media.html'); - expect(coverage[0].ranges).toEqual([ - {start: 17, end: 38} - ]); - }); - it('should work with complicated usecases', async function({page, server}) { - await page.coverage.startCSSCoverage(); - await page.goto(server.PREFIX + '/csscoverage/involved.html'); - const coverage = await page.coverage.stopCSSCoverage(); - expect(JSON.stringify(coverage, null, 2).replace(/:\d{4}\//g, ':/')).toBeGolden('csscoverage-involved.txt'); - }); - it('should ignore injected stylesheets', async function({page, server}) { - await page.coverage.startCSSCoverage(); - await page.addStyleTag({content: 'body { margin: 10px;}'}); - // trigger style recalc - const margin = await page.evaluate(() => window.getComputedStyle(document.body).margin); - expect(margin).toBe('10px'); - const coverage = await page.coverage.stopCSSCoverage(); - expect(coverage.length).toBe(0); - }); - describe('resetOnNavigation', function() { - it('should report stylesheets across navigations', async function({page, server}) { - await page.coverage.startCSSCoverage({resetOnNavigation: false}); - await page.goto(server.PREFIX + '/csscoverage/multiple.html'); - await page.goto(server.EMPTY_PAGE); - const coverage = await page.coverage.stopCSSCoverage(); - expect(coverage.length).toBe(2); - }); - it('should NOT report scripts across navigations', async function({page, server}) { - await page.coverage.startCSSCoverage(); // Enabled by default. - await page.goto(server.PREFIX + '/csscoverage/multiple.html'); - await page.goto(server.EMPTY_PAGE); - const coverage = await page.coverage.stopCSSCoverage(); - expect(coverage.length).toBe(0); - }); - }); - }); describe('Page.Events.Close', function() { it('should work with window.close', async function({ page, browser, server }) { const newPagePromise = new Promise(fulfill => browser.once('targetcreated', target => fulfill(target.page()))); diff --git a/test/target.spec.js b/test/target.spec.js new file mode 100644 index 0000000000000..3faf7141a2936 --- /dev/null +++ b/test/target.spec.js @@ -0,0 +1,134 @@ +/** + * Copyright 2018 Google Inc. All rights reserved. + * + * 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 {waitForEvents} = require('./utils'); + +module.exports.addTests = function({testRunner, expect}) { + const {describe, xdescribe, fdescribe} = testRunner; + const {it, fit, xit} = testRunner; + const {beforeAll, beforeEach, afterAll, afterEach} = testRunner; + + describe('Target', function() { + it('Browser.targets should return all of the targets', async({page, server, browser}) => { + // The pages will be the testing page and the original newtab page + const targets = browser.targets(); + expect(targets.some(target => target.type() === 'page' && + target.url() === 'about:blank')).toBeTruthy('Missing blank page'); + expect(targets.some(target => target.type() === 'browser')).toBeTruthy('Missing browser target'); + }); + it('Browser.pages should return all of the pages', async({page, server, browser}) => { + // The pages will be the testing page and the original newtab page + const allPages = await browser.pages(); + expect(allPages.length).toBe(2); + expect(allPages).toContain(page); + expect(allPages[0]).not.toBe(allPages[1]); + }); + it('should contain browser target', async({browser}) => { + const targets = browser.targets(); + const browserTarget = targets.find(target => target.type() === 'browser'); + expect(browserTarget).toBeTruthy(); + }); + it('should be able to use the default page in the browser', async({page, server, browser}) => { + // The pages will be the testing page and the original newtab page + const allPages = await browser.pages(); + const originalPage = allPages.find(p => p !== page); + expect(await originalPage.evaluate(() => ['Hello', 'world'].join(' '))).toBe('Hello world'); + expect(await originalPage.$('body')).toBeTruthy(); + }); + it('should report when a new page is created and closed', async({page, server, browser}) => { + const otherPagePromise = new Promise(fulfill => browser.once('targetcreated', target => fulfill(target.page()))); + await page.evaluate(url => window.open(url), server.CROSS_PROCESS_PREFIX); + const otherPage = await otherPagePromise; + expect(otherPage.url()).toContain(server.CROSS_PROCESS_PREFIX); + + expect(await otherPage.evaluate(() => ['Hello', 'world'].join(' '))).toBe('Hello world'); + expect(await otherPage.$('body')).toBeTruthy(); + + let allPages = await browser.pages(); + expect(allPages).toContain(page); + expect(allPages).toContain(otherPage); + + const closePagePromise = new Promise(fulfill => browser.once('targetdestroyed', target => fulfill(target.page()))); + await otherPage.close(); + expect(await closePagePromise).toBe(otherPage); + + allPages = await Promise.all(browser.targets().map(target => target.page())); + expect(allPages).toContain(page); + expect(allPages).not.toContain(otherPage); + }); + it('should report when a service worker is created and destroyed', async({page, server, browser}) => { + await page.goto(server.EMPTY_PAGE); + const createdTarget = new Promise(fulfill => browser.once('targetcreated', target => fulfill(target))); + + await page.goto(server.PREFIX + '/serviceworkers/empty/sw.html'); + + expect((await createdTarget).type()).toBe('service_worker'); + expect((await createdTarget).url()).toBe(server.PREFIX + '/serviceworkers/empty/sw.js'); + + const destroyedTarget = new Promise(fulfill => browser.once('targetdestroyed', target => fulfill(target))); + await page.evaluate(() => window.registrationPromise.then(registration => registration.unregister())); + expect(await destroyedTarget).toBe(await createdTarget); + }); + it('should report when a target url changes', async({page, server, browser}) => { + await page.goto(server.EMPTY_PAGE); + let changedTarget = new Promise(fulfill => browser.once('targetchanged', target => fulfill(target))); + await page.goto(server.CROSS_PROCESS_PREFIX + '/'); + expect((await changedTarget).url()).toBe(server.CROSS_PROCESS_PREFIX + '/'); + + changedTarget = new Promise(fulfill => browser.once('targetchanged', target => fulfill(target))); + await page.goto(server.EMPTY_PAGE); + expect((await changedTarget).url()).toBe(server.EMPTY_PAGE); + }); + it('should not report uninitialized pages', async({page, server, browser}) => { + let targetChanged = false; + const listener = () => targetChanged = true; + browser.on('targetchanged', listener); + const targetPromise = new Promise(fulfill => browser.once('targetcreated', target => fulfill(target))); + const newPagePromise = browser.newPage(); + const target = await targetPromise; + expect(target.url()).toBe('about:blank'); + + const newPage = await newPagePromise; + const targetPromise2 = new Promise(fulfill => browser.once('targetcreated', target => fulfill(target))); + const evaluatePromise = newPage.evaluate(() => window.open('about:blank')); + const target2 = await targetPromise2; + expect(target2.url()).toBe('about:blank'); + await evaluatePromise; + await newPage.close(); + expect(targetChanged).toBe(false, 'target should not be reported as changed'); + browser.removeListener('targetchanged', listener); + }); + it('should not crash while redirecting if original request was missed', async({page, server, browser}) => { + let serverResponse = null; + server.setRoute('/one-style.css', (req, res) => serverResponse = res); + // Open a new page. Use window.open to connect to the page later. + await Promise.all([ + page.evaluate(url => window.open(url), server.PREFIX + '/one-style.html'), + server.waitForRequest('/one-style.css') + ]); + // Connect to the opened page. + const target = browser.targets().find(target => target.url().includes('one-style.html')); + const newPage = await target.page(); + // Issue a redirect. + serverResponse.writeHead(302, { location: '/injectedstyle.css' }); + serverResponse.end(); + // Wait for the new page to load. + await waitForEvents(newPage, 'load'); + // Cleanup. + await newPage.close(); + }); + }); +}; \ No newline at end of file