test: Break 'page.spec.js' to smaller files (#2218)
This patch breaks huge `page.spec.js` into a bunch of smaller files.
This commit is contained in:
parent
38c6873fbb
commit
47481967c5
75
test/browser.spec.js
Normal file
75
test/browser.spec.js
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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, defaultBrowserOptions, puppeteer}) {
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit} = testRunner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
const headless = defaultBrowserOptions.headless;
|
||||
|
||||
describe('Browser.version', function() {
|
||||
it('should return whether we are in headless', async({browser}) => {
|
||||
const version = await browser.version();
|
||||
expect(version.length).toBeGreaterThan(0);
|
||||
expect(version.startsWith('Headless')).toBe(headless);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Browser.userAgent', function() {
|
||||
it('should include WebKit', async({browser}) => {
|
||||
const userAgent = await browser.userAgent();
|
||||
expect(userAgent.length).toBeGreaterThan(0);
|
||||
expect(userAgent).toContain('WebKit');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Browser.process', function() {
|
||||
it('should return child_process instance', async function({browser}) {
|
||||
const process = await browser.process();
|
||||
expect(process.pid).toBeGreaterThan(0);
|
||||
const browserWSEndpoint = browser.wsEndpoint();
|
||||
const remoteBrowser = await puppeteer.connect({browserWSEndpoint});
|
||||
expect(remoteBrowser.process()).toBe(null);
|
||||
await remoteBrowser.disconnect();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Browser.Events.disconnected', function() {
|
||||
it('should emitted when: browser gets closed, disconnected or underlying websocket gets closed', async() => {
|
||||
const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
|
||||
const browserWSEndpoint = originalBrowser.wsEndpoint();
|
||||
const remoteBrowser1 = await puppeteer.connect({browserWSEndpoint});
|
||||
const remoteBrowser2 = await puppeteer.connect({browserWSEndpoint});
|
||||
|
||||
let disconnectedOriginal = 0;
|
||||
let disconnectedRemote1 = 0;
|
||||
let disconnectedRemote2 = 0;
|
||||
originalBrowser.on('disconnected', () => ++disconnectedOriginal);
|
||||
remoteBrowser1.on('disconnected', () => ++disconnectedRemote1);
|
||||
remoteBrowser2.on('disconnected', () => ++disconnectedRemote2);
|
||||
|
||||
await remoteBrowser2.disconnect();
|
||||
expect(disconnectedOriginal).toBe(0);
|
||||
expect(disconnectedRemote1).toBe(0);
|
||||
expect(disconnectedRemote2).toBe(1);
|
||||
|
||||
await originalBrowser.close();
|
||||
expect(disconnectedOriginal).toBe(1);
|
||||
expect(disconnectedRemote1).toBe(1);
|
||||
expect(disconnectedRemote2).toBe(1);
|
||||
});
|
||||
});
|
||||
};
|
272
test/elementhandle.spec.js
Normal file
272
test/elementhandle.spec.js
Normal file
@ -0,0 +1,272 @@
|
||||
/**
|
||||
* 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 utils = 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('ElementHandle.boundingBox', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const elementHandle = await page.$('.box:nth-of-type(13)');
|
||||
const box = await elementHandle.boundingBox();
|
||||
expect(box).toEqual({ x: 100, y: 50, width: 50, height: 50 });
|
||||
});
|
||||
it('should handle nested frames', async({page, server}) => {
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/frames/nested-frames.html');
|
||||
const nestedFrame = page.frames()[1].childFrames()[1];
|
||||
const elementHandle = await nestedFrame.$('div');
|
||||
const box = await elementHandle.boundingBox();
|
||||
expect(box).toEqual({ x: 28, y: 260, width: 264, height: 18 });
|
||||
});
|
||||
it('should return null for invisible elements', async({page, server}) => {
|
||||
await page.setContent('<div style="display:none">hi</div>');
|
||||
const element = await page.$('div');
|
||||
expect(await element.boundingBox()).toBe(null);
|
||||
});
|
||||
it('should force a layout', async({page, server}) => {
|
||||
await page.setViewport({ width: 500, height: 500 });
|
||||
await page.setContent('<div style="width: 100px; height: 100px">hello</div>');
|
||||
const elementHandle = await page.$('div');
|
||||
await page.evaluate(element => element.style.height = '200px', elementHandle);
|
||||
const box = await elementHandle.boundingBox();
|
||||
expect(box).toEqual({ x: 8, y: 8, width: 100, height: 200 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('ElementHandle.contentFrame', function() {
|
||||
it('should work', async({page,server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
const elementHandle = await page.$('#frame1');
|
||||
const frame = await elementHandle.contentFrame();
|
||||
expect(frame).toBe(page.frames()[1]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ElementHandle.click', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
const button = await page.$('button');
|
||||
await button.click();
|
||||
expect(await page.evaluate(() => result)).toBe('Clicked');
|
||||
});
|
||||
it('should work for Shadow DOM v1', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/shadow.html');
|
||||
const buttonHandle = await page.evaluateHandle(() => button);
|
||||
await buttonHandle.click();
|
||||
expect(await page.evaluate(() => clicked)).toBe(true);
|
||||
});
|
||||
it('should work for TextNodes', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
const buttonTextNode = await page.evaluateHandle(() => document.querySelector('button').firstChild);
|
||||
let error = null;
|
||||
await buttonTextNode.click().catch(err => error = err);
|
||||
expect(error.message).toBe('Node is not of type HTMLElement');
|
||||
});
|
||||
it('should throw for detached nodes', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
const button = await page.$('button');
|
||||
await page.evaluate(button => button.remove(), button);
|
||||
let error = null;
|
||||
await button.click().catch(err => error = err);
|
||||
expect(error.message).toBe('Node is detached from document');
|
||||
});
|
||||
it('should throw for hidden nodes', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
const button = await page.$('button');
|
||||
await page.evaluate(button => button.style.display = 'none', button);
|
||||
const error = await button.click().catch(err => err);
|
||||
expect(error.message).toBe('Node is either not visible or not an HTMLElement');
|
||||
});
|
||||
it('should throw for recursively hidden nodes', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
const button = await page.$('button');
|
||||
await page.evaluate(button => button.parentElement.style.display = 'none', button);
|
||||
const error = await button.click().catch(err => err);
|
||||
expect(error.message).toBe('Node is either not visible or not an HTMLElement');
|
||||
});
|
||||
it('should throw for <br> elements', async({page, server}) => {
|
||||
await page.setContent('hello<br>goodbye');
|
||||
const br = await page.$('br');
|
||||
const error = await br.click().catch(err => err);
|
||||
expect(error.message).toBe('Node is either not visible or not an HTMLElement');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ElementHandle.hover', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/scrollable.html');
|
||||
const button = await page.$('#button-6');
|
||||
await button.hover();
|
||||
expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-6');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ElementHandle.screenshot', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.evaluate(() => window.scrollBy(50, 100));
|
||||
const elementHandle = await page.$('.box:nth-of-type(3)');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-bounding-box.png');
|
||||
});
|
||||
it('should take into account padding and border', async({page, server}) => {
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
await page.setContent(`
|
||||
something above
|
||||
<style>div {
|
||||
border: 2px solid blue;
|
||||
background: green;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
||||
`);
|
||||
const elementHandle = await page.$('div');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-padding-border.png');
|
||||
});
|
||||
it('should capture full element when larger than viewport', async({page, server}) => {
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
|
||||
await page.setContent(`
|
||||
something above
|
||||
<style>
|
||||
div.to-screenshot {
|
||||
border: 1px solid blue;
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
margin-left: 50px;
|
||||
}
|
||||
</style>
|
||||
<div class="to-screenshot"></div>
|
||||
`);
|
||||
const elementHandle = await page.$('div.to-screenshot');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-larger-than-viewport.png');
|
||||
|
||||
expect(await page.evaluate(() => ({ w: window.innerWidth, h: window.innerHeight }))).toEqual({ w: 500, h: 500 });
|
||||
});
|
||||
it('should scroll element into view', async({page, server}) => {
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
await page.setContent(`
|
||||
something above
|
||||
<style>div.above {
|
||||
border: 2px solid blue;
|
||||
background: red;
|
||||
height: 1500px;
|
||||
}
|
||||
div.to-screenshot {
|
||||
border: 2px solid blue;
|
||||
background: green;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
</style>
|
||||
<div class="above"></div>
|
||||
<div class="to-screenshot"></div>
|
||||
`);
|
||||
const elementHandle = await page.$('div.to-screenshot');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-scrolled-into-view.png');
|
||||
});
|
||||
it('should work with a rotated element', async({page, server}) => {
|
||||
await page.setViewport({width: 500, height: 500});
|
||||
await page.setContent(`<div style="position:absolute;
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: green;
|
||||
transform: rotateZ(200deg);"> </div>`);
|
||||
const elementHandle = await page.$('div');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-rotate.png');
|
||||
});
|
||||
it('should fail to screenshot a detached element', async({page, server}) => {
|
||||
await page.setContent('<h1>remove this</h1>');
|
||||
const elementHandle = await page.$('h1');
|
||||
await page.evaluate(element => element.remove(), elementHandle);
|
||||
const screenshotError = await elementHandle.screenshot().catch(error => error);
|
||||
expect(screenshotError.message).toBe('Node is either not visible or not an HTMLElement');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ElementHandle.$', function() {
|
||||
it('should query existing element', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/playground.html');
|
||||
await page.setContent('<html><body><div class="second"><div class="inner">A</div></div></body></html>');
|
||||
const html = await page.$('html');
|
||||
const second = await html.$('.second');
|
||||
const inner = await second.$('.inner');
|
||||
const content = await page.evaluate(e => e.textContent, inner);
|
||||
expect(content).toBe('A');
|
||||
});
|
||||
|
||||
it('should return null for non-existing element', async({page, server}) => {
|
||||
await page.setContent('<html><body><div class="second"><div class="inner">B</div></div></body></html>');
|
||||
const html = await page.$('html');
|
||||
const second = await html.$('.third');
|
||||
expect(second).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ElementHandle.$$', function() {
|
||||
it('should query existing elements', async({page, server}) => {
|
||||
await page.setContent('<html><body><div>A</div><br/><div>B</div></body></html>');
|
||||
const html = await page.$('html');
|
||||
const elements = await html.$$('div');
|
||||
expect(elements.length).toBe(2);
|
||||
const promises = elements.map(element => page.evaluate(e => e.textContent, element));
|
||||
expect(await Promise.all(promises)).toEqual(['A', 'B']);
|
||||
});
|
||||
|
||||
it('should return empty array for non-existing elements', async({page, server}) => {
|
||||
await page.setContent('<html><body><span>A</span><br/><span>B</span></body></html>');
|
||||
const html = await page.$('html');
|
||||
const elements = await html.$$('div');
|
||||
expect(elements.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('ElementHandle.$x', function() {
|
||||
it('should query existing element', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/playground.html');
|
||||
await page.setContent('<html><body><div class="second"><div class="inner">A</div></div></body></html>');
|
||||
const html = await page.$('html');
|
||||
const second = await html.$x(`./body/div[contains(@class, 'second')]`);
|
||||
const inner = await second[0].$x(`./div[contains(@class, 'inner')]`);
|
||||
const content = await page.evaluate(e => e.textContent, inner[0]);
|
||||
expect(content).toBe('A');
|
||||
});
|
||||
|
||||
it('should return null for non-existing element', async({page, server}) => {
|
||||
await page.setContent('<html><body><div class="second"><div class="inner">B</div></div></body></html>');
|
||||
const html = await page.$('html');
|
||||
const second = await html.$x(`/div[contains(@class, 'third')]`);
|
||||
expect(second).toEqual([]);
|
||||
});
|
||||
});
|
||||
};
|
371
test/frame.spec.js
Normal file
371
test/frame.spec.js
Normal file
@ -0,0 +1,371 @@
|
||||
/**
|
||||
* Copyright 2017 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 utils = 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('Frame.context', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
expect(page.frames().length).toBe(2);
|
||||
const [frame1, frame2] = page.frames();
|
||||
const context1 = await frame1.executionContext();
|
||||
const context2 = await frame2.executionContext();
|
||||
expect(context1).toBeTruthy();
|
||||
expect(context2).toBeTruthy();
|
||||
expect(context1 !== context2).toBeTruthy();
|
||||
expect(context1.frame()).toBe(frame1);
|
||||
expect(context2.frame()).toBe(frame2);
|
||||
|
||||
await Promise.all([
|
||||
context1.evaluate(() => window.a = 1),
|
||||
context2.evaluate(() => window.a = 2)
|
||||
]);
|
||||
const [a1, a2] = await Promise.all([
|
||||
context1.evaluate(() => window.a),
|
||||
context2.evaluate(() => window.a)
|
||||
]);
|
||||
expect(a1).toBe(1);
|
||||
expect(a2).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Frame.evaluateHandle', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const mainFrame = page.mainFrame();
|
||||
const windowHandle = await mainFrame.evaluateHandle(() => window);
|
||||
expect(windowHandle).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Frame.evaluate', function() {
|
||||
it('should have different execution contexts', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
expect(page.frames().length).toBe(2);
|
||||
const frame1 = page.frames()[0];
|
||||
const frame2 = page.frames()[1];
|
||||
await frame1.evaluate(() => window.FOO = 'foo');
|
||||
await frame2.evaluate(() => window.FOO = 'bar');
|
||||
expect(await frame1.evaluate(() => window.FOO)).toBe('foo');
|
||||
expect(await frame2.evaluate(() => window.FOO)).toBe('bar');
|
||||
});
|
||||
it('should execute after cross-site navigation', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const mainFrame = page.mainFrame();
|
||||
expect(await mainFrame.evaluate(() => window.location.href)).toContain('localhost');
|
||||
await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
|
||||
expect(await mainFrame.evaluate(() => window.location.href)).toContain('127');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Frame.waitForFunction', function() {
|
||||
it('should accept a string', async({page, server}) => {
|
||||
const watchdog = page.waitForFunction('window.__FOO === 1');
|
||||
await page.evaluate(() => window.__FOO = 1);
|
||||
await watchdog;
|
||||
});
|
||||
it('should poll on interval', async({page, server}) => {
|
||||
let success = false;
|
||||
const startTime = Date.now();
|
||||
const polling = 100;
|
||||
const watchdog = page.waitForFunction(() => window.__FOO === 'hit', {polling})
|
||||
.then(() => success = true);
|
||||
await page.evaluate(() => window.__FOO = 'hit');
|
||||
expect(success).toBe(false);
|
||||
await page.evaluate(() => document.body.appendChild(document.createElement('div')));
|
||||
await watchdog;
|
||||
expect(Date.now() - startTime).not.toBeLessThan(polling / 2);
|
||||
});
|
||||
it('should poll on mutation', async({page, server}) => {
|
||||
let success = false;
|
||||
const watchdog = page.waitForFunction(() => window.__FOO === 'hit', {polling: 'mutation'})
|
||||
.then(() => success = true);
|
||||
await page.evaluate(() => window.__FOO = 'hit');
|
||||
expect(success).toBe(false);
|
||||
await page.evaluate(() => document.body.appendChild(document.createElement('div')));
|
||||
await watchdog;
|
||||
});
|
||||
it('should poll on raf', async({page, server}) => {
|
||||
const watchdog = page.waitForFunction(() => window.__FOO === 'hit', {polling: 'raf'});
|
||||
await page.evaluate(() => window.__FOO = 'hit');
|
||||
await watchdog;
|
||||
});
|
||||
it('should throw on bad polling value', async({page, server}) => {
|
||||
let error = null;
|
||||
try {
|
||||
await page.waitForFunction(() => !!document.body, {polling: 'unknown'});
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeTruthy();
|
||||
expect(error.message).toContain('polling');
|
||||
});
|
||||
it('should throw negative polling interval', async({page, server}) => {
|
||||
let error = null;
|
||||
try {
|
||||
await page.waitForFunction(() => !!document.body, {polling: -10});
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeTruthy();
|
||||
expect(error.message).toContain('Cannot poll with non-positive interval');
|
||||
});
|
||||
it('should return the success value as a JSHandle', async({page}) => {
|
||||
expect(await (await page.waitForFunction(() => 5)).jsonValue()).toBe(5);
|
||||
});
|
||||
it('should return the window as a success value', async({ page }) => {
|
||||
expect(await page.waitForFunction(() => window)).toBeTruthy();
|
||||
});
|
||||
it('should accept ElementHandle arguments', async({page}) => {
|
||||
await page.setContent('<div></div>');
|
||||
const div = await page.$('div');
|
||||
let resolved = false;
|
||||
const waitForFunction = page.waitForFunction(element => !element.parentElement, {}, div).then(() => resolved = true);
|
||||
expect(resolved).toBe(false);
|
||||
await page.evaluate(element => element.remove(), div);
|
||||
await waitForFunction;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Frame.waitForSelector', function() {
|
||||
const addElement = tag => document.body.appendChild(document.createElement(tag));
|
||||
|
||||
it('should immediately resolve promise if node exists', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const frame = page.mainFrame();
|
||||
await frame.waitForSelector('*');
|
||||
await frame.evaluate(addElement, 'div');
|
||||
await frame.waitForSelector('div');
|
||||
});
|
||||
|
||||
it('should resolve promise when node is added', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const frame = page.mainFrame();
|
||||
const watchdog = frame.waitForSelector('div');
|
||||
await frame.evaluate(addElement, 'br');
|
||||
await frame.evaluate(addElement, 'div');
|
||||
const eHandle = await watchdog;
|
||||
const tagName = await eHandle.getProperty('tagName').then(e => e.jsonValue());
|
||||
expect(tagName).toBe('DIV');
|
||||
});
|
||||
|
||||
it('should work when node is added through innerHTML', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const watchdog = page.waitForSelector('h3 div');
|
||||
await page.evaluate(addElement, 'span');
|
||||
await page.evaluate(() => document.querySelector('span').innerHTML = '<h3><div></div></h3>');
|
||||
await watchdog;
|
||||
});
|
||||
|
||||
it('Page.waitForSelector is shortcut for main frame', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
const otherFrame = page.frames()[1];
|
||||
const watchdog = page.waitForSelector('div');
|
||||
await otherFrame.evaluate(addElement, 'div');
|
||||
await page.evaluate(addElement, 'div');
|
||||
const eHandle = await watchdog;
|
||||
expect(eHandle.executionContext().frame()).toBe(page.mainFrame());
|
||||
});
|
||||
|
||||
it('should run in specified frame', async({page, server}) => {
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
await utils.attachFrame(page, 'frame2', server.EMPTY_PAGE);
|
||||
const frame1 = page.frames()[1];
|
||||
const frame2 = page.frames()[2];
|
||||
const waitForSelectorPromise = frame2.waitForSelector('div');
|
||||
await frame1.evaluate(addElement, 'div');
|
||||
await frame2.evaluate(addElement, 'div');
|
||||
const eHandle = await waitForSelectorPromise;
|
||||
expect(eHandle.executionContext().frame()).toBe(frame2);
|
||||
});
|
||||
|
||||
it('should throw if evaluation failed', async({page, server}) => {
|
||||
await page.evaluateOnNewDocument(function() {
|
||||
document.querySelector = null;
|
||||
});
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
let error = null;
|
||||
await page.waitForSelector('*').catch(e => error = e);
|
||||
expect(error.message).toContain('document.querySelector is not a function');
|
||||
});
|
||||
it('should throw when frame is detached', async({page, server}) => {
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
const frame = page.frames()[1];
|
||||
let waitError = null;
|
||||
const waitPromise = frame.waitForSelector('.box').catch(e => waitError = e);
|
||||
await utils.detachFrame(page, 'frame1');
|
||||
await waitPromise;
|
||||
expect(waitError).toBeTruthy();
|
||||
expect(waitError.message).toContain('waitForFunction failed: frame got detached.');
|
||||
});
|
||||
it('should survive cross-process navigation', async({page, server}) => {
|
||||
let boxFound = false;
|
||||
const waitForSelector = page.waitForSelector('.box').then(() => boxFound = true);
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(boxFound).toBe(false);
|
||||
await page.reload();
|
||||
expect(boxFound).toBe(false);
|
||||
await page.goto(server.CROSS_PROCESS_PREFIX + '/grid.html');
|
||||
await waitForSelector;
|
||||
expect(boxFound).toBe(true);
|
||||
});
|
||||
it('should wait for visible', async({page, server}) => {
|
||||
let divFound = false;
|
||||
const waitForSelector = page.waitForSelector('div', {visible: true}).then(() => divFound = true);
|
||||
await page.setContent(`<div style='display: none; visibility: hidden;'>1</div>`);
|
||||
expect(divFound).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.removeProperty('display'));
|
||||
expect(divFound).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.removeProperty('visibility'));
|
||||
expect(await waitForSelector).toBe(true);
|
||||
expect(divFound).toBe(true);
|
||||
});
|
||||
it('should wait for visible recursively', async({page, server}) => {
|
||||
let divVisible = false;
|
||||
const waitForSelector = page.waitForSelector('div#inner', {visible: true}).then(() => divVisible = true);
|
||||
await page.setContent(`<div style='display: none; visibility: hidden;'><div id="inner">hi</div></div>`);
|
||||
expect(divVisible).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.removeProperty('display'));
|
||||
expect(divVisible).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.removeProperty('visibility'));
|
||||
expect(await waitForSelector).toBe(true);
|
||||
expect(divVisible).toBe(true);
|
||||
});
|
||||
it('hidden should wait for visibility: hidden', async({page, server}) => {
|
||||
let divHidden = false;
|
||||
await page.setContent(`<div style='display: block;'></div>`);
|
||||
const waitForSelector = page.waitForSelector('div', {hidden: true}).then(() => divHidden = true);
|
||||
await page.waitForSelector('div'); // do a round trip
|
||||
expect(divHidden).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.setProperty('visibility', 'hidden'));
|
||||
expect(await waitForSelector).toBe(true);
|
||||
expect(divHidden).toBe(true);
|
||||
});
|
||||
it('hidden should wait for display: none', async({page, server}) => {
|
||||
let divHidden = false;
|
||||
await page.setContent(`<div style='display: block;'></div>`);
|
||||
const waitForSelector = page.waitForSelector('div', {hidden: true}).then(() => divHidden = true);
|
||||
await page.waitForSelector('div'); // do a round trip
|
||||
expect(divHidden).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.setProperty('display', 'none'));
|
||||
expect(await waitForSelector).toBe(true);
|
||||
expect(divHidden).toBe(true);
|
||||
});
|
||||
it('hidden should wait for removal', async({page, server}) => {
|
||||
await page.setContent(`<div></div>`);
|
||||
let divRemoved = false;
|
||||
const waitForSelector = page.waitForSelector('div', {hidden: true}).then(() => divRemoved = true);
|
||||
await page.waitForSelector('div'); // do a round trip
|
||||
expect(divRemoved).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').remove());
|
||||
expect(await waitForSelector).toBe(true);
|
||||
expect(divRemoved).toBe(true);
|
||||
});
|
||||
it('should respect timeout', async({page, server}) => {
|
||||
let error = null;
|
||||
await page.waitForSelector('div', {timeout: 10}).catch(e => error = e);
|
||||
expect(error).toBeTruthy();
|
||||
expect(error.message).toContain('waiting failed: timeout');
|
||||
});
|
||||
|
||||
it('should respond to node attribute mutation', async({page, server}) => {
|
||||
let divFound = false;
|
||||
const waitForSelector = page.waitForSelector('.zombo').then(() => divFound = true);
|
||||
await page.setContent(`<div class='notZombo'></div>`);
|
||||
expect(divFound).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').className = 'zombo');
|
||||
expect(await waitForSelector).toBe(true);
|
||||
});
|
||||
it('should return the element handle', async({page, server}) => {
|
||||
const waitForSelector = page.waitForSelector('.zombo');
|
||||
await page.setContent(`<div class='zombo'>anything</div>`);
|
||||
expect(await page.evaluate(x => x.textContent, await waitForSelector)).toBe('anything');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Frame.waitForXPath', function() {
|
||||
const addElement = tag => document.body.appendChild(document.createElement(tag));
|
||||
|
||||
it('should support some fancy xpath', async({page, server}) => {
|
||||
await page.setContent(`<p>red herring</p><p>hello world </p>`);
|
||||
const waitForXPath = page.waitForXPath('//p[normalize-space(.)="hello world"]');
|
||||
expect(await page.evaluate(x => x.textContent, await waitForXPath)).toBe('hello world ');
|
||||
});
|
||||
it('should run in specified frame', async({page, server}) => {
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
await utils.attachFrame(page, 'frame2', server.EMPTY_PAGE);
|
||||
const frame1 = page.frames()[1];
|
||||
const frame2 = page.frames()[2];
|
||||
const waitForXPathPromise = frame2.waitForXPath('//div');
|
||||
await frame1.evaluate(addElement, 'div');
|
||||
await frame2.evaluate(addElement, 'div');
|
||||
const eHandle = await waitForXPathPromise;
|
||||
expect(eHandle.executionContext().frame()).toBe(frame2);
|
||||
});
|
||||
it('should throw if evaluation failed', async({page, server}) => {
|
||||
await page.evaluateOnNewDocument(function() {
|
||||
document.evaluate = null;
|
||||
});
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
let error = null;
|
||||
await page.waitForXPath('*').catch(e => error = e);
|
||||
expect(error.message).toContain('document.evaluate is not a function');
|
||||
});
|
||||
it('should throw when frame is detached', async({page, server}) => {
|
||||
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
|
||||
const frame = page.frames()[1];
|
||||
let waitError = null;
|
||||
const waitPromise = frame.waitForXPath('//*[@class="box"]').catch(e => waitError = e);
|
||||
await utils.detachFrame(page, 'frame1');
|
||||
await waitPromise;
|
||||
expect(waitError).toBeTruthy();
|
||||
expect(waitError.message).toContain('waitForFunction failed: frame got detached.');
|
||||
});
|
||||
it('hidden should wait for display: none', async({page, server}) => {
|
||||
let divHidden = false;
|
||||
await page.setContent(`<div style='display: block;'></div>`);
|
||||
const waitForXPath = page.waitForXPath('//div', {hidden: true}).then(() => divHidden = true);
|
||||
await page.waitForXPath('//div'); // do a round trip
|
||||
expect(divHidden).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.setProperty('display', 'none'));
|
||||
expect(await waitForXPath).toBe(true);
|
||||
expect(divHidden).toBe(true);
|
||||
});
|
||||
it('should return the element handle', async({page, server}) => {
|
||||
const waitForXPath = page.waitForXPath('//*[@class="zombo"]');
|
||||
await page.setContent(`<div class='zombo'>anything</div>`);
|
||||
expect(await page.evaluate(x => x.textContent, await waitForXPath)).toBe('anything');
|
||||
});
|
||||
it('should allow you to select a text node', async({page, server}) => {
|
||||
await page.setContent(`<div>some text</div>`);
|
||||
const text = await page.waitForXPath('//div/text()');
|
||||
expect(await (await text.getProperty('nodeType')).jsonValue()).toBe(3 /* Node.TEXT_NODE */);
|
||||
});
|
||||
it('should allow you to select an element with single slash', async({page, server}) => {
|
||||
await page.setContent(`<div>some text</div>`);
|
||||
const waitForXPath = page.waitForXPath('/html/body/div');
|
||||
expect(await page.evaluate(x => x.textContent, await waitForXPath)).toBe('some text');
|
||||
});
|
||||
});
|
||||
};
|
444
test/input.spec.js
Normal file
444
test/input.spec.js
Normal file
@ -0,0 +1,444 @@
|
||||
/**
|
||||
* Copyright 2017 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 path = require('path');
|
||||
const utils = require('./utils');
|
||||
|
||||
module.exports.addTests = function({testRunner, expect, PROJECT_ROOT}) {
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit} = testRunner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
const DeviceDescriptors = require(path.join(PROJECT_ROOT, 'DeviceDescriptors'));
|
||||
const iPhone = DeviceDescriptors['iPhone 6'];
|
||||
describe('input', function() {
|
||||
it('should click the button', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.click('button');
|
||||
expect(await page.evaluate(() => result)).toBe('Clicked');
|
||||
});
|
||||
|
||||
it('should click on checkbox input and toggle', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/checkbox.html');
|
||||
expect(await page.evaluate(() => result.check)).toBe(null);
|
||||
await page.click('input#agree');
|
||||
expect(await page.evaluate(() => result.check)).toBe(true);
|
||||
expect(await page.evaluate(() => result.events)).toEqual([
|
||||
'mouseover',
|
||||
'mouseenter',
|
||||
'mousemove',
|
||||
'mousedown',
|
||||
'mouseup',
|
||||
'click',
|
||||
'input',
|
||||
'change',
|
||||
]);
|
||||
await page.click('input#agree');
|
||||
expect(await page.evaluate(() => result.check)).toBe(false);
|
||||
});
|
||||
|
||||
it('should click on checkbox label and toggle', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/checkbox.html');
|
||||
expect(await page.evaluate(() => result.check)).toBe(null);
|
||||
await page.click('label[for="agree"]');
|
||||
expect(await page.evaluate(() => result.check)).toBe(true);
|
||||
expect(await page.evaluate(() => result.events)).toEqual([
|
||||
'click',
|
||||
'input',
|
||||
'change',
|
||||
]);
|
||||
await page.click('label[for="agree"]');
|
||||
expect(await page.evaluate(() => result.check)).toBe(false);
|
||||
});
|
||||
|
||||
it('should fail to click a missing button', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
let error = null;
|
||||
await page.click('button.does-not-exist').catch(e => error = e);
|
||||
expect(error.message).toBe('No node found for selector: button.does-not-exist');
|
||||
});
|
||||
// @see https://github.com/GoogleChrome/puppeteer/issues/161
|
||||
it('should not hang with touch-enabled viewports', async({page, server}) => {
|
||||
await page.setViewport(iPhone.viewport);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(100, 10);
|
||||
await page.mouse.up();
|
||||
});
|
||||
it('should type into the textarea', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
|
||||
const textarea = await page.$('textarea');
|
||||
await textarea.type('Type in this text!');
|
||||
expect(await page.evaluate(() => result)).toBe('Type in this text!');
|
||||
});
|
||||
it('should click the button after navigation ', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.click('button');
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.click('button');
|
||||
expect(await page.evaluate(() => result)).toBe('Clicked');
|
||||
});
|
||||
it('should upload the file', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/fileupload.html');
|
||||
const filePath = path.relative(process.cwd(), __dirname + '/assets/file-to-upload.txt');
|
||||
const input = await page.$('input');
|
||||
await input.uploadFile(filePath);
|
||||
expect(await page.evaluate(e => e.files[0].name, input)).toBe('file-to-upload.txt');
|
||||
expect(await page.evaluate(e => {
|
||||
const reader = new FileReader();
|
||||
const promise = new Promise(fulfill => reader.onload = fulfill);
|
||||
reader.readAsText(e.files[0]);
|
||||
return promise.then(() => reader.result);
|
||||
}, input)).toBe('contents of the file');
|
||||
});
|
||||
it('should move with the arrow keys', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
await page.type('textarea', 'Hello World!');
|
||||
expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('Hello World!');
|
||||
for (let i = 0; i < 'World!'.length; i++)
|
||||
page.keyboard.press('ArrowLeft');
|
||||
await page.keyboard.type('inserted ');
|
||||
expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('Hello inserted World!');
|
||||
page.keyboard.down('Shift');
|
||||
for (let i = 0; i < 'inserted '.length; i++)
|
||||
page.keyboard.press('ArrowLeft');
|
||||
page.keyboard.up('Shift');
|
||||
await page.keyboard.press('Backspace');
|
||||
expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('Hello World!');
|
||||
});
|
||||
it('should send a character with ElementHandle.press', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
const textarea = await page.$('textarea');
|
||||
await textarea.press('a', {text: 'f'});
|
||||
expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('f');
|
||||
|
||||
await page.evaluate(() => window.addEventListener('keydown', e => e.preventDefault(), true));
|
||||
|
||||
await textarea.press('a', {text: 'y'});
|
||||
expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('f');
|
||||
});
|
||||
it('should send a character with sendCharacter', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
await page.focus('textarea');
|
||||
await page.keyboard.sendCharacter('嗨');
|
||||
expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('嗨');
|
||||
await page.evaluate(() => window.addEventListener('keydown', e => e.preventDefault(), true));
|
||||
await page.keyboard.sendCharacter('a');
|
||||
expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('嗨a');
|
||||
});
|
||||
it('should report shiftKey', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
const keyboard = page.keyboard;
|
||||
const codeForKey = {'Shift': 16, 'Alt': 18, 'Meta': 91, 'Control': 17};
|
||||
for (const modifierKey in codeForKey) {
|
||||
await keyboard.down(modifierKey);
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keydown: ' + modifierKey + ' ' + modifierKey + 'Left ' + codeForKey[modifierKey] + ' [' + modifierKey + ']');
|
||||
await keyboard.down('!');
|
||||
// Shift+! will generate a keypress
|
||||
if (modifierKey === 'Shift')
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keydown: ! Digit1 49 [' + modifierKey + ']\nKeypress: ! Digit1 33 33 33 [' + modifierKey + ']');
|
||||
else
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keydown: ! Digit1 49 [' + modifierKey + ']');
|
||||
|
||||
await keyboard.up('!');
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keyup: ! Digit1 49 [' + modifierKey + ']');
|
||||
await keyboard.up(modifierKey);
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keyup: ' + modifierKey + ' ' + modifierKey + 'Left ' + codeForKey[modifierKey] + ' []');
|
||||
}
|
||||
});
|
||||
it('should report multiple modifiers', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
const keyboard = page.keyboard;
|
||||
await keyboard.down('Control');
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keydown: Control ControlLeft 17 [Control]');
|
||||
await keyboard.down('Meta');
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keydown: Meta MetaLeft 91 [Control Meta]');
|
||||
await keyboard.down(';');
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keydown: ; Semicolon 186 [Control Meta]');
|
||||
await keyboard.up(';');
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keyup: ; Semicolon 186 [Control Meta]');
|
||||
await keyboard.up('Control');
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keyup: Control ControlLeft 17 [Meta]');
|
||||
await keyboard.up('Meta');
|
||||
expect(await page.evaluate(() => getResult())).toBe('Keyup: Meta MetaLeft 91 []');
|
||||
});
|
||||
it('should send proper codes while typing', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
await page.keyboard.type('!');
|
||||
expect(await page.evaluate(() => getResult())).toBe(
|
||||
[ 'Keydown: ! Digit1 49 []',
|
||||
'Keypress: ! Digit1 33 33 33 []',
|
||||
'Keyup: ! Digit1 49 []'].join('\n'));
|
||||
await page.keyboard.type('^');
|
||||
expect(await page.evaluate(() => getResult())).toBe(
|
||||
[ 'Keydown: ^ Digit6 54 []',
|
||||
'Keypress: ^ Digit6 94 94 94 []',
|
||||
'Keyup: ^ Digit6 54 []'].join('\n'));
|
||||
});
|
||||
it('should send proper codes while typing with shift', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
const keyboard = page.keyboard;
|
||||
await keyboard.down('Shift');
|
||||
await page.keyboard.type('~');
|
||||
expect(await page.evaluate(() => getResult())).toBe(
|
||||
[ 'Keydown: Shift ShiftLeft 16 [Shift]',
|
||||
'Keydown: ~ Backquote 192 [Shift]', // 192 is ` keyCode
|
||||
'Keypress: ~ Backquote 126 126 126 [Shift]', // 126 is ~ charCode
|
||||
'Keyup: ~ Backquote 192 [Shift]'].join('\n'));
|
||||
await keyboard.up('Shift');
|
||||
});
|
||||
it('should not type canceled events', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
await page.focus('textarea');
|
||||
await page.evaluate(() => {
|
||||
window.addEventListener('keydown', event => {
|
||||
event.stopPropagation();
|
||||
event.stopImmediatePropagation();
|
||||
if (event.key === 'l')
|
||||
event.preventDefault();
|
||||
if (event.key === 'o')
|
||||
Promise.resolve().then(() => event.preventDefault());
|
||||
}, false);
|
||||
});
|
||||
await page.keyboard.type('Hello World!');
|
||||
expect(await page.evaluate(() => textarea.value)).toBe('He Wrd!');
|
||||
});
|
||||
it('keyboard.modifiers()', async({page, server}) => {
|
||||
const keyboard = page.keyboard;
|
||||
expect(keyboard._modifiers).toBe(0);
|
||||
await keyboard.down('Shift');
|
||||
expect(keyboard._modifiers).toBe(8);
|
||||
await keyboard.down('Alt');
|
||||
expect(keyboard._modifiers).toBe(9);
|
||||
await keyboard.up('Shift');
|
||||
await keyboard.up('Alt');
|
||||
expect(keyboard._modifiers).toBe(0);
|
||||
});
|
||||
it('should resize the textarea', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
const {x, y, width, height} = await page.evaluate(dimensions);
|
||||
const mouse = page.mouse;
|
||||
await mouse.move(x + width - 4, y + height - 4);
|
||||
await mouse.down();
|
||||
await mouse.move(x + width + 100, y + height + 100);
|
||||
await mouse.up();
|
||||
const newDimensions = await page.evaluate(dimensions);
|
||||
expect(newDimensions.width).toBe(width + 104);
|
||||
expect(newDimensions.height).toBe(height + 104);
|
||||
});
|
||||
it('should scroll and click the button', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/scrollable.html');
|
||||
await page.click('#button-5');
|
||||
expect(await page.evaluate(() => document.querySelector('#button-5').textContent)).toBe('clicked');
|
||||
await page.click('#button-80');
|
||||
expect(await page.evaluate(() => document.querySelector('#button-80').textContent)).toBe('clicked');
|
||||
});
|
||||
it('should double click the button', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.evaluate(() => {
|
||||
window.double = false;
|
||||
const button = document.querySelector('button');
|
||||
button.addEventListener('dblclick', event => {
|
||||
window.double = true;
|
||||
});
|
||||
});
|
||||
const button = await page.$('button');
|
||||
await button.click({ clickCount: 2 });
|
||||
expect(await page.evaluate('double')).toBe(true);
|
||||
expect(await page.evaluate('result')).toBe('Clicked');
|
||||
});
|
||||
it('should click a partially obscured button', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.evaluate(() => {
|
||||
const button = document.querySelector('button');
|
||||
button.textContent = 'Some really long text that will go offscreen';
|
||||
button.style.position = 'absolute';
|
||||
button.style.left = '368px';
|
||||
});
|
||||
await page.click('button');
|
||||
expect(await page.evaluate(() => window.result)).toBe('Clicked');
|
||||
});
|
||||
it('should select the text with mouse', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
await page.focus('textarea');
|
||||
const text = 'This is the text that we are going to try to select. Let\'s see how it goes.';
|
||||
await page.keyboard.type(text);
|
||||
await page.evaluate(() => document.querySelector('textarea').scrollTop = 0);
|
||||
const {x, y} = await page.evaluate(dimensions);
|
||||
await page.mouse.move(x + 2,y + 2);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(100,100);
|
||||
await page.mouse.up();
|
||||
expect(await page.evaluate(() => window.getSelection().toString())).toBe(text);
|
||||
});
|
||||
it('should select the text by triple clicking', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
await page.focus('textarea');
|
||||
const text = 'This is the text that we are going to try to select. Let\'s see how it goes.';
|
||||
await page.keyboard.type(text);
|
||||
await page.click('textarea');
|
||||
await page.click('textarea', {clickCount: 2});
|
||||
await page.click('textarea', {clickCount: 3});
|
||||
expect(await page.evaluate(() => window.getSelection().toString())).toBe(text);
|
||||
});
|
||||
it('should trigger hover state', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/scrollable.html');
|
||||
await page.hover('#button-6');
|
||||
expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-6');
|
||||
await page.hover('#button-2');
|
||||
expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-2');
|
||||
await page.hover('#button-91');
|
||||
expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-91');
|
||||
});
|
||||
it('should fire contextmenu event on right click', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/scrollable.html');
|
||||
await page.click('#button-8', {button: 'right'});
|
||||
expect(await page.evaluate(() => document.querySelector('#button-8').textContent)).toBe('context menu');
|
||||
});
|
||||
it('should set modifier keys on click', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/scrollable.html');
|
||||
await page.evaluate(() => document.querySelector('#button-3').addEventListener('mousedown', e => window.lastEvent = e, true));
|
||||
const modifiers = {'Shift': 'shiftKey', 'Control': 'ctrlKey', 'Alt': 'altKey', 'Meta': 'metaKey'};
|
||||
for (const modifier in modifiers) {
|
||||
await page.keyboard.down(modifier);
|
||||
await page.click('#button-3');
|
||||
if (!(await page.evaluate(mod => window.lastEvent[mod], modifiers[modifier])))
|
||||
fail(modifiers[modifier] + ' should be true');
|
||||
await page.keyboard.up(modifier);
|
||||
}
|
||||
await page.click('#button-3');
|
||||
for (const modifier in modifiers) {
|
||||
if ((await page.evaluate(mod => window.lastEvent[mod], modifiers[modifier])))
|
||||
fail(modifiers[modifier] + ' should be false');
|
||||
}
|
||||
});
|
||||
it('should specify repeat property', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
await page.focus('textarea');
|
||||
await page.evaluate(() => document.querySelector('textarea').addEventListener('keydown', e => window.lastEvent = e, true));
|
||||
await page.keyboard.down('a');
|
||||
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(false);
|
||||
await page.keyboard.press('a');
|
||||
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(true);
|
||||
|
||||
await page.keyboard.down('b');
|
||||
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(false);
|
||||
await page.keyboard.down('b');
|
||||
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(true);
|
||||
|
||||
await page.keyboard.up('a');
|
||||
await page.keyboard.down('a');
|
||||
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(false);
|
||||
});
|
||||
// @see https://github.com/GoogleChrome/puppeteer/issues/206
|
||||
it('should click links which cause navigation', async({page, server}) => {
|
||||
await page.setContent(`<a href="${server.EMPTY_PAGE}">empty.html</a>`);
|
||||
// This await should not hang.
|
||||
await page.click('a');
|
||||
});
|
||||
it('should tween mouse movement', async({page, server}) => {
|
||||
await page.mouse.move(100, 100);
|
||||
await page.evaluate(() => {
|
||||
window.result = [];
|
||||
document.addEventListener('mousemove', event => {
|
||||
window.result.push([event.clientX, event.clientY]);
|
||||
});
|
||||
});
|
||||
await page.mouse.move(200, 300, {steps: 5});
|
||||
expect(await page.evaluate('result')).toEqual([
|
||||
[120, 140],
|
||||
[140, 180],
|
||||
[160, 220],
|
||||
[180, 260],
|
||||
[200, 300]
|
||||
]);
|
||||
});
|
||||
it('should tap the button', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.tap('button');
|
||||
expect(await page.evaluate(() => result)).toBe('Clicked');
|
||||
});
|
||||
xit('should report touches', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/touches.html');
|
||||
const button = await page.$('button');
|
||||
await button.tap();
|
||||
expect(await page.evaluate(() => getResult())).toEqual(['Touchstart: 0', 'Touchend: 0']);
|
||||
});
|
||||
it('should click the button inside an iframe', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<div style="width:100px;height:100px">spacer</div>');
|
||||
await utils.attachFrame(page, 'button-test', server.PREFIX + '/input/button.html');
|
||||
const frame = page.frames()[1];
|
||||
const button = await frame.$('button');
|
||||
await button.click();
|
||||
expect(await frame.evaluate(() => window.result)).toBe('Clicked');
|
||||
});
|
||||
it('should click the button with deviceScaleFactor set', async({page, server}) => {
|
||||
await page.setViewport({width: 400, height: 400, deviceScaleFactor: 5});
|
||||
expect(await page.evaluate(() => window.devicePixelRatio)).toBe(5);
|
||||
await page.setContent('<div style="width:100px;height:100px">spacer</div>');
|
||||
await utils.attachFrame(page, 'button-test', server.PREFIX + '/input/button.html');
|
||||
const frame = page.frames()[1];
|
||||
const button = await frame.$('button');
|
||||
await button.click();
|
||||
expect(await frame.evaluate(() => window.result)).toBe('Clicked');
|
||||
});
|
||||
it('should type all kinds of characters', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
await page.focus('textarea');
|
||||
const text = 'This text goes onto two lines.\nThis character is 嗨.';
|
||||
await page.keyboard.type(text);
|
||||
expect(await page.evaluate('result')).toBe(text);
|
||||
});
|
||||
it('should specify location', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/input/textarea.html');
|
||||
await page.evaluate(() => {
|
||||
window.addEventListener('keydown', event => window.keyLocation = event.location, true);
|
||||
});
|
||||
const textarea = await page.$('textarea');
|
||||
|
||||
await textarea.press('Digit5');
|
||||
expect(await page.evaluate('keyLocation')).toBe(0);
|
||||
|
||||
await textarea.press('ControlLeft');
|
||||
expect(await page.evaluate('keyLocation')).toBe(1);
|
||||
|
||||
await textarea.press('ControlRight');
|
||||
expect(await page.evaluate('keyLocation')).toBe(2);
|
||||
|
||||
await textarea.press('NumpadSubtract');
|
||||
expect(await page.evaluate('keyLocation')).toBe(3);
|
||||
});
|
||||
it('should throw on unknown keys', async({page, server}) => {
|
||||
let error = await page.keyboard.press('NotARealKey').catch(e => e);
|
||||
expect(error.message).toBe('Unknown key: "NotARealKey"');
|
||||
|
||||
error = await page.keyboard.press('ё').catch(e => e);
|
||||
expect(error && error.message).toBe('Unknown key: "ё"');
|
||||
|
||||
error = await page.keyboard.press('😊').catch(e => e);
|
||||
expect(error && error.message).toBe('Unknown key: "😊"');
|
||||
});
|
||||
function dimensions() {
|
||||
const rect = document.querySelector('textarea').getBoundingClientRect();
|
||||
return {
|
||||
x: rect.left,
|
||||
y: rect.top,
|
||||
width: rect.width,
|
||||
height: rect.height
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
116
test/jshandle.spec.js
Normal file
116
test/jshandle.spec.js
Normal file
@ -0,0 +1,116 @@
|
||||
/**
|
||||
* 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('JSHandle.getProperty', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
const aHandle = await page.evaluateHandle(() => ({
|
||||
one: 1,
|
||||
two: 2,
|
||||
three: 3
|
||||
}));
|
||||
const twoHandle = await aHandle.getProperty('two');
|
||||
expect(await twoHandle.jsonValue()).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('JSHandle.jsonValue', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
const aHandle = await page.evaluateHandle(() => ({foo: 'bar'}));
|
||||
const json = await aHandle.jsonValue();
|
||||
expect(json).toEqual({foo: 'bar'});
|
||||
});
|
||||
it('should not work with dates', async({page, server}) => {
|
||||
const dateHandle = await page.evaluateHandle(() => new Date('2017-09-26T00:00:00.000Z'));
|
||||
const json = await dateHandle.jsonValue();
|
||||
expect(json).toEqual({});
|
||||
});
|
||||
it('should throw for circular objects', async({page, server}) => {
|
||||
const windowHandle = await page.evaluateHandle('window');
|
||||
let error = null;
|
||||
await windowHandle.jsonValue().catch(e => error = e);
|
||||
expect(error.message).toContain('Object reference chain is too long');
|
||||
});
|
||||
});
|
||||
|
||||
describe('JSHandle.getProperties', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
const aHandle = await page.evaluateHandle(() => ({
|
||||
foo: 'bar'
|
||||
}));
|
||||
const properties = await aHandle.getProperties();
|
||||
const foo = properties.get('foo');
|
||||
expect(foo).toBeTruthy();
|
||||
expect(await foo.jsonValue()).toBe('bar');
|
||||
});
|
||||
it('should return even non-own properties', async({page, server}) => {
|
||||
const aHandle = await page.evaluateHandle(() => {
|
||||
class A {
|
||||
constructor() {
|
||||
this.a = '1';
|
||||
}
|
||||
}
|
||||
class B extends A {
|
||||
constructor() {
|
||||
super();
|
||||
this.b = '2';
|
||||
}
|
||||
}
|
||||
return new B();
|
||||
});
|
||||
const properties = await aHandle.getProperties();
|
||||
expect(await properties.get('a').jsonValue()).toBe('1');
|
||||
expect(await properties.get('b').jsonValue()).toBe('2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('JSHandle.asElement', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
const aHandle = await page.evaluateHandle(() => document.body);
|
||||
const element = aHandle.asElement();
|
||||
expect(element).toBeTruthy();
|
||||
});
|
||||
it('should return null for non-elements', async({page, server}) => {
|
||||
const aHandle = await page.evaluateHandle(() => 2);
|
||||
const element = aHandle.asElement();
|
||||
expect(element).toBeFalsy();
|
||||
});
|
||||
it('should return ElementHandle for TextNodes', async({page, server}) => {
|
||||
await page.setContent('<div>ee!</div>');
|
||||
const aHandle = await page.evaluateHandle(() => document.querySelector('div').firstChild);
|
||||
const element = aHandle.asElement();
|
||||
expect(element).toBeTruthy();
|
||||
expect(await page.evaluate(e => e.nodeType === HTMLElement.TEXT_NODE, element));
|
||||
});
|
||||
});
|
||||
|
||||
describe('JSHandle.toString', function() {
|
||||
it('should work for primitives', async({page, server}) => {
|
||||
const numberHandle = await page.evaluateHandle(() => 2);
|
||||
expect(numberHandle.toString()).toBe('JSHandle:2');
|
||||
const stringHandle = await page.evaluateHandle(() => 'a');
|
||||
expect(stringHandle.toString()).toBe('JSHandle:a');
|
||||
});
|
||||
it('should work for complicated objects', async({page, server}) => {
|
||||
const aHandle = await page.evaluateHandle(() => window);
|
||||
expect(aHandle.toString()).toBe('JSHandle@object');
|
||||
});
|
||||
});
|
||||
};
|
188
test/network.spec.js
Normal file
188
test/network.spec.js
Normal file
@ -0,0 +1,188 @@
|
||||
/**
|
||||
* 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('Network Events', function() {
|
||||
it('Page.Events.Request', async({page, server}) => {
|
||||
const requests = [];
|
||||
page.on('request', request => requests.push(request));
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(requests.length).toBe(1);
|
||||
expect(requests[0].url()).toBe(server.EMPTY_PAGE);
|
||||
expect(requests[0].resourceType()).toBe('document');
|
||||
expect(requests[0].method()).toBe('GET');
|
||||
expect(requests[0].response()).toBeTruthy();
|
||||
expect(requests[0].frame() === page.mainFrame()).toBe(true);
|
||||
expect(requests[0].frame().url()).toBe(server.EMPTY_PAGE);
|
||||
});
|
||||
it('Page.Events.Request should report post data', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
server.setRoute('/post', (req, res) => res.end());
|
||||
let request = null;
|
||||
page.on('request', r => request = r);
|
||||
await page.evaluate(() => fetch('./post', { method: 'POST', body: JSON.stringify({foo: 'bar'})}));
|
||||
expect(request).toBeTruthy();
|
||||
expect(request.postData()).toBe('{"foo":"bar"}');
|
||||
});
|
||||
it('Page.Events.Response', async({page, server}) => {
|
||||
const responses = [];
|
||||
page.on('response', response => responses.push(response));
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(responses.length).toBe(1);
|
||||
expect(responses[0].url()).toBe(server.EMPTY_PAGE);
|
||||
expect(responses[0].status()).toBe(200);
|
||||
expect(responses[0].ok()).toBe(true);
|
||||
expect(responses[0].fromCache()).toBe(false);
|
||||
expect(responses[0].fromServiceWorker()).toBe(false);
|
||||
expect(responses[0].request()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('Response.fromCache()', async({page, server}) => {
|
||||
const responses = new Map();
|
||||
page.on('response', r => responses.set(r.url().split('/').pop(), r));
|
||||
|
||||
// Load and re-load to make sure it's cached.
|
||||
await page.goto(server.PREFIX + '/cached/one-style.html');
|
||||
await page.reload();
|
||||
|
||||
expect(responses.size).toBe(2);
|
||||
expect(responses.get('one-style.html').status()).toBe(304);
|
||||
expect(responses.get('one-style.html').fromCache()).toBe(false);
|
||||
expect(responses.get('one-style.css').status()).toBe(200);
|
||||
expect(responses.get('one-style.css').fromCache()).toBe(true);
|
||||
});
|
||||
it('Response.fromServiceWorker', async({page, server}) => {
|
||||
const responses = new Map();
|
||||
page.on('response', r => responses.set(r.url().split('/').pop(), r));
|
||||
|
||||
// Load and re-load to make sure serviceworker is installed and running.
|
||||
await page.goto(server.PREFIX + '/serviceworkers/fetch/sw.html', {waitUntil: 'networkidle2'});
|
||||
await page.evaluate(async() => await window.activationPromise);
|
||||
await page.reload();
|
||||
|
||||
expect(responses.size).toBe(2);
|
||||
expect(responses.get('sw.html').status()).toBe(200);
|
||||
expect(responses.get('sw.html').fromServiceWorker()).toBe(true);
|
||||
expect(responses.get('style.css').status()).toBe(200);
|
||||
expect(responses.get('style.css').fromServiceWorker()).toBe(true);
|
||||
});
|
||||
|
||||
it('Page.Events.Response should provide body', async({page, server}) => {
|
||||
let response = null;
|
||||
page.on('response', r => response = r);
|
||||
await page.goto(server.PREFIX + '/simple.json');
|
||||
expect(response).toBeTruthy();
|
||||
expect(await response.text()).toBe('{"foo": "bar"}\n');
|
||||
expect(await response.json()).toEqual({foo: 'bar'});
|
||||
});
|
||||
it('Page.Events.Response should not report body unless request is finished', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
// Setup server to trap request.
|
||||
let serverResponse = null;
|
||||
server.setRoute('/get', (req, res) => {
|
||||
serverResponse = res;
|
||||
res.write('hello ');
|
||||
});
|
||||
// Setup page to trap response.
|
||||
let pageResponse = null;
|
||||
let requestFinished = false;
|
||||
page.on('response', r => pageResponse = r);
|
||||
page.on('requestfinished', () => requestFinished = true);
|
||||
// send request and wait for server response
|
||||
await Promise.all([
|
||||
page.evaluate(() => fetch('./get', { method: 'GET'})),
|
||||
waitForEvents(page, 'response')
|
||||
]);
|
||||
|
||||
expect(serverResponse).toBeTruthy();
|
||||
expect(pageResponse).toBeTruthy();
|
||||
expect(pageResponse.status()).toBe(200);
|
||||
expect(requestFinished).toBe(false);
|
||||
|
||||
const responseText = pageResponse.text();
|
||||
// Write part of the response and wait for it to be flushed.
|
||||
await new Promise(x => serverResponse.write('wor', x));
|
||||
// Finish response.
|
||||
await new Promise(x => serverResponse.end('ld!', x));
|
||||
expect(await responseText).toBe('hello world!');
|
||||
});
|
||||
it('Page.Events.RequestFailed', async({page, server}) => {
|
||||
await page.setRequestInterception(true);
|
||||
page.on('request', request => {
|
||||
if (request.url().endsWith('css'))
|
||||
request.abort();
|
||||
else
|
||||
request.continue();
|
||||
});
|
||||
const failedRequests = [];
|
||||
page.on('requestfailed', request => failedRequests.push(request));
|
||||
await page.goto(server.PREFIX + '/one-style.html');
|
||||
expect(failedRequests.length).toBe(1);
|
||||
expect(failedRequests[0].url()).toContain('one-style.css');
|
||||
expect(failedRequests[0].response()).toBe(null);
|
||||
expect(failedRequests[0].resourceType()).toBe('stylesheet');
|
||||
expect(failedRequests[0].failure().errorText).toBe('net::ERR_FAILED');
|
||||
expect(failedRequests[0].frame()).toBeTruthy();
|
||||
});
|
||||
it('Page.Events.RequestFinished', async({page, server}) => {
|
||||
const requests = [];
|
||||
page.on('requestfinished', request => requests.push(request));
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(requests.length).toBe(1);
|
||||
expect(requests[0].url()).toBe(server.EMPTY_PAGE);
|
||||
expect(requests[0].response()).toBeTruthy();
|
||||
expect(requests[0].frame() === page.mainFrame()).toBe(true);
|
||||
expect(requests[0].frame().url()).toBe(server.EMPTY_PAGE);
|
||||
});
|
||||
it('should fire events in proper order', async({page, server}) => {
|
||||
const events = [];
|
||||
page.on('request', request => events.push('request'));
|
||||
page.on('response', response => events.push('response'));
|
||||
page.on('requestfinished', request => events.push('requestfinished'));
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(events).toEqual(['request', 'response', 'requestfinished']);
|
||||
});
|
||||
it('should support redirects', async({page, server}) => {
|
||||
const events = [];
|
||||
page.on('request', request => events.push(`${request.method()} ${request.url()}`));
|
||||
page.on('response', response => events.push(`${response.status()} ${response.url()}`));
|
||||
page.on('requestfinished', request => events.push(`DONE ${request.url()}`));
|
||||
page.on('requestfailed', request => events.push(`FAIL ${request.url()}`));
|
||||
server.setRedirect('/foo.html', '/empty.html');
|
||||
const FOO_URL = server.PREFIX + '/foo.html';
|
||||
const response = await page.goto(FOO_URL);
|
||||
expect(events).toEqual([
|
||||
`GET ${FOO_URL}`,
|
||||
`302 ${FOO_URL}`,
|
||||
`DONE ${FOO_URL}`,
|
||||
`GET ${server.EMPTY_PAGE}`,
|
||||
`200 ${server.EMPTY_PAGE}`,
|
||||
`DONE ${server.EMPTY_PAGE}`
|
||||
]);
|
||||
|
||||
// Check redirect chain
|
||||
const redirectChain = response.request().redirectChain();
|
||||
expect(redirectChain.length).toBe(1);
|
||||
expect(redirectChain[0].url()).toContain('/foo.html');
|
||||
});
|
||||
});
|
||||
};
|
1458
test/page.spec.js
1458
test/page.spec.js
File diff suppressed because it is too large
Load Diff
@ -21,12 +21,12 @@ const {helper} = require('../lib/helper');
|
||||
const mkdtempAsync = helper.promisify(fs.mkdtemp);
|
||||
const readFileAsync = helper.promisify(fs.readFile);
|
||||
const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-');
|
||||
const FrameUtils = require('./frame-utils');
|
||||
const utils = require('./utils');
|
||||
|
||||
module.exports.addTests = function(runner, expect, defaultBrowserOptions, puppeteer, PROJECT_ROOT) {
|
||||
const {describe, xdescribe, fdescribe} = runner;
|
||||
const {it, fit, xit} = runner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = runner;
|
||||
module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, puppeteer, PROJECT_ROOT}) {
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit} = testRunner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
|
||||
describe('Puppeteer', function() {
|
||||
describe('BrowserFetcher', function() {
|
||||
@ -244,7 +244,7 @@ module.exports.addTests = function(runner, expect, defaultBrowserOptions, puppet
|
||||
const browser = await puppeteer.connect({browserWSEndpoint});
|
||||
const pages = await browser.pages();
|
||||
const restoredPage = pages.find(page => page.url() === server.PREFIX + '/frames/nested-frames.html');
|
||||
expect(FrameUtils.dumpFrames(restoredPage.mainFrame())).toBeGolden('reconnect-nested-frames.txt');
|
||||
expect(utils.dumpFrames(restoredPage.mainFrame())).toBeGolden('reconnect-nested-frames.txt');
|
||||
expect(await restoredPage.evaluate(() => 7 * 8)).toBe(56);
|
||||
await browser.close();
|
||||
});
|
||||
@ -256,19 +256,4 @@ module.exports.addTests = function(runner, expect, defaultBrowserOptions, puppet
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (process.env.COVERAGE) {
|
||||
describe('COVERAGE', function(){
|
||||
const coverage = helper.publicAPICoverage();
|
||||
const disabled = new Set(['page.bringToFront']);
|
||||
if (!defaultBrowserOptions.headless)
|
||||
disabled.add('page.pdf');
|
||||
|
||||
for (const method of coverage.keys()) {
|
||||
(disabled.has(method) ? xit : it)(`public api '${method}' should be called`, async({page, server}) => {
|
||||
expect(coverage.get(method)).toBe(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
37
test/test.js
37
test/test.js
@ -59,7 +59,7 @@ require('events').defaultMaxListeners *= parallel;
|
||||
const timeout = slowMo ? 0 : 10 * 1000;
|
||||
const runner = new TestRunner({timeout, parallel});
|
||||
new Reporter(runner);
|
||||
|
||||
const {beforeAll, beforeEach, afterAll, describe, xit, it} = runner;
|
||||
const {expect} = new Matchers({
|
||||
toBeGolden: GoldenUtils.compare.bind(null, GOLDEN_DIR, OUTPUT_DIR)
|
||||
});
|
||||
@ -69,7 +69,7 @@ if (fs.existsSync(OUTPUT_DIR))
|
||||
|
||||
console.log('Testing on Node', process.version);
|
||||
|
||||
runner.beforeAll(async state => {
|
||||
beforeAll(async state => {
|
||||
const assetsPath = path.join(__dirname, 'assets');
|
||||
const cachedPath = path.join(__dirname, 'assets', 'cached');
|
||||
|
||||
@ -88,12 +88,12 @@ runner.beforeAll(async state => {
|
||||
state.httpsServer.EMPTY_PAGE = `https://localhost:${httpsPort}/empty.html`;
|
||||
});
|
||||
|
||||
runner.beforeEach(async({server, httpsServer}) => {
|
||||
beforeEach(async({server, httpsServer}) => {
|
||||
server.reset();
|
||||
httpsServer.reset();
|
||||
});
|
||||
|
||||
runner.afterAll(async({server, httpsServer}) => {
|
||||
afterAll(async({server, httpsServer}) => {
|
||||
await Promise.all([
|
||||
server.stop(),
|
||||
httpsServer.stop(),
|
||||
@ -108,15 +108,30 @@ const testFiles = [
|
||||
testFiles
|
||||
.map(file => path.join(__dirname, file))
|
||||
.forEach(file =>
|
||||
require(file).addTests(
|
||||
runner,
|
||||
expect,
|
||||
defaultBrowserOptions,
|
||||
puppeteer,
|
||||
PROJECT_ROOT
|
||||
)
|
||||
require(file).addTests({
|
||||
testRunner: runner,
|
||||
expect,
|
||||
defaultBrowserOptions,
|
||||
puppeteer,
|
||||
PROJECT_ROOT
|
||||
})
|
||||
);
|
||||
|
||||
if (process.env.COVERAGE) {
|
||||
describe('COVERAGE', function(){
|
||||
const coverage = helper.publicAPICoverage();
|
||||
const disabled = new Set(['page.bringToFront']);
|
||||
if (!defaultBrowserOptions.headless)
|
||||
disabled.add('page.pdf');
|
||||
|
||||
for (const method of coverage.keys()) {
|
||||
(disabled.has(method) ? xit : it)(`public api '${method}' should be called`, async({page, server}) => {
|
||||
expect(coverage.get(method)).toBe(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (process.env.CI && runner.hasFocusedTestsOrSuites()) {
|
||||
console.error('ERROR: "focused" tests/suites are prohibitted on bots. Remove any "fit"/"fdescribe" declarations.');
|
||||
process.exit(1);
|
||||
|
56
test/tracing.spec.js
Normal file
56
test/tracing.spec.js
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright 2017 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 fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
module.exports.addTests = function({testRunner, expect}) {
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit} = testRunner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
|
||||
describe('Tracing', function() {
|
||||
beforeEach(function(state) {
|
||||
state.outputFile = path.join(__dirname, 'assets', `trace-${state.parallelIndex}.json`);
|
||||
});
|
||||
afterEach(function(state) {
|
||||
fs.unlinkSync(state.outputFile);
|
||||
state.outputFile = null;
|
||||
});
|
||||
it('should output a trace', async({page, server, outputFile}) => {
|
||||
await page.tracing.start({screenshots: true, path: outputFile});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.tracing.stop();
|
||||
expect(fs.existsSync(outputFile)).toBe(true);
|
||||
});
|
||||
it('should run with custom categories if provided', async({page, outputFile}) => {
|
||||
await page.tracing.start({path: outputFile, categories: ['disabled-by-default-v8.cpu_profiler.hires']});
|
||||
await page.tracing.stop();
|
||||
|
||||
const traceJson = JSON.parse(fs.readFileSync(outputFile));
|
||||
expect(traceJson.metadata['trace-config']).toContain('disabled-by-default-v8.cpu_profiler.hires');
|
||||
});
|
||||
it('should throw if tracing on two pages', async({page, server, browser, outputFile}) => {
|
||||
await page.tracing.start({path: outputFile});
|
||||
const newPage = await browser.newPage();
|
||||
let error = null;
|
||||
await newPage.tracing.start({path: outputFile}).catch(e => error = e);
|
||||
await newPage.close();
|
||||
expect(error).toBeTruthy();
|
||||
await page.tracing.stop();
|
||||
});
|
||||
});
|
||||
};
|
@ -72,4 +72,58 @@ const utils = module.exports = {
|
||||
result += '\n' + utils.dumpFrames(child, ' ' + indentation);
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {!EventEmitter} emitter
|
||||
* @param {string} eventName
|
||||
* @param {number=} eventCount
|
||||
* @return {!Promise<!Object>}
|
||||
*/
|
||||
waitForEvents: function(emitter, eventName, eventCount = 1) {
|
||||
let fulfill;
|
||||
const promise = new Promise(x => fulfill = x);
|
||||
emitter.on(eventName, onEvent);
|
||||
return promise;
|
||||
|
||||
function onEvent(event) {
|
||||
--eventCount;
|
||||
if (eventCount)
|
||||
return;
|
||||
emitter.removeListener(eventName, onEvent);
|
||||
fulfill(event);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {!Buffer} pdfBuffer
|
||||
* @return {!Promise<!Array<!Object>>}
|
||||
*/
|
||||
getPDFPages: async function(pdfBuffer) {
|
||||
const PDFJS = require('pdfjs-dist');
|
||||
PDFJS.disableWorker = true;
|
||||
const data = new Uint8Array(pdfBuffer);
|
||||
const doc = await PDFJS.getDocument(data);
|
||||
const pages = [];
|
||||
for (let i = 0; i < doc.numPages; ++i) {
|
||||
const page = await doc.getPage(i + 1);
|
||||
const viewport = page.getViewport(1);
|
||||
// Viewport width and height is in PDF points, which is
|
||||
// 1/72 of an inch.
|
||||
pages.push({
|
||||
width: viewport.width / 72,
|
||||
height: viewport.height / 72,
|
||||
});
|
||||
page.cleanup();
|
||||
}
|
||||
doc.cleanup();
|
||||
return pages;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} px
|
||||
* @return {number}
|
||||
*/
|
||||
cssPixelsToInches: function(px) {
|
||||
return px / 96;
|
||||
},
|
||||
};
|
Loading…
Reference in New Issue
Block a user