chore: migrate tests to TypeScript (#6075)

This CL migrates all the tests to TypeScript. The main benefits of this is that we start consuming our TypeScript definitions and therefore find errors in them. The act of migrating found some bugs in our definitions and now we can be sure to avoid them going forwards.

You'll notice the addition of some `TODO`s in the code; I didn't want this CL to get any bigger than it already is but I intend to follow those up once this lands. It's mostly figuring out how to extend the `expect` types with our `toBeGolden` helpers and some other slight confusions with types that the tests exposed.

Co-authored-by: Mathias Bynens <mathias@qiwi.be>
This commit is contained in:
Jack Franklin 2020-06-23 06:18:46 +01:00 committed by GitHub
parent 2090676a55
commit 28797dee41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 794 additions and 518 deletions

View File

@ -18,8 +18,9 @@ const base = require('./base');
module.exports = {
...base,
require: ['./test/mocha-utils.js'],
spec: 'test/*.spec.js',
require: ['ts-node/register', './test/mocha-utils.ts'],
spec: 'test/*.spec.ts',
extension: ['ts'],
parallel: process.env.CI && !process.env.COVERAGE,
// retry twice more, so we run each test up to 3 times if needed.
retries: process.env.CI ? 2 : 0,

View File

@ -63,7 +63,8 @@
"@microsoft/api-extractor": "7.8.12",
"@types/debug": "0.0.31",
"@types/mime": "^2.0.0",
"@types/node": "^10.17.14",
"@types/mocha": "^7.0.2",
"@types/node": "^14.0.13",
"@types/proxy-from-env": "^1.0.1",
"@types/rimraf": "^2.0.2",
"@types/tar-fs": "^1.16.2",
@ -89,6 +90,7 @@
"prettier": "^2.0.5",
"sinon": "^9.0.2",
"text-diff": "^1.0.1",
"ts-node": "^8.10.2",
"typescript": "3.9.2"
},
"browser": {

View File

@ -310,7 +310,7 @@ export class BrowserContext extends EventEmitter {
waitForTarget(
predicate: (x: Target) => boolean,
options: { timeout?: number }
options: { timeout?: number } = {}
): Promise<Target> {
return this._browser.waitForTarget(
(target) => target.browserContext() === this && predicate(target),

View File

@ -36,10 +36,12 @@ export class Coverage {
this._cssCoverage = new CSSCoverage(client);
}
async startJSCoverage(options: {
async startJSCoverage(
options: {
resetOnNavigation?: boolean;
reportAnonymousScripts?: boolean;
}): Promise<void> {
} = {}
): Promise<void> {
return await this._jsCoverage.start(options);
}
@ -47,9 +49,11 @@ export class Coverage {
return await this._jsCoverage.stop();
}
async startCSSCoverage(options: {
async startCSSCoverage(
options: {
resetOnNavigation?: boolean;
}): Promise<void> {
} = {}
): Promise<void> {
return await this._cssCoverage.start(options);
}

View File

@ -417,10 +417,12 @@ export class Frame {
return await this._frameManager.navigateFrame(this, url, options);
}
async waitForNavigation(options: {
async waitForNavigation(
options: {
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<HTTPResponse | null> {
} = {}
): Promise<HTTPResponse | null> {
return await this._frameManager.waitForFrameNavigation(this, options);
}
@ -523,7 +525,11 @@ export class Frame {
async click(
selector: string,
options: { delay?: number; button?: MouseButtonInput; clickCount?: number }
options: {
delay?: number;
button?: MouseButtonInput;
clickCount?: number;
} = {}
): Promise<void> {
return this._secondaryWorld.click(selector, options);
}
@ -584,7 +590,7 @@ export class Frame {
async waitForSelector(
selector: string,
options: WaitForSelectorOptions
options: WaitForSelectorOptions = {}
): Promise<ElementHandle | null> {
const handle = await this._secondaryWorld.waitForSelector(
selector,
@ -599,7 +605,7 @@ export class Frame {
async waitForXPath(
xpath: string,
options: WaitForSelectorOptions
options: WaitForSelectorOptions = {}
): Promise<ElementHandle | null> {
const handle = await this._secondaryWorld.waitForXPath(xpath, options);
if (!handle) return null;

View File

@ -122,7 +122,7 @@ export class Keyboard {
return !!keyDefinitions[char];
}
async type(text: string, options: { delay?: number }): Promise<void> {
async type(text: string, options: { delay?: number } = {}): Promise<void> {
const delay = (options && options.delay) || null;
for (const char of text) {
if (this.charIsKey(char)) {

View File

@ -430,7 +430,7 @@ export class ElementHandle extends JSHandle {
* uses {@link Page.mouse} to click in the center of the element.
* If the element is detached from DOM, the method throws an error.
*/
async click(options: ClickOptions): Promise<void> {
async click(options: ClickOptions = {}): Promise<void> {
await this._scrollIntoViewIfNeeded();
const { x, y } = await this._clickablePoint();
await this._page.mouse.click(x, y, options);

View File

@ -44,7 +44,7 @@ import Protocol from '../protocol';
const writeFileAsync = helper.promisify(fs.writeFile);
interface Metrics {
export interface Metrics {
Timestamp?: number;
Documents?: number;
Frames?: number;
@ -129,14 +129,13 @@ const paperFormats: Record<string, PaperFormat> = {
a6: { width: 4.13, height: 5.83 },
} as const;
enum VisionDeficiency {
none = 'none',
achromatopsia = 'achromatopsia',
blurredVision = 'blurredVision',
deuteranopia = 'deuteranopia',
protanopia = 'protanopia',
tritanopia = 'tritanopia',
}
type VisionDeficiency =
| 'none'
| 'achromatopsia'
| 'blurredVision'
| 'deuteranopia'
| 'protanopia'
| 'tritanopia';
/**
* All the events that a page instance may emit.
@ -837,7 +836,7 @@ export class Page extends EventEmitter {
return await this._frameManager.mainFrame().content();
}
async setContent(html: string, options: WaitForOptions): Promise<void> {
async setContent(html: string, options: WaitForOptions = {}): Promise<void> {
await this._frameManager.mainFrame().setContent(html, options);
}
@ -913,11 +912,11 @@ export class Page extends EventEmitter {
);
}
async goBack(options: WaitForOptions): Promise<HTTPResponse | null> {
async goBack(options: WaitForOptions = {}): Promise<HTTPResponse | null> {
return this._go(-1, options);
}
async goForward(options: WaitForOptions): Promise<HTTPResponse | null> {
async goForward(options: WaitForOptions = {}): Promise<HTTPResponse | null> {
return this._go(+1, options);
}
@ -1005,7 +1004,14 @@ export class Page extends EventEmitter {
}
async emulateVisionDeficiency(type?: VisionDeficiency): Promise<void> {
const visionDeficiencies = new Set(Object.keys(VisionDeficiency));
const visionDeficiencies = new Set([
'none',
'achromatopsia',
'blurredVision',
'deuteranopia',
'protanopia',
'tritanopia',
]);
try {
assert(
!type || visionDeficiencies.has(type),
@ -1356,7 +1362,7 @@ export class Page extends EventEmitter {
}
waitForFunction(
pageFunction: Function,
pageFunction: Function | string,
options: {
timeout?: number;
polling?: string | number;

View File

@ -134,7 +134,7 @@ export class Puppeteer {
return puppeteerErrors;
}
defaultArgs(options: ChromeArgOptions): string[] {
defaultArgs(options: ChromeArgOptions = {}): string[] {
return this._launcher.defaultArgs(options);
}

View File

@ -31,4 +31,4 @@ const puppeteer = initializePuppeteer({
* And therefore consuming via require('puppeteer') would break / require the user
* to access require('puppeteer').default;
*/
module.exports = puppeteer;
export = puppeteer;

View File

@ -215,7 +215,7 @@ export class BrowserFetcher {
*/
async download(
revision: string,
progressCallback: (x: number, y: number) => void
progressCallback: (x: number, y: number) => void = (): void => {}
): Promise<BrowserFetcherRevisionInfo> {
const url = downloadURL(
this._product,

View File

@ -14,13 +14,14 @@
* limitations under the License.
*/
const { waitEvent } = require('./utils');
const expect = require('expect');
const {
import { waitEvent } from './utils';
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
describeChromeOnly,
} from './mocha-utils';
describeChromeOnly('Target.createCDPSession', function () {
setupTestBrowserHooks();
@ -35,7 +36,7 @@ describeChromeOnly('Target.createCDPSession', function () {
client.send('Runtime.enable'),
client.send('Runtime.evaluate', { expression: 'window.foo = "bar"' }),
]);
const foo = await page.evaluate(() => window.foo);
const foo = await page.evaluate(() => globalThis.foo);
expect(foo).toBe('bar');
});
it('should send events', async () => {
@ -96,6 +97,9 @@ describeChromeOnly('Target.createCDPSession', function () {
expect(error.message).toContain('ThisCommand.DoesNotExist');
async function theSourceOfTheProblems() {
// This fails in TS as it knows that command does not exist but we want to
// have this tests for our users who consume in JS not TS.
// @ts-expect-error
await client.send('ThisCommand.DoesNotExist');
}
});

View File

@ -1,6 +1,22 @@
const { EventEmitter } = require('../lib/common/EventEmitter');
const sinon = require('sinon');
const expect = require('expect');
/**
* Copyright 2020 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.
*/
import { EventEmitter } from '../src/common/EventEmitter';
import sinon from 'sinon';
import expect from 'expect';
describe('EventEmitter', () => {
let emitter;
@ -10,7 +26,7 @@ describe('EventEmitter', () => {
});
describe('on', () => {
const onTests = (methodName) => {
const onTests = (methodName: 'on' | 'addListener'): void => {
it(`${methodName}: adds an event listener that is fired when the event is emitted`, () => {
const listener = sinon.spy();
emitter[methodName]('foo', listener);
@ -39,7 +55,7 @@ describe('EventEmitter', () => {
});
describe('off', () => {
const offTests = (methodName) => {
const offTests = (methodName: 'off' | 'removeListener'): void => {
it(`${methodName}: removes the listener so it is no longer called`, () => {
const listener = sinon.spy();
emitter.on('foo', listener);

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
describeFailsFirefox,
} from './mocha-utils';
describeFailsFirefox('Accessibility', function () {
setupTestBrowserHooks();

View File

@ -7,8 +7,8 @@
<textarea></textarea>
<script src='mouse-helper.js'></script>
<script>
window.result = '';
let textarea = document.querySelector('textarea');
globalThis.result = '';
globalThis.textarea = document.querySelector('textarea');
textarea.addEventListener('input', () => result = textarea.value, false);
</script>
</body>

View File

@ -1,8 +1,8 @@
<script>
let h1 = null;
let button = null;
let clicked = false;
window.button = null;
window.clicked = false;
window.addEventListener('DOMContentLoaded', () => {
const shadowRoot = document.body.attachShadow({mode: 'open'});

View File

@ -14,8 +14,8 @@
* limitations under the License.
*/
const expect = require('expect');
const { getTestState, setupTestBrowserHooks } = require('./mocha-utils');
import expect from 'expect';
import { getTestState, setupTestBrowserHooks } from './mocha-utils';
describe('Browser specs', function () {
setupTestBrowserHooks();

View File

@ -14,9 +14,13 @@
* limitations under the License.
*/
const expect = require('expect');
const { getTestState, setupTestBrowserHooks } = require('./mocha-utils');
const utils = require('./utils');
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
itFailsFirefox,
} from './mocha-utils';
import utils from './utils';
describe('BrowserContext', function () {
setupTestBrowserHooks();

View File

@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
describeChromeOnly,
} from './mocha-utils';
describeChromeOnly('Chromium-Specific Launcher tests', function () {
describe('Puppeteer.launch |browserURL| option', function () {

View File

@ -14,13 +14,14 @@
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestPageAndContextHooks,
setupTestBrowserHooks,
} = require('./mocha-utils');
const utils = require('./utils');
itFailsFirefox,
} from './mocha-utils';
import utils from './utils';
describe('Page.click', function () {
setupTestBrowserHooks();
@ -30,7 +31,7 @@ describe('Page.click', function () {
await page.goto(server.PREFIX + '/input/button.html');
await page.click('button');
expect(await page.evaluate(() => result)).toBe('Clicked');
expect(await page.evaluate(() => globalThis.result)).toBe('Clicked');
});
it('should click svg', async () => {
const { page } = getTestState();
@ -41,7 +42,7 @@ describe('Page.click', function () {
</svg>
`);
await page.click('circle');
expect(await page.evaluate(() => window.__CLICKED)).toBe(42);
expect(await page.evaluate(() => globalThis.__CLICKED)).toBe(42);
});
itFailsFirefox(
'should click the button if window.Node is removed',
@ -51,7 +52,7 @@ describe('Page.click', function () {
await page.goto(server.PREFIX + '/input/button.html');
await page.evaluate(() => delete window.Node);
await page.click('button');
expect(await page.evaluate(() => result)).toBe('Clicked');
expect(await page.evaluate(() => globalThis.result)).toBe('Clicked');
}
);
// @see https://github.com/puppeteer/puppeteer/issues/4281
@ -67,7 +68,7 @@ describe('Page.click', function () {
<span onclick='javascript:window.CLICKED=42'></span>
`);
await page.click('span');
expect(await page.evaluate(() => window.CLICKED)).toBe(42);
expect(await page.evaluate(() => globalThis.CLICKED)).toBe(42);
});
it('should not throw UnhandledPromiseRejection when page closes', async () => {
const { page } = getTestState();
@ -76,7 +77,7 @@ describe('Page.click', function () {
await Promise.all([
newPage.close(),
newPage.mouse.click(1, 2),
]).catch((error) => {});
]).catch(() => {});
});
it('should click the button after navigation ', async () => {
const { page, server } = getTestState();
@ -85,7 +86,7 @@ describe('Page.click', function () {
await page.click('button');
await page.goto(server.PREFIX + '/input/button.html');
await page.click('button');
expect(await page.evaluate(() => result)).toBe('Clicked');
expect(await page.evaluate(() => globalThis.result)).toBe('Clicked');
});
itFailsFirefox('should click with disabled javascript', async () => {
const { page, server } = getTestState();
@ -108,7 +109,7 @@ describe('Page.click', function () {
<span onclick='javascript:window.CLICKED = 42;'><i>woof</i><b>doggo</b></span>
`);
await page.click('span');
expect(await page.evaluate(() => window.CLICKED)).toBe(42);
expect(await page.evaluate(() => globalThis.CLICKED)).toBe(42);
});
it('should select the text by triple clicking', async () => {
const { page, server } = getTestState();
@ -162,17 +163,17 @@ describe('Page.click', function () {
await page.goto(server.PREFIX + '/wrappedlink.html');
await page.click('a');
expect(await page.evaluate(() => window.__clicked)).toBe(true);
expect(await page.evaluate(() => globalThis.__clicked)).toBe(true);
});
it('should click on checkbox input and toggle', async () => {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/input/checkbox.html');
expect(await page.evaluate(() => result.check)).toBe(null);
expect(await page.evaluate(() => globalThis.result.check)).toBe(null);
await page.click('input#agree');
expect(await page.evaluate(() => result.check)).toBe(true);
expect(await page.evaluate(() => result.events)).toEqual([
expect(await page.evaluate(() => globalThis.result.check)).toBe(true);
expect(await page.evaluate(() => globalThis.result.events)).toEqual([
'mouseover',
'mouseenter',
'mousemove',
@ -183,23 +184,23 @@ describe('Page.click', function () {
'change',
]);
await page.click('input#agree');
expect(await page.evaluate(() => result.check)).toBe(false);
expect(await page.evaluate(() => globalThis.result.check)).toBe(false);
});
itFailsFirefox('should click on checkbox label and toggle', async () => {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/input/checkbox.html');
expect(await page.evaluate(() => result.check)).toBe(null);
expect(await page.evaluate(() => globalThis.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([
expect(await page.evaluate(() => globalThis.result.check)).toBe(true);
expect(await page.evaluate(() => globalThis.result.events)).toEqual([
'click',
'input',
'change',
]);
await page.click('label[for="agree"]');
expect(await page.evaluate(() => result.check)).toBe(false);
expect(await page.evaluate(() => globalThis.result.check)).toBe(false);
});
it('should fail to click a missing button', async () => {
@ -243,10 +244,10 @@ describe('Page.click', function () {
await page.goto(server.PREFIX + '/input/button.html');
await page.evaluate(() => {
window.double = false;
globalThis.double = false;
const button = document.querySelector('button');
button.addEventListener('dblclick', (event) => {
window.double = true;
button.addEventListener('dblclick', () => {
globalThis.double = true;
});
});
const button = await page.$('button');
@ -265,14 +266,14 @@ describe('Page.click', function () {
button.style.left = '368px';
});
await page.click('button');
expect(await page.evaluate(() => window.result)).toBe('Clicked');
expect(await page.evaluate(() => globalThis.result)).toBe('Clicked');
});
it('should click a rotated button', async () => {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/input/rotatedButton.html');
await page.click('button');
expect(await page.evaluate(() => result)).toBe('Clicked');
expect(await page.evaluate(() => globalThis.result)).toBe('Clicked');
});
it('should fire contextmenu event on right click', async () => {
const { page, server } = getTestState();
@ -304,7 +305,7 @@ describe('Page.click', function () {
const frame = page.frames()[1];
const button = await frame.$('button');
await button.click();
expect(await frame.evaluate(() => window.result)).toBe('Clicked');
expect(await frame.evaluate(() => globalThis.result)).toBe('Clicked');
});
// @see https://github.com/puppeteer/puppeteer/issues/4110
xit('should click the button with fixed position inside an iframe', async () => {
@ -325,7 +326,7 @@ describe('Page.click', function () {
button.style.setProperty('position', 'fixed')
);
await frame.click('button');
expect(await frame.evaluate(() => window.result)).toBe('Clicked');
expect(await frame.evaluate(() => globalThis.result)).toBe('Clicked');
});
itFailsFirefox(
'should click the button with deviceScaleFactor set',
@ -345,7 +346,7 @@ describe('Page.click', function () {
const frame = page.frames()[1];
const button = await frame.$('button');
await button.click();
expect(await frame.evaluate(() => window.result)).toBe('Clicked');
expect(await frame.evaluate(() => globalThis.result)).toBe('Clicked');
}
);
});

View File

@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
} from './mocha-utils';
describe('Cookie specs', () => {
setupTestBrowserHooks();

View File

@ -14,6 +14,9 @@
* limitations under the License.
*/
// TODO (@jackfranklin): convert this to TypeScript and enable type-checking
// @ts-nocheck
/* We want to ensure that all of Puppeteer's public API is tested via our unit
* tests but we can't use a tool like Istanbul because the way it instruments
* code unfortunately breaks in Puppeteer where some of that code is then being

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestPageAndContextHooks,
setupTestBrowserHooks,
} = require('./mocha-utils');
describeChromeOnly,
} from './mocha-utils';
describe('Coverage specs', function () {
describeChromeOnly('JSCoverage', function () {
@ -122,6 +123,8 @@ describe('Coverage specs', function () {
const coverage = await page.coverage.stopJSCoverage();
expect(
JSON.stringify(coverage, null, 2).replace(/:\d{4}\//g, ':<PORT>/')
// TODO (@jackfranklin) extend the Expect typedefs to fix this
// @ts-expect-error toBeGolden matcher
).toBeGolden('jscoverage-involved.txt');
});
describe('resetOnNavigation', function () {
@ -224,6 +227,8 @@ describe('Coverage specs', function () {
const coverage = await page.coverage.stopCSSCoverage();
expect(
JSON.stringify(coverage, null, 2).replace(/:\d{4}\//g, ':<PORT>/')
// TODO (@jackfranklin) extend the Expect typedefs to fix this
// @ts-expect-error toBeGolden matcher
).toBeGolden('csscoverage-involved.txt');
});
it('should ignore injected stylesheets', async () => {

View File

@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
} from './mocha-utils';
describe('DefaultBrowserContext', function () {
setupTestBrowserHooks();

View File

@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const expect = require('expect');
const sinon = require('sinon');
import expect from 'expect';
import sinon from 'sinon';
const {
import {
getTestState,
setupTestPageAndContextHooks,
setupTestBrowserHooks,
} = require('./mocha-utils');
itFailsFirefox,
} from './mocha-utils';
describe('Page.Events.Dialog', function () {
setupTestBrowserHooks();

View File

@ -14,14 +14,17 @@
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
describeFailsFirefox,
itFailsFirefox,
} from './mocha-utils';
const utils = require('./utils');
import utils from './utils';
import { ElementHandle } from '../src/common/JSHandle';
describe('ElementHandle specs', function () {
setupTestBrowserHooks();
@ -98,12 +101,10 @@ describe('ElementHandle specs', function () {
// Step 1: Add Frame and position it absolutely.
await utils.attachFrame(page, 'frame1', server.PREFIX + '/resetcss.html');
await page.evaluate(() => {
const frame = document.querySelector('#frame1');
frame.style = `
position: absolute;
left: 1px;
top: 2px;
`;
const frame = document.querySelector<HTMLElement>('#frame1');
frame.style.position = 'absolute';
frame.style.left = '1px';
frame.style.top = '2px';
});
// Step 2: Add div and position it absolutely inside frame.
@ -112,17 +113,15 @@ describe('ElementHandle specs', function () {
await frame.evaluateHandle(() => {
const div = document.createElement('div');
document.body.appendChild(div);
div.style = `
box-sizing: border-box;
position: absolute;
border-left: 1px solid black;
padding-left: 2px;
margin-left: 3px;
left: 4px;
top: 5px;
width: 6px;
height: 7px;
`;
div.style.boxSizing = 'border-box';
div.style.position = 'absolute';
div.style.borderLeft = '1px solid black';
div.style.paddingLeft = '2px';
div.style.marginLeft = '3px';
div.style.left = '4px';
div.style.top = '5px';
div.style.width = '6px';
div.style.height = '7px';
return div;
})
).asElement();
@ -177,15 +176,29 @@ describe('ElementHandle specs', function () {
await page.goto(server.PREFIX + '/input/button.html');
const button = await page.$('button');
await button.click();
expect(await page.evaluate(() => result)).toBe('Clicked');
expect(await page.evaluate(() => globalThis.result)).toBe('Clicked');
});
it('should work for Shadow DOM v1', async () => {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/shadow.html');
const buttonHandle = await page.evaluateHandle(() => button);
await buttonHandle.click();
expect(await page.evaluate(() => clicked)).toBe(true);
const buttonHandle = await page.evaluateHandle(
// @ts-expect-error button is expected to be in the page's scope.
() => button
);
// TODO (@jackfranklin): TS types are off here. evaluateHandle returns a
// JSHandle but that doesn't have a click() method. In this case it seems
// to return an ElementHandle. I'm not sure if the tests are wrong here
// and should use evaluate<ElementHandle> or if the type of evaluateHandle
// should change to enable the user to tell us they are expecting an
// ElementHandle rather than the default JSHandle.
await (buttonHandle as ElementHandle).click();
expect(
await page.evaluate(
// @ts-expect-error clicked is expected to be in the page's scope.
() => clicked
)
).toBe(true);
});
it('should work for TextNodes', async () => {
const { page, server } = getTestState();
@ -195,6 +208,7 @@ describe('ElementHandle specs', function () {
() => document.querySelector('button').firstChild
);
let error = null;
// @ts-expect-error
await buttonTextNode.click().catch((error_) => (error = error_));
expect(error.message).toBe('Node is not of type HTMLElement');
});
@ -293,7 +307,7 @@ describe('ElementHandle specs', function () {
puppeteer.__experimental_unregisterCustomQueryHandler('getById');
try {
await page.$('getById/foo');
expect.fail('Custom query handler not set - throw expected');
throw new Error('Custom query handler name not set - throw expected');
} catch (error) {
expect(error).toStrictEqual(
new Error(
@ -307,9 +321,12 @@ describe('ElementHandle specs', function () {
const { puppeteer } = getTestState();
puppeteer.__experimental_registerCustomQueryHandler(
'1/2/3',
(element, selector) => {}
// @ts-expect-error
() => {}
);
throw new Error(
'Custom query handler name was invalid - throw expected'
);
expect.fail('Custom query handler name was invalid - throw expected');
} catch (error) {
expect(error).toStrictEqual(
new Error('Custom query handler names may only contain [a-zA-Z]')

View File

@ -14,12 +14,14 @@
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
describeFailsFirefox,
} from './mocha-utils';
describe('Emulation', () => {
setupTestBrowserHooks();
@ -95,7 +97,9 @@ describe('Emulation', () => {
await page.setViewport({ width: 800, height: 600, hasTouch: true });
await page.addScriptTag({ url: server.PREFIX + '/modernizr.js' });
expect(await page.evaluate(() => Modernizr.touchevents)).toBe(true);
expect(
await page.evaluate(() => globalThis.Modernizr.touchevents)
).toBe(true);
}
);
itFailsFirefox('should support landscape emulation', async () => {
@ -138,7 +142,7 @@ describe('Emulation', () => {
button
);
await button.click();
expect(await page.evaluate(() => result)).toBe('Clicked');
expect(await page.evaluate(() => globalThis.result)).toBe('Clicked');
});
});
@ -162,11 +166,13 @@ describe('Emulation', () => {
expect(await page.evaluate(() => matchMedia('print').matches)).toBe(
false
);
// @ts-expect-error this method is deprecated so we don't declare it
await page.emulateMedia('print');
expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(
false
);
expect(await page.evaluate(() => matchMedia('print').matches)).toBe(true);
// @ts-expect-error this method is deprecated so we don't declare it
await page.emulateMedia(null);
expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(
true
@ -179,6 +185,7 @@ describe('Emulation', () => {
const { page } = getTestState();
let error = null;
// @ts-expect-error this method is deprecated so we don't declare it
await page.emulateMedia('bad').catch((error_) => (error = error_));
expect(error.message).toBe('Unsupported media type: bad');
});
@ -306,22 +313,22 @@ describe('Emulation', () => {
globalThis.date = new Date(1479579154987);
});
await page.emulateTimezone('America/Jamaica');
expect(await page.evaluate(() => date.toString())).toBe(
expect(await page.evaluate(() => globalThis.date.toString())).toBe(
'Sat Nov 19 2016 13:12:34 GMT-0500 (Eastern Standard Time)'
);
await page.emulateTimezone('Pacific/Honolulu');
expect(await page.evaluate(() => date.toString())).toBe(
expect(await page.evaluate(() => globalThis.date.toString())).toBe(
'Sat Nov 19 2016 08:12:34 GMT-1000 (Hawaii-Aleutian Standard Time)'
);
await page.emulateTimezone('America/Buenos_Aires');
expect(await page.evaluate(() => date.toString())).toBe(
expect(await page.evaluate(() => globalThis.date.toString())).toBe(
'Sat Nov 19 2016 15:12:34 GMT-0300 (Argentina Standard Time)'
);
await page.emulateTimezone('Europe/Berlin');
expect(await page.evaluate(() => date.toString())).toBe(
expect(await page.evaluate(() => globalThis.date.toString())).toBe(
'Sat Nov 19 2016 19:12:34 GMT+0100 (Central European Standard Time)'
);
});
@ -347,42 +354,49 @@ describe('Emulation', () => {
{
await page.emulateVisionDeficiency('none');
const screenshot = await page.screenshot();
// @ts-expect-error TODO (@jackfranklin) toBeGolden needs declaring
expect(screenshot).toBeGolden('screenshot-sanity.png');
}
{
await page.emulateVisionDeficiency('achromatopsia');
const screenshot = await page.screenshot();
// @ts-expect-error TODO (@jackfranklin) toBeGolden needs declaring
expect(screenshot).toBeGolden('vision-deficiency-achromatopsia.png');
}
{
await page.emulateVisionDeficiency('blurredVision');
const screenshot = await page.screenshot();
// @ts-expect-error TODO (@jackfranklin) toBeGolden needs declaring
expect(screenshot).toBeGolden('vision-deficiency-blurredVision.png');
}
{
await page.emulateVisionDeficiency('deuteranopia');
const screenshot = await page.screenshot();
// @ts-expect-error TODO (@jackfranklin) toBeGolden needs declaring
expect(screenshot).toBeGolden('vision-deficiency-deuteranopia.png');
}
{
await page.emulateVisionDeficiency('protanopia');
const screenshot = await page.screenshot();
// @ts-expect-error TODO (@jackfranklin) toBeGolden needs declaring
expect(screenshot).toBeGolden('vision-deficiency-protanopia.png');
}
{
await page.emulateVisionDeficiency('tritanopia');
const screenshot = await page.screenshot();
// @ts-expect-error TODO (@jackfranklin) toBeGolden needs declaring
expect(screenshot).toBeGolden('vision-deficiency-tritanopia.png');
}
{
await page.emulateVisionDeficiency('none');
const screenshot = await page.screenshot();
// @ts-expect-error TODO (@jackfranklin) toBeGolden needs declaring
expect(screenshot).toBeGolden('screenshot-sanity.png');
}
});
@ -392,6 +406,7 @@ describe('Emulation', () => {
let error = null;
await page
// @ts-expect-error deliberately passign invalid deficiency
.emulateVisionDeficiency('invalid')
.catch((error_) => (error = error_));
expect(error.message).toBe('Unsupported vision deficiency: invalid');

View File

@ -14,13 +14,15 @@
* limitations under the License.
*/
const utils = require('./utils');
const expect = require('expect');
const {
import utils from './utils';
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
describeFailsFirefox,
} from './mocha-utils';
const bigint = typeof BigInt !== 'undefined';
@ -80,7 +82,7 @@ describe('Evaluation specs', function () {
it('should modify global environment', async () => {
const { page } = getTestState();
await page.evaluate(() => (window.globalVar = 123));
await page.evaluate(() => (globalThis.globalVar = 123));
expect(await page.evaluate('globalVar')).toBe(123);
});
it('should evaluate in the page context', async () => {
@ -156,7 +158,7 @@ describe('Evaluation specs', function () {
return await page.evaluate((a, b) => a * b, a, b);
});
const result = await page.evaluate(async function () {
return await callController(9, 3);
return await globalThis.callController(9, 3);
});
expect(result).toBe(27);
});
@ -165,10 +167,11 @@ describe('Evaluation specs', function () {
let error = null;
await page
.evaluate(() => not_existing_object.property)
// @ts-expect-error we know the object doesn't exist
.evaluate(() => notExistingObject.property)
.catch((error_) => (error = error_));
expect(error).toBeTruthy();
expect(error.message).toContain('not_existing_object');
expect(error.message).toContain('notExistingObject');
});
it('should support thrown strings as error messages', async () => {
const { page } = getTestState();
@ -259,7 +262,7 @@ describe('Evaluation specs', function () {
const { page } = getTestState();
const result = await page.evaluate(() => {
const a = {};
const a: { [x: string]: any } = {};
const b = { a };
a.b = b;
return a;
@ -274,7 +277,7 @@ describe('Evaluation specs', function () {
.jsonValue()
.catch((error_) => error_.message);
const error = await page
.evaluate((errorText) => {
.evaluate<Error>((errorText) => {
throw new Error(errorText);
}, errorText)
.catch((error_) => error_);
@ -358,7 +361,7 @@ describe('Evaluation specs', function () {
const error = await executionContext
.evaluate(() => null)
.catch((error_) => error_);
expect(error.message).toContain('navigation');
expect((error as Error).message).toContain('navigation');
});
itFailsFirefox(
'should not throw an error when evaluation does a navigation',
@ -367,7 +370,7 @@ describe('Evaluation specs', function () {
await page.goto(server.PREFIX + '/one-style.html');
const result = await page.evaluate(() => {
window.location = '/empty.html';
(window as any).location = '/empty.html';
return [42];
});
expect(result).toEqual([42]);
@ -376,7 +379,7 @@ describe('Evaluation specs', function () {
it('should transfer 100Mb of data from page to node.js', async function () {
const { page } = getTestState();
const a = await page.evaluate(() =>
const a = await page.evaluate<any[]>(() =>
Array(100 * 1024 * 1024 + 1).join('a')
);
expect(a.length).toBe(100 * 1024 * 1024);
@ -402,26 +405,26 @@ describe('Evaluation specs', function () {
const { page, server } = getTestState();
await page.evaluateOnNewDocument(function () {
window.injected = 123;
globalThis.injected = 123;
});
await page.goto(server.PREFIX + '/tamperable.html');
expect(await page.evaluate(() => window.result)).toBe(123);
expect(await page.evaluate(() => globalThis.result)).toBe(123);
});
it('should work with CSP', async () => {
const { page, server } = getTestState();
server.setCSP('/empty.html', 'script-src ' + server.PREFIX);
await page.evaluateOnNewDocument(function () {
window.injected = 123;
globalThis.injected = 123;
});
await page.goto(server.PREFIX + '/empty.html');
expect(await page.evaluate(() => window.injected)).toBe(123);
expect(await page.evaluate(() => globalThis.injected)).toBe(123);
// Make sure CSP works.
await page
.addScriptTag({ content: 'window.e = 10;' })
.catch((error) => void error);
expect(await page.evaluate(() => window.e)).toBe(undefined);
expect(await page.evaluate(() => (window as any).e)).toBe(undefined);
});
});
@ -432,10 +435,10 @@ describe('Evaluation specs', function () {
await page.goto(server.EMPTY_PAGE);
await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE);
expect(page.frames().length).toBe(2);
await page.frames()[0].evaluate(() => (window.FOO = 'foo'));
await page.frames()[1].evaluate(() => (window.FOO = 'bar'));
expect(await page.frames()[0].evaluate(() => window.FOO)).toBe('foo');
expect(await page.frames()[1].evaluate(() => window.FOO)).toBe('bar');
await page.frames()[0].evaluate(() => (globalThis.FOO = 'foo'));
await page.frames()[1].evaluate(() => (globalThis.FOO = 'bar'));
expect(await page.frames()[0].evaluate(() => globalThis.FOO)).toBe('foo');
expect(await page.frames()[1].evaluate(() => globalThis.FOO)).toBe('bar');
});
itFailsFirefox('should have correct execution contexts', async () => {
const { page, server } = getTestState();

View File

@ -14,10 +14,12 @@
* limitations under the License.
*/
const expect = require('expect');
const { getTestState } = require('./mocha-utils');
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
import expect from 'expect';
import { getTestState, itChromeOnly } from './mocha-utils';
import path from 'path';
describe('Fixtures', function () {
itChromeOnly('dumpio option should work with pipe option ', async () => {
@ -67,7 +69,9 @@ describe('Fixtures', function () {
JSON.stringify(options),
]);
let wsEndPointCallback;
const wsEndPointPromise = new Promise((x) => (wsEndPointCallback = x));
const wsEndPointPromise = new Promise<string>(
(x) => (wsEndPointCallback = x)
);
let output = '';
res.stdout.on('data', (data) => {
output += data;

View File

@ -14,13 +14,14 @@
* limitations under the License.
*/
const utils = require('./utils');
const expect = require('expect');
const {
import utils from './utils';
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
} from './mocha-utils';
describe('Frame specs', function () {
setupTestBrowserHooks();
@ -43,12 +44,12 @@ describe('Frame specs', function () {
expect(context2.frame()).toBe(frame2);
await Promise.all([
context1.evaluate(() => (window.a = 1)),
context2.evaluate(() => (window.a = 2)),
context1.evaluate(() => (globalThis.a = 1)),
context2.evaluate(() => (globalThis.a = 2)),
]);
const [a1, a2] = await Promise.all([
context1.evaluate(() => window.a),
context2.evaluate(() => window.a),
context1.evaluate(() => globalThis.a),
context2.evaluate(() => globalThis.a),
]);
expect(a1).toBe(1);
expect(a2).toBe(2);
@ -146,8 +147,8 @@ describe('Frame specs', function () {
const { page, server } = getTestState();
let hasEvents = false;
page.on('frameattached', (frame) => (hasEvents = true));
page.on('framedetached', (frame) => (hasEvents = true));
page.on('frameattached', () => (hasEvents = true));
page.on('framedetached', () => (hasEvents = true));
await page.goto(server.EMPTY_PAGE);
expect(hasEvents).toBe(false);
});
@ -243,13 +244,13 @@ describe('Frame specs', function () {
server.EMPTY_PAGE
);
await page.evaluate(() => {
window.frame = document.querySelector('#frame1');
window.frame.remove();
globalThis.frame = document.querySelector('#frame1');
globalThis.frame.remove();
});
expect(frame1.isDetached()).toBe(true);
const [frame2] = await Promise.all([
utils.waitEvent(page, 'frameattached'),
page.evaluate(() => document.body.appendChild(window.frame)),
page.evaluate(() => document.body.appendChild(globalThis.frame)),
]);
expect(frame2.isDetached()).toBe(false);
expect(frame1).not.toBe(frame2);

View File

@ -1,3 +1,4 @@
// @ts-nocheck
/**
* Copyright 2017 Google Inc. All rights reserved.
*

View File

@ -14,15 +14,19 @@
* limitations under the License.
*/
const path = require('path');
const os = require('os');
const fs = require('fs');
const { promisify } = require('util');
const { waitEvent } = require('./utils');
const expect = require('expect');
const { getTestState } = require('./mocha-utils');
import path from 'path';
import os from 'os';
import fs from 'fs';
import { promisify } from 'util';
import expect from 'expect';
import {
getTestState,
describeChromeOnly,
itFailsWindowsUntilDate,
} from './mocha-utils';
import rimraf from 'rimraf';
const rmAsync = promisify(require('rimraf'));
const rmAsync = promisify(rimraf);
const mkdtempAsync = promisify(fs.mkdtemp);
const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-');
@ -77,7 +81,7 @@ describeChromeOnly('headful tests', function () {
);
const page = await backgroundPageTarget.page();
expect(await page.evaluate(() => 2 * 3)).toBe(6);
expect(await page.evaluate(() => window.MAGIC)).toBe(42);
expect(await page.evaluate(() => globalThis.MAGIC)).toBe(42);
await browserWithExtension.close();
});
it('should have default url when launching browser', async function () {
@ -120,13 +124,13 @@ describeChromeOnly('headful tests', function () {
const cookie = await headlessPage.evaluate(() => document.cookie);
await headlessBrowser.close();
// This might throw. See https://github.com/puppeteer/puppeteer/issues/2778
await rmAsync(userDataDir).catch((error) => {});
await rmAsync(userDataDir).catch(() => {});
expect(cookie).toBe('foo=true');
}
);
// TODO: Support OOOPIF. @see https://github.com/puppeteer/puppeteer/issues/2548
xit('OOPIF: should report google.com frame', async () => {
const { server } = getTestState();
const { server, puppeteer } = getTestState();
// https://google.com is isolated by default in Chromium embedder.
const browser = await puppeteer.launch(headfulOptions);

View File

@ -14,8 +14,12 @@
* limitations under the License.
*/
const expect = require('expect');
const { getTestState } = require('./mocha-utils');
import expect from 'expect';
import {
getTestState,
describeFailsFirefox,
itFailsFirefox,
} from './mocha-utils';
describe('ignoreHTTPSErrors', function () {
/* Note that this test creates its own browser rather than use

View File

@ -14,13 +14,14 @@
* limitations under the License.
*/
const path = require('path');
const expect = require('expect');
const {
import path from 'path';
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
describeFailsFirefox,
} from './mocha-utils';
const FILE_TO_UPLOAD = path.join(__dirname, '/assets/file-to-upload.txt');
@ -36,9 +37,13 @@ describe('input tests', function () {
const filePath = path.relative(process.cwd(), FILE_TO_UPLOAD);
const input = await page.$('input');
await page.evaluate((e) => {
window._inputEvents = [];
e.addEventListener('change', (ev) => window._inputEvents.push(ev.type));
e.addEventListener('input', (ev) => window._inputEvents.push(ev.type));
globalThis._inputEvents = [];
e.addEventListener('change', (ev) =>
globalThis._inputEvents.push(ev.type)
);
e.addEventListener('input', (ev) =>
globalThis._inputEvents.push(ev.type)
);
}, input);
await input.uploadFile(filePath);
expect(await page.evaluate((e) => e.files[0].name, input)).toBe(
@ -47,7 +52,7 @@ describe('input tests', function () {
expect(await page.evaluate((e) => e.files[0].type, input)).toBe(
'text/plain'
);
expect(await page.evaluate(() => window._inputEvents)).toEqual([
expect(await page.evaluate(() => globalThis._inputEvents)).toEqual([
'input',
'change',
]);

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
} from './mocha-utils';
describe('JSHandle', function () {
setupTestBrowserHooks();
@ -70,7 +71,7 @@ describe('JSHandle', function () {
const { page } = getTestState();
const aHandle = await page.evaluateHandle(() => {
window.FOO = 123;
globalThis.FOO = 123;
return window;
});
expect(await page.evaluate((e) => e.FOO, aHandle)).toBe(123);
@ -79,7 +80,7 @@ describe('JSHandle', function () {
const { page } = getTestState();
const aHandle = await page.evaluateHandle(() => {
window.FOO = 123;
globalThis.FOO = 123;
return window;
});
expect(await page.evaluate((e) => e.FOO, aHandle)).toBe(123);
@ -146,11 +147,13 @@ describe('JSHandle', function () {
const aHandle = await page.evaluateHandle(() => {
class A {
a: string;
constructor() {
this.a = '1';
}
}
class B extends A {
b: string;
constructor() {
super();
this.b = '2';
@ -189,17 +192,15 @@ describe('JSHandle', function () {
const element = aHandle.asElement();
expect(element).toBeTruthy();
expect(
await page.evaluate(
(e) => e.nodeType === HTMLElement.TEXT_NODE,
element
)
await page.evaluate((e) => e.nodeType === Node.TEXT_NODE, element)
);
});
it('should work with nullified Node', async () => {
const { page } = getTestState();
await page.setContent('<section>test</section>');
await page.evaluate(() => delete Node);
// TODO (@jackfranklin): this line doesn't do anything. What was intended here?
// await page.evaluate(() => delete Node);
const handle = await page.evaluateHandle(() =>
document.querySelector('section')
);

View File

@ -14,14 +14,16 @@
* limitations under the License.
*/
const utils = require('./utils');
const os = require('os');
const expect = require('expect');
const {
import utils from './utils';
import os from 'os';
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
} from './mocha-utils';
import { KeyInput } from '../src/common/USKeyboardLayout';
describe('Keyboard', function () {
setupTestBrowserHooks();
@ -45,7 +47,7 @@ describe('Keyboard', function () {
const { page, isFirefox } = getTestState();
await page.evaluate(() => {
window.keyPromise = new Promise((resolve) =>
(window as any).keyPromise = new Promise((resolve) =>
document.addEventListener('keydown', (event) => resolve(event.key))
);
});
@ -130,16 +132,20 @@ describe('Keyboard', function () {
await page.goto(server.PREFIX + '/input/keyboard.html');
const keyboard = page.keyboard;
const codeForKey = { Shift: 16, Alt: 18, Control: 17 };
for (const modifierKey in codeForKey) {
const codeForKey = new Map<KeyInput, number>([
['Shift', 16],
['Alt', 18],
['Control', 17],
]);
for (const [modifierKey, modifierCode] of codeForKey) {
await keyboard.down(modifierKey);
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keydown: ' +
modifierKey +
' ' +
modifierKey +
'Left ' +
codeForKey[modifierKey] +
modifierCode +
' [' +
modifierKey +
']'
@ -147,7 +153,7 @@ describe('Keyboard', function () {
await keyboard.down('!');
// Shift+! will generate a keypress
if (modifierKey === 'Shift')
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keydown: ! Digit1 49 [' +
modifierKey +
']\nKeypress: ! Digit1 33 33 [' +
@ -155,22 +161,22 @@ describe('Keyboard', function () {
']'
);
else
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keydown: ! Digit1 49 [' + modifierKey + ']'
);
await keyboard.up('!');
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keyup: ! Digit1 49 [' + modifierKey + ']'
);
await keyboard.up(modifierKey);
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keyup: ' +
modifierKey +
' ' +
modifierKey +
'Left ' +
codeForKey[modifierKey] +
modifierCode +
' []'
);
}
@ -181,27 +187,27 @@ describe('Keyboard', function () {
await page.goto(server.PREFIX + '/input/keyboard.html');
const keyboard = page.keyboard;
await keyboard.down('Control');
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keydown: Control ControlLeft 17 [Control]'
);
await keyboard.down('Alt');
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keydown: Alt AltLeft 18 [Alt Control]'
);
await keyboard.down(';');
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keydown: ; Semicolon 186 [Alt Control]'
);
await keyboard.up(';');
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keyup: ; Semicolon 186 [Alt Control]'
);
await keyboard.up('Control');
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keyup: Control ControlLeft 17 [Alt]'
);
await keyboard.up('Alt');
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
'Keyup: Alt AltLeft 18 []'
);
});
@ -210,7 +216,7 @@ describe('Keyboard', function () {
await page.goto(server.PREFIX + '/input/keyboard.html');
await page.keyboard.type('!');
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
[
'Keydown: ! Digit1 49 []',
'Keypress: ! Digit1 33 33 []',
@ -218,7 +224,7 @@ describe('Keyboard', function () {
].join('\n')
);
await page.keyboard.type('^');
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
[
'Keydown: ^ Digit6 54 []',
'Keypress: ^ Digit6 94 94 []',
@ -233,7 +239,7 @@ describe('Keyboard', function () {
const keyboard = page.keyboard;
await keyboard.down('Shift');
await page.keyboard.type('~');
expect(await page.evaluate(() => getResult())).toBe(
expect(await page.evaluate(() => globalThis.getResult())).toBe(
[
'Keydown: Shift ShiftLeft 16 [Shift]',
'Keydown: ~ Backquote 192 [Shift]', // 192 is ` keyCode
@ -261,7 +267,9 @@ describe('Keyboard', function () {
);
});
await page.keyboard.type('Hello World!');
expect(await page.evaluate(() => textarea.value)).toBe('He Wrd!');
expect(await page.evaluate(() => globalThis.textarea.value)).toBe(
'He Wrd!'
);
});
itFailsFirefox('should specify repeat property', async () => {
const { page, server } = getTestState();
@ -271,21 +279,21 @@ describe('Keyboard', function () {
await page.evaluate(() =>
document
.querySelector('textarea')
.addEventListener('keydown', (e) => (window.lastEvent = e), true)
.addEventListener('keydown', (e) => (globalThis.lastEvent = e), true)
);
await page.keyboard.down('a');
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(false);
expect(await page.evaluate(() => globalThis.lastEvent.repeat)).toBe(false);
await page.keyboard.press('a');
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(true);
expect(await page.evaluate(() => globalThis.lastEvent.repeat)).toBe(true);
await page.keyboard.down('b');
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(false);
expect(await page.evaluate(() => globalThis.lastEvent.repeat)).toBe(false);
await page.keyboard.down('b');
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(true);
expect(await page.evaluate(() => globalThis.lastEvent.repeat)).toBe(true);
await page.keyboard.up('a');
await page.keyboard.down('a');
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(false);
expect(await page.evaluate(() => globalThis.lastEvent.repeat)).toBe(false);
});
itFailsFirefox('should type all kinds of characters', async () => {
const { page, server } = getTestState();
@ -303,7 +311,7 @@ describe('Keyboard', function () {
await page.evaluate(() => {
window.addEventListener(
'keydown',
(event) => (window.keyLocation = event.location),
(event) => (globalThis.keyLocation = event.location),
true
);
});
@ -325,13 +333,16 @@ describe('Keyboard', function () {
const { page } = getTestState();
let error = await page.keyboard
// @ts-expect-error
.press('NotARealKey')
.catch((error_) => error_);
expect(error.message).toBe('Unknown key: "NotARealKey"');
// @ts-expect-error
error = await page.keyboard.press('ё').catch((error_) => error_);
expect(error && error.message).toBe('Unknown key: "ё"');
// @ts-expect-error
error = await page.keyboard.press('😊').catch((error_) => error_);
expect(error && error.message).toBe('Unknown key: "😊"');
});
@ -364,9 +375,9 @@ describe('Keyboard', function () {
const { page, isFirefox } = getTestState();
await page.evaluate(() => {
window.result = null;
globalThis.result = null;
document.addEventListener('keydown', (event) => {
window.result = [event.key, event.code, event.metaKey];
globalThis.result = [event.key, event.code, event.metaKey];
});
});
await page.keyboard.press('Meta');

View File

@ -13,19 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require('fs');
const os = require('os');
const path = require('path');
const sinon = require('sinon');
const { helper } = require('../lib/common/helper');
const rmAsync = helper.promisify(require('rimraf'));
import fs from 'fs';
import os from 'os';
import path from 'path';
import sinon from 'sinon';
import { helper } from '../src/common/helper';
import {
getTestState,
itFailsFirefox,
itOnlyRegularInstall,
itFailsWindowsUntilDate,
} from './mocha-utils';
import utils from './utils';
import expect from 'expect';
import rimraf from 'rimraf';
import { Page } from '../src/common/Page';
const rmAsync = helper.promisify(rimraf);
const mkdtempAsync = helper.promisify(fs.mkdtemp);
const readFileAsync = helper.promisify(fs.readFile);
const statAsync = helper.promisify(fs.stat);
const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-');
const utils = require('./utils');
const expect = require('expect');
const { getTestState } = require('./mocha-utils');
describe('Launcher specs', function () {
if (getTestState().isFirefox) this.timeout(30 * 1000);
@ -187,7 +195,7 @@ describe('Launcher specs', function () {
const page = await browser.newPage();
let error = null;
const neverResolves = page
.evaluate(() => new Promise((r) => {}))
.evaluate(() => new Promise(() => {}))
.catch((error_) => (error = error_));
await browser.close();
await neverResolves;
@ -215,7 +223,7 @@ describe('Launcher specs', function () {
await browser.close();
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
// This might throw. See https://github.com/puppeteer/puppeteer/issues/2778
await rmAsync(userDataDir).catch((error) => {});
await rmAsync(userDataDir).catch(() => {});
});
it('userDataDir argument', async () => {
const { isChrome, puppeteer, defaultBrowserOptions } = getTestState();
@ -239,7 +247,7 @@ describe('Launcher specs', function () {
await browser.close();
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
// This might throw. See https://github.com/puppeteer/puppeteer/issues/2778
await rmAsync(userDataDir).catch((error) => {});
await rmAsync(userDataDir).catch(() => {});
});
it('userDataDir option should restore state', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState();
@ -258,12 +266,12 @@ describe('Launcher specs', function () {
expect(await page2.evaluate(() => localStorage.hey)).toBe('hello');
await browser2.close();
// This might throw. See https://github.com/puppeteer/puppeteer/issues/2778
await rmAsync(userDataDir).catch((error) => {});
await rmAsync(userDataDir).catch(() => {});
});
// This mysteriously fails on Windows on AppVeyor. See
// https://github.com/puppeteer/puppeteer/issues/4111
xit('userDataDir option should restore cookies', async () => {
const { server, puppeteer } = getTestState();
const { server, puppeteer, defaultBrowserOptions } = getTestState();
const userDataDir = await mkdtempAsync(TMP_FOLDER);
const options = Object.assign({ userDataDir }, defaultBrowserOptions);
@ -285,7 +293,7 @@ describe('Launcher specs', function () {
);
await browser2.close();
// This might throw. See https://github.com/puppeteer/puppeteer/issues/2778
await rmAsync(userDataDir).catch((error) => {});
await rmAsync(userDataDir).catch(() => {});
});
it('should return the default arguments', async () => {
const { isChrome, isFirefox, puppeteer } = getTestState();
@ -351,6 +359,9 @@ describe('Launcher specs', function () {
})
);
const spawnargs = browser.process().spawnargs;
if (!spawnargs) {
throw new Error('spawnargs not present');
}
expect(spawnargs.indexOf(defaultArgs[0])).toBe(-1);
expect(spawnargs.indexOf(defaultArgs[1])).not.toBe(-1);
expect(spawnargs.indexOf(defaultArgs[2])).toBe(-1);
@ -486,10 +497,7 @@ describe('Launcher specs', function () {
otherBrowser.disconnect();
const secondPage = await originalBrowser.newPage();
expect(await secondPage.evaluate(() => 7 * 6)).toBe(
42,
'original browser should still work'
);
expect(await secondPage.evaluate(() => 7 * 6)).toBe(42);
await originalBrowser.close();
});
it('should be able to close remote browser', async () => {
@ -571,7 +579,7 @@ describe('Launcher specs', function () {
browserWSEndpoint: browserOne.wsEndpoint(),
});
const [page1, page2] = await Promise.all([
new Promise((x) =>
new Promise<Page>((x) =>
browserOne.once('targetcreated', (target) => x(target.page()))
),
browserTwo.newPage(),

View File

@ -14,16 +14,19 @@
* limitations under the License.
*/
const { TestServer } = require('../utils/testserver/index');
const path = require('path');
const fs = require('fs');
const os = require('os');
const sinon = require('sinon');
const puppeteer = require('../');
const utils = require('./utils');
const rimraf = require('rimraf');
import { TestServer } from '../utils/testserver/index';
import * as path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import sinon from 'sinon';
import puppeteer from '../src/index';
import { Browser, BrowserContext } from '../src/common/Browser';
import { Page } from '../src/common/Page';
import { Puppeteer } from '../src/common/Puppeteer';
import utils from './utils';
import rimraf from 'rimraf';
const { trackCoverage } = require('./coverage-utils');
import { trackCoverage } from './coverage-utils';
const setupServer = async () => {
const assetsPath = path.join(__dirname, 'assets');
@ -48,7 +51,8 @@ const setupServer = async () => {
return { server, httpsServer };
};
exports.getTestState = () => state;
export const getTestState = (): PuppeteerTestState =>
state as PuppeteerTestState;
const product =
process.env.PRODUCT || process.env.PUPPETEER_PRODUCT || 'Chromium';
@ -73,19 +77,20 @@ const defaultBrowserOptions = Object.assign(
{
handleSIGINT: true,
executablePath: process.env.BINARY,
slowMo: false,
headless: isHeadless,
dumpio: !!process.env.DUMPIO,
},
extraLaunchOptions
);
(async () => {
(async (): Promise<void> => {
if (defaultBrowserOptions.executablePath) {
console.warn(
`WARN: running ${product} tests with ${defaultBrowserOptions.executablePath}`
);
} else {
// TODO(jackfranklin): declare updateRevision in some form for the Firefox launcher.
// @ts-expect-error
if (product === 'firefox') await puppeteer._launcher._updateRevision();
const executablePath = puppeteer.executablePath();
if (!fs.existsSync(executablePath))
@ -95,7 +100,7 @@ const defaultBrowserOptions = Object.assign(
}
})();
const setupGoldenAssertions = () => {
const setupGoldenAssertions = (): void => {
const suffix = product.toLowerCase();
const GOLDEN_DIR = path.join(__dirname, 'golden-' + suffix);
const OUTPUT_DIR = path.join(__dirname, 'output-' + suffix);
@ -105,44 +110,78 @@ const setupGoldenAssertions = () => {
setupGoldenAssertions();
const state = {};
interface PuppeteerTestState {
browser: Browser;
context: BrowserContext;
page: Page;
puppeteer: Puppeteer;
defaultBrowserOptions: {
[x: string]: any;
};
server: any;
httpsServer: any;
isFirefox: boolean;
isChrome: boolean;
isHeadless: boolean;
puppeteerPath: string;
}
const state: Partial<PuppeteerTestState> = {};
global.itFailsFirefox = (...args) => {
if (isFirefox) return xit(...args);
else return it(...args);
export const itFailsFirefox = (
description: string,
body: Mocha.Func
): Mocha.Test => {
if (isFirefox) return xit(description, body);
else return it(description, body);
};
global.itChromeOnly = (...args) => {
if (isChrome) return it(...args);
else return xit(...args);
export const itChromeOnly = (
description: string,
body: Mocha.Func
): Mocha.Test => {
if (isChrome) return it(description, body);
else return xit(description, body);
};
global.itOnlyRegularInstall = (...args) => {
if (alternativeInstall || process.env.BINARY) return xit(...args);
else return it(...args);
export const itOnlyRegularInstall = (
description: string,
body: Mocha.Func
): Mocha.Test => {
if (alternativeInstall || process.env.BINARY) return xit(description, body);
else return it(description, body);
};
global.itFailsWindowsUntilDate = (date, ...args) => {
if (os.platform() === 'win32' && Date.now() < date) {
export const itFailsWindowsUntilDate = (
date: Date,
description: string,
body: Mocha.Func
): Mocha.Test => {
if (os.platform() === 'win32' && Date.now() < date.getTime()) {
// we are within the deferred time so skip the test
return xit(...args);
return xit(description, body);
}
return it(...args);
return it(description, body);
};
global.describeFailsFirefox = (...args) => {
if (isFirefox) return xdescribe(...args);
else return describe(...args);
export const describeFailsFirefox = (
description: string,
body: (this: Mocha.Suite) => void
): void | Mocha.Suite => {
if (isFirefox) return xdescribe(description, body);
else return describe(description, body);
};
global.describeChromeOnly = (...args) => {
if (isChrome) return describe(...args);
export const describeChromeOnly = (
description: string,
body: (this: Mocha.Suite) => void
): Mocha.Suite => {
if (isChrome) return describe(description, body);
};
let coverageHooks = {
beforeAll: () => {},
afterAll: () => {},
beforeAll: (): void => {},
afterAll: (): void => {},
};
if (process.env.COVERAGE) {
@ -158,7 +197,7 @@ console.log(
}`
);
exports.setupTestBrowserHooks = () => {
export const setupTestBrowserHooks = () => {
before(async () => {
const browser = await puppeteer.launch(defaultBrowserOptions);
state.browser = browser;
@ -170,7 +209,7 @@ exports.setupTestBrowserHooks = () => {
});
};
exports.setupTestPageAndContextHooks = () => {
export const setupTestPageAndContextHooks = () => {
beforeEach(async () => {
state.context = await state.browser.createIncognitoBrowserContext();
state.page = await state.context.newPage();
@ -183,7 +222,7 @@ exports.setupTestPageAndContextHooks = () => {
});
};
exports.mochaHooks = {
export const mochaHooks = {
beforeAll: [
async () => {
const { server, httpsServer } = await setupServer();

View File

@ -13,15 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const os = require('os');
const expect = require('expect');
const {
import os from 'os';
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
} from './mocha-utils';
import { KeyInput } from '../src/common/USKeyboardLayout';
function dimensions() {
interface Dimensions {
x: number;
y: number;
width: number;
height: number;
}
function dimensions(): Dimensions {
const rect = document.querySelector('textarea').getBoundingClientRect();
return {
x: rect.left,
@ -38,7 +47,7 @@ describe('Mouse', function () {
const { page } = getTestState();
await page.evaluate(() => {
window.clickPromise = new Promise((resolve) => {
globalThis.clickPromise = new Promise((resolve) => {
document.addEventListener('click', (event) => {
resolve({
type: event.type,
@ -52,7 +61,9 @@ describe('Mouse', function () {
});
});
await page.mouse.click(50, 60);
const event = await page.evaluate(() => window.clickPromise);
const event = await page.evaluate<MouseEvent>(
() => globalThis.clickPromise
);
expect(event.type).toBe('click');
expect(event.detail).toBe(1);
expect(event.clientX).toBe(50);
@ -64,13 +75,13 @@ describe('Mouse', function () {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/input/textarea.html');
const { x, y, width, height } = await page.evaluate(dimensions);
const { x, y, width, height } = await page.evaluate<Dimensions>(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);
const newDimensions = await page.evaluate<Dimensions>(dimensions);
expect(newDimensions.width).toBe(Math.round(width + 104));
expect(newDimensions.height).toBe(Math.round(height + 104));
});
@ -139,33 +150,26 @@ describe('Mouse', function () {
await page.evaluate(() =>
document
.querySelector('#button-3')
.addEventListener('mousedown', (e) => (window.lastEvent = e), true)
.addEventListener('mousedown', (e) => (globalThis.lastEvent = e), true)
);
const modifiers = {
Shift: 'shiftKey',
Control: 'ctrlKey',
Alt: 'altKey',
Meta: 'metaKey',
};
const modifiers = new Map<KeyInput, string>([
['Shift', 'shiftKey'],
['Control', 'ctrlKey'],
['Alt', 'altKey'],
['Meta', 'metaKey'],
]);
// In Firefox, the Meta modifier only exists on Mac
if (isFirefox && os.platform() !== 'darwin') delete modifiers['Meta'];
for (const modifier in modifiers) {
for (const [modifier, key] of modifiers) {
await page.keyboard.down(modifier);
await page.click('#button-3');
if (
!(await page.evaluate(
(mod) => window.lastEvent[mod],
modifiers[modifier]
))
)
throw new Error(modifiers[modifier] + ' should be true');
if (!(await page.evaluate((mod) => globalThis.lastEvent[mod], key)))
throw new Error(key + ' 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])
)
for (const [modifier, key] of modifiers) {
if (await page.evaluate((mod) => globalThis.lastEvent[mod], key))
throw new Error(modifiers[modifier] + ' should be false');
}
});
@ -174,9 +178,9 @@ describe('Mouse', function () {
await page.mouse.move(100, 100);
await page.evaluate(() => {
window.result = [];
globalThis.result = [];
document.addEventListener('mousemove', (event) => {
window.result.push([event.clientX, event.clientY]);
globalThis.result.push([event.clientX, event.clientY]);
});
});
await page.mouse.move(200, 300, { steps: 5 });
@ -199,7 +203,7 @@ describe('Mouse', function () {
await page.goto(server.CROSS_PROCESS_PREFIX + '/mobile.html');
await page.evaluate(() => {
document.addEventListener('click', (event) => {
window.result = { x: event.clientX, y: event.clientY };
globalThis.result = { x: event.clientX, y: event.clientY };
});
});

View File

@ -14,14 +14,16 @@
* limitations under the License.
*/
const utils = require('./utils');
const expect = require('expect');
const {
import utils from './utils';
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
const os = require('os');
itFailsFirefox,
describeFailsFirefox,
} from './mocha-utils';
import os from 'os';
describe('navigation', function () {
setupTestBrowserHooks();
@ -155,9 +157,9 @@ describe('navigation', function () {
// Make sure that network events do not emit 'undefined'.
// @see https://crbug.com/750469
const requests = [];
page.on('request', (request) => requests.push('request'));
page.on('requestfinished', (request) => requests.push('requestfinished'));
page.on('requestfailed', (request) => requests.push('requestfailed'));
page.on('request', () => requests.push('request'));
page.on('requestfinished', () => requests.push('requestfinished'));
page.on('requestfailed', () => requests.push('requestfailed'));
let error = null;
await page
@ -187,6 +189,7 @@ describe('navigation', function () {
let error = null;
await page
// @ts-expect-error
.goto(server.EMPTY_PAGE, { waitUntil: 'networkidle' })
.catch((error_) => (error = error_));
expect(error.message).toContain(
@ -208,7 +211,7 @@ describe('navigation', function () {
const { page, server, puppeteer } = getTestState();
// Hang for request to the empty.html
server.setRoute('/empty.html', (req, res) => {});
server.setRoute('/empty.html', () => {});
let error = null;
await page
.goto(server.PREFIX + '/empty.html', { timeout: 1 })
@ -220,7 +223,7 @@ describe('navigation', function () {
const { page, server, puppeteer } = getTestState();
// Hang for request to the empty.html
server.setRoute('/empty.html', (req, res) => {});
server.setRoute('/empty.html', () => {});
let error = null;
page.setDefaultNavigationTimeout(1);
await page
@ -233,7 +236,7 @@ describe('navigation', function () {
const { page, server, puppeteer } = getTestState();
// Hang for request to the empty.html
server.setRoute('/empty.html', (req, res) => {});
server.setRoute('/empty.html', () => {});
let error = null;
page.setDefaultTimeout(1);
await page
@ -246,7 +249,7 @@ describe('navigation', function () {
const { page, server, puppeteer } = getTestState();
// Hang for request to the empty.html
server.setRoute('/empty.html', (req, res) => {});
server.setRoute('/empty.html', () => {});
let error = null;
page.setDefaultTimeout(0);
page.setDefaultNavigationTimeout(1);
@ -389,7 +392,7 @@ describe('navigation', function () {
const warningHandler = (w) => (warning = w);
process.on('warning', warningHandler);
for (let i = 0; i < 20; ++i)
await page.goto('asdf').catch((error) => {
await page.goto('asdf').catch(() => {
/* swallow navigation error */
});
process.removeListener('warning', warningHandler);
@ -601,7 +604,7 @@ describe('navigation', function () {
async () => {
const { page, server } = getTestState();
server.setRoute('/frames/style.css', (req, res) => {});
server.setRoute('/frames/style.css', () => {});
const navigationPromise = page.goto(
server.PREFIX + '/frames/one-frame.html'
);
@ -748,7 +751,7 @@ describe('navigation', function () {
.catch((error_) => (error = error_));
await Promise.all([
server.waitForRequest('/empty.html'),
frame.evaluate(() => (window.location = '/empty.html')),
frame.evaluate(() => ((window as any).location = '/empty.html')),
]);
await page.$eval('iframe', (frame) => frame.remove());
await navigationPromise;
@ -761,9 +764,9 @@ describe('navigation', function () {
const { page, server } = getTestState();
await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => (window._foo = 10));
await page.evaluate(() => (globalThis._foo = 10));
await page.reload();
expect(await page.evaluate(() => window._foo)).toBe(undefined);
expect(await page.evaluate(() => globalThis._foo)).toBe(undefined);
});
});
});

View File

@ -14,15 +14,17 @@
* limitations under the License.
*/
const fs = require('fs');
const path = require('path');
const utils = require('./utils');
const expect = require('expect');
const {
import fs from 'fs';
import path from 'path';
import utils from './utils';
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
describeFailsFirefox,
} from './mocha-utils';
describe('network', function () {
setupTestBrowserHooks();
@ -184,7 +186,7 @@ describe('network', function () {
await page.goto(server.PREFIX + '/serviceworkers/fetch/sw.html', {
waitUntil: 'networkidle2',
});
await page.evaluate(async () => await window.activationPromise);
await page.evaluate(async () => await globalThis.activationPromise);
await page.reload();
expect(responses.size).toBe(2);
@ -409,9 +411,9 @@ describe('network', function () {
const { page, server } = getTestState();
const events = [];
page.on('request', (request) => events.push('request'));
page.on('response', (response) => events.push('response'));
page.on('requestfinished', (request) => events.push('requestfinished'));
page.on('request', () => events.push('request'));
page.on('response', () => events.push('response'));
page.on('requestfinished', () => events.push('requestfinished'));
await page.goto(server.EMPTY_PAGE);
expect(events).toEqual(['request', 'response', 'requestfinished']);
});
@ -514,6 +516,7 @@ describe('network', function () {
let error = null;
try {
// @ts-expect-error
await page.setExtraHTTPHeaders({ foo: 1 });
} catch (error_) {
error = error_;

View File

@ -14,8 +14,8 @@
* limitations under the License.
*/
const expect = require('expect');
const { getTestState } = require('./mocha-utils');
import expect from 'expect';
import { getTestState, describeChromeOnly } from './mocha-utils';
describeChromeOnly('OOPIF', function () {
/* We use a special browser for this test as we need the --site-per-process flag */

View File

@ -13,17 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require('fs');
const path = require('path');
const utils = require('./utils');
import fs from 'fs';
import path from 'path';
import utils from './utils';
const { waitEvent } = utils;
const expect = require('expect');
const sinon = require('sinon');
const {
import expect from 'expect';
import sinon from 'sinon';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
describeFailsFirefox,
} from './mocha-utils';
import { Page, Metrics } from '../src/common/Page';
describe('Page', function () {
setupTestBrowserHooks();
@ -36,7 +39,7 @@ describe('Page', function () {
let error = null;
await Promise.all([
newPage
.evaluate(() => new Promise((r) => {}))
.evaluate(() => new Promise(() => {}))
.catch((error_) => (error = error_)),
newPage.close(),
]);
@ -160,7 +163,7 @@ describe('Page', function () {
let error = null;
page.on('error', (err) => (error = err));
page.goto('chrome://crash').catch((error_) => {});
page.goto('chrome://crash').catch(() => {});
await waitEvent(page, 'error');
expect(error.message).toBe('Page crashed!');
});
@ -171,7 +174,7 @@ describe('Page', function () {
const { page } = getTestState();
const [popup] = await Promise.all([
new Promise((x) => page.once('popup', x)),
new Promise<Page>((x) => page.once('popup', x)),
page.evaluate(() => window.open('about:blank')),
]);
expect(await page.evaluate(() => !!window.opener)).toBe(false);
@ -181,7 +184,7 @@ describe('Page', function () {
const { page } = getTestState();
const [popup] = await Promise.all([
new Promise((x) => page.once('popup', x)),
new Promise<Page>((x) => page.once('popup', x)),
page.evaluate(() => window.open('about:blank', null, 'noopener')),
]);
expect(await page.evaluate(() => !!window.opener)).toBe(false);
@ -193,7 +196,7 @@ describe('Page', function () {
await page.goto(server.EMPTY_PAGE);
await page.setContent('<a target=_blank href="/one-style.html">yo</a>');
const [popup] = await Promise.all([
new Promise((x) => page.once('popup', x)),
new Promise<Page>((x) => page.once('popup', x)),
page.click('a'),
]);
expect(await page.evaluate(() => !!window.opener)).toBe(false);
@ -207,7 +210,7 @@ describe('Page', function () {
'<a target=_blank rel=noopener href="/one-style.html">yo</a>'
);
const [popup] = await Promise.all([
new Promise((x) => page.once('popup', x)),
new Promise<Page>((x) => page.once('popup', x)),
page.$eval('a', (a) => a.click()),
]);
expect(await page.evaluate(() => !!window.opener)).toBe(false);
@ -221,7 +224,7 @@ describe('Page', function () {
'<a target=_blank rel=noopener href="/one-style.html">yo</a>'
);
const [popup] = await Promise.all([
new Promise((x) => page.once('popup', x)),
new Promise<Page>((x) => page.once('popup', x)),
page.click('a'),
]);
expect(await page.evaluate(() => !!window.opener)).toBe(false);
@ -257,6 +260,7 @@ describe('Page', function () {
await page.goto(server.EMPTY_PAGE);
let error = null;
await context
// @ts-expect-error
.overridePermissions(server.EMPTY_PAGE, ['foo'])
.catch((error_) => (error = error_));
expect(error.message).toBe('Unknown permission: foo');
@ -282,30 +286,30 @@ describe('Page', function () {
await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => {
window.events = [];
globalThis.events = [];
return navigator.permissions
.query({ name: 'geolocation' })
.then(function (result) {
window.events.push(result.state);
globalThis.events.push(result.state);
result.onchange = function () {
window.events.push(result.state);
globalThis.events.push(result.state);
};
});
});
expect(await page.evaluate(() => window.events)).toEqual(['prompt']);
expect(await page.evaluate(() => globalThis.events)).toEqual(['prompt']);
await context.overridePermissions(server.EMPTY_PAGE, []);
expect(await page.evaluate(() => window.events)).toEqual([
expect(await page.evaluate(() => globalThis.events)).toEqual([
'prompt',
'denied',
]);
await context.overridePermissions(server.EMPTY_PAGE, ['geolocation']);
expect(await page.evaluate(() => window.events)).toEqual([
expect(await page.evaluate(() => globalThis.events)).toEqual([
'prompt',
'denied',
'granted',
]);
await context.clearPermissionOverrides();
expect(await page.evaluate(() => window.events)).toEqual([
expect(await page.evaluate(() => globalThis.events)).toEqual([
'prompt',
'denied',
'granted',
@ -404,7 +408,7 @@ describe('Page', function () {
const { page } = getTestState();
// Instantiate an object
await page.evaluate(() => (window.set = new Set(['hello', 'world'])));
await page.evaluate(() => (globalThis.set = new Set(['hello', 'world'])));
const prototypeHandle = await page.evaluateHandle(() => Set.prototype);
const objectsHandle = await page.queryObjects(prototypeHandle);
const count = await page.evaluate(
@ -423,7 +427,7 @@ describe('Page', function () {
// Instantiate an object
await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => (window.set = new Set(['hello', 'world'])));
await page.evaluate(() => (globalThis.set = new Set(['hello', 'world'])));
const prototypeHandle = await page.evaluateHandle(() => Set.prototype);
const objectsHandle = await page.queryObjects(prototypeHandle);
const count = await page.evaluate(
@ -526,7 +530,7 @@ describe('Page', function () {
const [message] = await Promise.all([
waitEvent(page, 'console'),
page.evaluate(
async (url) => fetch(url).catch((error) => {}),
async (url) => fetch(url).catch(() => {}),
server.EMPTY_PAGE
),
]);
@ -616,8 +620,8 @@ describe('Page', function () {
it('metrics event fired on console.timeStamp', async () => {
const { page } = getTestState();
const metricsPromise = new Promise((fulfill) =>
page.once('metrics', fulfill)
const metricsPromise = new Promise<{ metrics: Metrics; title: string }>(
(fulfill) => page.once('metrics', fulfill)
);
await page.evaluate(() => console.timeStamp('test42'));
const metrics = await metricsPromise;
@ -793,7 +797,7 @@ describe('Page', function () {
return a * b;
});
const result = await page.evaluate(async function () {
return await compute(9, 4);
return await globalThis.compute(9, 4);
});
expect(result).toBe(36);
});
@ -805,7 +809,7 @@ describe('Page', function () {
});
const { message, stack } = await page.evaluate(async () => {
try {
await woof();
await globalThis.woof();
} catch (error) {
return { message: error.message, stack: error.stack };
}
@ -821,7 +825,7 @@ describe('Page', function () {
});
const thrown = await page.evaluate(async () => {
try {
await woof();
await globalThis.woof();
} catch (error) {
return error;
}
@ -835,7 +839,7 @@ describe('Page', function () {
await page.exposeFunction('woof', function () {
called = true;
});
await page.evaluateOnNewDocument(() => woof());
await page.evaluateOnNewDocument(() => globalThis.woof());
await page.reload();
expect(called).toBe(true);
});
@ -848,7 +852,7 @@ describe('Page', function () {
await page.goto(server.EMPTY_PAGE);
const result = await page.evaluate(async function () {
return await compute(9, 4);
return await globalThis.compute(9, 4);
});
expect(result).toBe(36);
});
@ -860,7 +864,7 @@ describe('Page', function () {
});
const result = await page.evaluate(async function () {
return await compute(3, 5);
return await globalThis.compute(3, 5);
});
expect(result).toBe(15);
});
@ -874,7 +878,7 @@ describe('Page', function () {
await page.goto(server.PREFIX + '/frames/nested-frames.html');
const frame = page.frames()[1];
const result = await frame.evaluate(async function () {
return await compute(3, 5);
return await globalThis.compute(3, 5);
});
expect(result).toBe(15);
});
@ -888,7 +892,7 @@ describe('Page', function () {
const frame = page.frames()[1];
const result = await frame.evaluate(async function () {
return await compute(3, 5);
return await globalThis.compute(3, 5);
});
expect(result).toBe(15);
});
@ -898,8 +902,8 @@ describe('Page', function () {
await page.exposeFunction('complexObject', function (a, b) {
return { x: a.x + b.x };
});
const result = await page.evaluate(async () =>
complexObject({ x: 5 }, { x: 2 })
const result = await page.evaluate<{ x: number }>(async () =>
globalThis.complexObject({ x: 5 }, { x: 2 })
);
expect(result.x).toBe(7);
});
@ -993,7 +997,7 @@ describe('Page', function () {
const imgPath = '/img.png';
// stall for image
server.setRoute(imgPath, (req, res) => {});
server.setRoute(imgPath, () => {});
let error = null;
await page
.setContent(`<img src="${server.PREFIX + imgPath}"></img>`, {
@ -1008,7 +1012,7 @@ describe('Page', function () {
page.setDefaultNavigationTimeout(1);
const imgPath = '/img.png';
// stall for image
server.setRoute(imgPath, (req, res) => {});
server.setRoute(imgPath, () => {});
let error = null;
await page
.setContent(`<img src="${server.PREFIX + imgPath}"></img>`)
@ -1074,13 +1078,13 @@ describe('Page', function () {
await page
.addScriptTag({ content: 'window.__injected = 42;' })
.catch((error) => void error);
expect(await page.evaluate(() => window.__injected)).toBe(undefined);
expect(await page.evaluate(() => globalThis.__injected)).toBe(undefined);
// By-pass CSP and try one more time.
await page.setBypassCSP(true);
await page.reload();
await page.addScriptTag({ content: 'window.__injected = 42;' });
expect(await page.evaluate(() => window.__injected)).toBe(42);
expect(await page.evaluate(() => globalThis.__injected)).toBe(42);
});
it('should bypass CSP header', async () => {
@ -1092,13 +1096,13 @@ describe('Page', function () {
await page
.addScriptTag({ content: 'window.__injected = 42;' })
.catch((error) => void error);
expect(await page.evaluate(() => window.__injected)).toBe(undefined);
expect(await page.evaluate(() => globalThis.__injected)).toBe(undefined);
// By-pass CSP and try one more time.
await page.setBypassCSP(true);
await page.reload();
await page.addScriptTag({ content: 'window.__injected = 42;' });
expect(await page.evaluate(() => window.__injected)).toBe(42);
expect(await page.evaluate(() => globalThis.__injected)).toBe(42);
});
it('should bypass after cross-process navigation', async () => {
@ -1107,11 +1111,11 @@ describe('Page', function () {
await page.setBypassCSP(true);
await page.goto(server.PREFIX + '/csp.html');
await page.addScriptTag({ content: 'window.__injected = 42;' });
expect(await page.evaluate(() => window.__injected)).toBe(42);
expect(await page.evaluate(() => globalThis.__injected)).toBe(42);
await page.goto(server.CROSS_PROCESS_PREFIX + '/csp.html');
await page.addScriptTag({ content: 'window.__injected = 42;' });
expect(await page.evaluate(() => window.__injected)).toBe(42);
expect(await page.evaluate(() => globalThis.__injected)).toBe(42);
});
it('should bypass CSP in iframes as well', async () => {
const { page, server } = getTestState();
@ -1127,7 +1131,9 @@ describe('Page', function () {
await frame
.addScriptTag({ content: 'window.__injected = 42;' })
.catch((error) => void error);
expect(await frame.evaluate(() => window.__injected)).toBe(undefined);
expect(await frame.evaluate(() => globalThis.__injected)).toBe(
undefined
);
}
// By-pass CSP and try one more time.
@ -1143,7 +1149,7 @@ describe('Page', function () {
await frame
.addScriptTag({ content: 'window.__injected = 42;' })
.catch((error) => void error);
expect(await frame.evaluate(() => window.__injected)).toBe(42);
expect(await frame.evaluate(() => globalThis.__injected)).toBe(42);
}
});
});
@ -1154,6 +1160,7 @@ describe('Page', function () {
let error = null;
try {
// @ts-expect-error
await page.addScriptTag('/injectedfile.js');
} catch (error_) {
error = error_;
@ -1169,7 +1176,7 @@ describe('Page', function () {
await page.goto(server.EMPTY_PAGE);
const scriptHandle = await page.addScriptTag({ url: '/injectedfile.js' });
expect(scriptHandle.asElement()).not.toBeNull();
expect(await page.evaluate(() => __injected)).toBe(42);
expect(await page.evaluate(() => globalThis.__injected)).toBe(42);
});
it('should work with a url and type=module', async () => {
@ -1177,7 +1184,7 @@ describe('Page', function () {
await page.goto(server.EMPTY_PAGE);
await page.addScriptTag({ url: '/es6/es6import.js', type: 'module' });
expect(await page.evaluate(() => __es6injected)).toBe(42);
expect(await page.evaluate(() => globalThis.__es6injected)).toBe(42);
});
it('should work with a path and type=module', async () => {
@ -1189,7 +1196,7 @@ describe('Page', function () {
type: 'module',
});
await page.waitForFunction('window.__es6injected');
expect(await page.evaluate(() => __es6injected)).toBe(42);
expect(await page.evaluate(() => globalThis.__es6injected)).toBe(42);
});
it('should work with a content and type=module', async () => {
@ -1201,7 +1208,7 @@ describe('Page', function () {
type: 'module',
});
await page.waitForFunction('window.__es6injected');
expect(await page.evaluate(() => __es6injected)).toBe(42);
expect(await page.evaluate(() => globalThis.__es6injected)).toBe(42);
});
it('should throw an error if loading from url fail', async () => {
@ -1225,7 +1232,7 @@ describe('Page', function () {
path: path.join(__dirname, 'assets/injectedfile.js'),
});
expect(scriptHandle.asElement()).not.toBeNull();
expect(await page.evaluate(() => __injected)).toBe(42);
expect(await page.evaluate(() => globalThis.__injected)).toBe(42);
});
it('should include sourcemap when path is provided', async () => {
@ -1235,7 +1242,9 @@ describe('Page', function () {
await page.addScriptTag({
path: path.join(__dirname, 'assets/injectedfile.js'),
});
const result = await page.evaluate(() => __injectedError.stack);
const result = await page.evaluate(
() => globalThis.__injectedError.stack
);
expect(result).toContain(path.join('assets', 'injectedfile.js'));
});
@ -1247,7 +1256,7 @@ describe('Page', function () {
content: 'window.__injected = 35;',
});
expect(scriptHandle.asElement()).not.toBeNull();
expect(await page.evaluate(() => __injected)).toBe(35);
expect(await page.evaluate(() => globalThis.__injected)).toBe(35);
});
// @see https://github.com/puppeteer/puppeteer/issues/4840
@ -1280,6 +1289,7 @@ describe('Page', function () {
let error = null;
try {
// @ts-expect-error
await page.addStyleTag('/injectedstyle.css');
} catch (error_) {
error = error_;
@ -1485,16 +1495,24 @@ describe('Page', function () {
await page.goto(server.PREFIX + '/input/select.html');
await page.select('select', 'blue');
expect(await page.evaluate(() => result.onInput)).toEqual(['blue']);
expect(await page.evaluate(() => result.onChange)).toEqual(['blue']);
expect(await page.evaluate(() => globalThis.result.onInput)).toEqual([
'blue',
]);
expect(await page.evaluate(() => globalThis.result.onChange)).toEqual([
'blue',
]);
});
it('should select only first option', async () => {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/input/select.html');
await page.select('select', 'blue', 'green', 'red');
expect(await page.evaluate(() => result.onInput)).toEqual(['blue']);
expect(await page.evaluate(() => result.onChange)).toEqual(['blue']);
expect(await page.evaluate(() => globalThis.result.onInput)).toEqual([
'blue',
]);
expect(await page.evaluate(() => globalThis.result.onChange)).toEqual([
'blue',
]);
});
it('should not throw when select causes navigation', async () => {
const { page, server } = getTestState();
@ -1503,7 +1521,7 @@ describe('Page', function () {
await page.$eval('select', (select) =>
select.addEventListener(
'input',
() => (window.location = '/empty.html')
() => ((window as any).location = '/empty.html')
)
);
await Promise.all([
@ -1516,14 +1534,14 @@ describe('Page', function () {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/input/select.html');
await page.evaluate(() => makeMultiple());
await page.evaluate(() => globalThis.makeMultiple());
await page.select('select', 'blue', 'green', 'red');
expect(await page.evaluate(() => result.onInput)).toEqual([
expect(await page.evaluate(() => globalThis.result.onInput)).toEqual([
'blue',
'green',
'red',
]);
expect(await page.evaluate(() => result.onChange)).toEqual([
expect(await page.evaluate(() => globalThis.result.onChange)).toEqual([
'blue',
'green',
'red',
@ -1534,12 +1552,12 @@ describe('Page', function () {
await page.goto(server.PREFIX + '/input/select.html');
await page.select('select', 'blue');
expect(await page.evaluate(() => result.onBubblingInput)).toEqual([
'blue',
]);
expect(await page.evaluate(() => result.onBubblingChange)).toEqual([
'blue',
]);
expect(
await page.evaluate(() => globalThis.result.onBubblingInput)
).toEqual(['blue']);
expect(
await page.evaluate(() => globalThis.result.onBubblingChange)
).toEqual(['blue']);
});
it('should throw when element is not a <select>', async () => {
const { page, server } = getTestState();
@ -1560,7 +1578,7 @@ describe('Page', function () {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/input/select.html');
await page.evaluate(() => makeMultiple());
await page.evaluate(() => globalThis.makeMultiple());
const result = await page.select('select', 'blue', 'black', 'magenta');
expect(
result.reduce(
@ -1594,12 +1612,14 @@ describe('Page', function () {
const { page, server } = getTestState();
await page.goto(server.PREFIX + '/input/select.html');
await page.evaluate(() => makeMultiple());
await page.evaluate(() => globalThis.makeMultiple());
await page.select('select', 'blue', 'black', 'magenta');
await page.select('select');
expect(
await page.$eval('select', (select) =>
Array.from(select.options).every((option) => !option.selected)
Array.from(select.options).every(
(option: HTMLOptionElement) => !option.selected
)
)
).toEqual(true);
});
@ -1611,7 +1631,9 @@ describe('Page', function () {
await page.select('select');
expect(
await page.$eval('select', (select) =>
Array.from(select.options).every((option) => !option.selected)
Array.from(select.options).every(
(option: HTMLOptionElement) => !option.selected
)
)
).toEqual(true);
});
@ -1621,6 +1643,7 @@ describe('Page', function () {
await page.setContent('<select><option value="12"/></select>');
let error = null;
try {
// @ts-expect-error
await page.select('select', 12);
} catch (error_) {
error = error_;
@ -1636,8 +1659,12 @@ describe('Page', function () {
await page.goto(server.PREFIX + '/input/select.html');
await page.evaluate(() => (window.Event = null));
await page.select('select', 'blue');
expect(await page.evaluate(() => result.onInput)).toEqual(['blue']);
expect(await page.evaluate(() => result.onChange)).toEqual(['blue']);
expect(await page.evaluate(() => globalThis.result.onInput)).toEqual([
'blue',
]);
expect(await page.evaluate(() => globalThis.result.onChange)).toEqual([
'blue',
]);
}
);
});
@ -1646,7 +1673,7 @@ describe('Page', function () {
itFailsFirefox('should work with window.close', async () => {
const { page, context } = getTestState();
const newPagePromise = new Promise((fulfill) =>
const newPagePromise = new Promise<Page>((fulfill) =>
context.once('targetcreated', (target) => fulfill(target.page()))
);
await page.evaluate(

View File

@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
} from './mocha-utils';
describe('querySelector', function () {
setupTestBrowserHooks();

View File

@ -14,15 +14,16 @@
* limitations under the License.
*/
const fs = require('fs');
const path = require('path');
const utils = require('./utils');
const expect = require('expect');
const {
import fs from 'fs';
import path from 'path';
import utils from './utils';
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
describeFailsFirefox,
} from './mocha-utils';
describe('request interception', function () {
setupTestBrowserHooks();
@ -188,7 +189,7 @@ describe('request interception', function () {
else request.continue();
});
let failedRequests = 0;
page.on('requestfailed', (event) => ++failedRequests);
page.on('requestfailed', () => ++failedRequests);
const response = await page.goto(server.PREFIX + '/one-style.html');
expect(response.ok()).toBe(true);
expect(response.request().failure()).toBe(null);
@ -203,7 +204,7 @@ describe('request interception', function () {
});
let failedRequest = null;
page.on('requestfailed', (request) => (failedRequest = request));
await page.goto(server.EMPTY_PAGE).catch((error) => {});
await page.goto(server.EMPTY_PAGE).catch(() => {});
expect(failedRequest).toBeTruthy();
expect(failedRequest.failure().errorText).toBe(
'net::ERR_INTERNET_DISCONNECTED'
@ -345,13 +346,13 @@ describe('request interception', function () {
Promise.all([
fetch('/zzz')
.then((response) => response.text())
.catch((error) => 'FAILED'),
.catch(() => 'FAILED'),
fetch('/zzz')
.then((response) => response.text())
.catch((error) => 'FAILED'),
.catch(() => 'FAILED'),
fetch('/zzz')
.then((response) => response.text())
.catch((error) => 'FAILED'),
.catch(() => 'FAILED'),
])
);
expect(results).toEqual(['11', 'FAILED', '22']);
@ -665,6 +666,8 @@ describe('request interception', function () {
return new Promise((fulfill) => (img.onload = fulfill));
}, server.PREFIX);
const img = await page.$('img');
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(await img.screenshot()).toBeGolden('mock-binary-response.png');
});
it('should stringify intercepted request response headers', async () => {

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
} from './mocha-utils';
describe('Screenshots', function () {
setupTestBrowserHooks();
@ -32,6 +33,8 @@ describe('Screenshots', function () {
await page.setViewport({ width: 500, height: 500 });
await page.goto(server.PREFIX + '/grid.html');
const screenshot = await page.screenshot();
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('screenshot-sanity.png');
});
itFailsFirefox('should clip rect', async () => {
@ -47,6 +50,8 @@ describe('Screenshots', function () {
height: 100,
},
});
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('screenshot-clip-rect.png');
});
itFailsFirefox('should clip elements to the viewport', async () => {
@ -62,6 +67,8 @@ describe('Screenshots', function () {
height: 100,
},
});
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('screenshot-offscreen-clip.png');
});
it('should run in parallel', async () => {
@ -83,6 +90,8 @@ describe('Screenshots', function () {
);
}
const screenshots = await Promise.all(promises);
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshots[1]).toBeGolden('grid-cell-1.png');
});
itFailsFirefox('should take fullPage screenshots', async () => {
@ -93,6 +102,8 @@ describe('Screenshots', function () {
const screenshot = await page.screenshot({
fullPage: true,
});
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('screenshot-grid-fullpage.png');
});
it('should run in parallel in multiple pages', async () => {
@ -117,6 +128,8 @@ describe('Screenshots', function () {
);
const screenshots = await Promise.all(promises);
for (let i = 0; i < N; ++i)
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshots[i]).toBeGolden(`grid-cell-${i}.png`);
await Promise.all(pages.map((page) => page.close()));
});
@ -126,6 +139,8 @@ describe('Screenshots', function () {
await page.setViewport({ width: 100, height: 100 });
await page.goto(server.EMPTY_PAGE);
const screenshot = await page.screenshot({ omitBackground: true });
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('transparent.png');
});
itFailsFirefox('should render white background on jpeg file', async () => {
@ -137,6 +152,8 @@ describe('Screenshots', function () {
omitBackground: true,
type: 'jpeg',
});
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('white.jpg');
});
it('should work with odd clip size on Retina displays', async () => {
@ -150,6 +167,8 @@ describe('Screenshots', function () {
height: 11,
},
});
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('screenshot-clip-odd-size.png');
});
itFailsFirefox('should return base64', async () => {
@ -160,6 +179,8 @@ describe('Screenshots', function () {
const screenshot = await page.screenshot({
encoding: 'base64',
});
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(Buffer.from(screenshot, 'base64')).toBeGolden(
'screenshot-sanity.png'
);
@ -175,6 +196,8 @@ describe('Screenshots', function () {
await page.evaluate(() => window.scrollBy(50, 100));
const elementHandle = await page.$('.box:nth-of-type(3)');
const screenshot = await elementHandle.screenshot();
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('screenshot-element-bounding-box.png');
});
it('should take into account padding and border', async () => {
@ -194,6 +217,8 @@ describe('Screenshots', function () {
`);
const elementHandle = await page.$('div');
const screenshot = await elementHandle.screenshot();
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('screenshot-element-padding-border.png');
});
it('should capture full element when larger than viewport', async () => {
@ -218,6 +243,8 @@ describe('Screenshots', function () {
`);
const elementHandle = await page.$('div.to-screenshot');
const screenshot = await elementHandle.screenshot();
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden(
'screenshot-element-larger-than-viewport.png'
);
@ -252,6 +279,8 @@ describe('Screenshots', function () {
`);
const elementHandle = await page.$('div.to-screenshot');
const screenshot = await elementHandle.screenshot();
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden(
'screenshot-element-scrolled-into-view.png'
);
@ -269,6 +298,8 @@ describe('Screenshots', function () {
transform: rotateZ(200deg);">&nbsp;</div>`);
const elementHandle = await page.$('div');
const screenshot = await elementHandle.screenshot();
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('screenshot-element-rotate.png');
});
itFailsFirefox('should fail to screenshot a detached element', async () => {
@ -300,6 +331,8 @@ describe('Screenshots', function () {
);
const elementHandle = await page.$('div');
const screenshot = await elementHandle.screenshot();
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('screenshot-element-fractional.png');
});
itFailsFirefox('should work for an element with an offset', async () => {
@ -310,6 +343,8 @@ describe('Screenshots', function () {
);
const elementHandle = await page.$('div');
const screenshot = await elementHandle.screenshot();
// TODO (@jackfranklin): toBeGolden type fix
// @ts-expect-error
expect(screenshot).toBeGolden('screenshot-element-fractional-offset.png');
});
});

View File

@ -14,14 +14,16 @@
* limitations under the License.
*/
const utils = require('./utils');
import utils from './utils';
const { waitEvent } = utils;
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
} from './mocha-utils';
import { Target } from '../src/common/Target';
describe('Target', function () {
setupTestBrowserHooks();
@ -112,7 +114,7 @@ describe('Target', function () {
const { page, server, context } = getTestState();
await page.goto(server.EMPTY_PAGE);
const createdTarget = new Promise((fulfill) =>
const createdTarget = new Promise<Target>((fulfill) =>
context.once('targetcreated', (target) => fulfill(target))
);
@ -127,7 +129,7 @@ describe('Target', function () {
context.once('targetdestroyed', (target) => fulfill(target))
);
await page.evaluate(() =>
window.registrationPromise.then((registration) =>
globalThis.registrationPromise.then((registration) =>
registration.unregister()
)
);
@ -166,7 +168,7 @@ describe('Target', function () {
const { page, server, context } = getTestState();
await page.goto(server.EMPTY_PAGE);
let changedTarget = new Promise((fulfill) =>
let changedTarget = new Promise<Target>((fulfill) =>
context.once('targetchanged', (target) => fulfill(target))
);
await page.goto(server.CROSS_PROCESS_PREFIX + '/');
@ -184,7 +186,7 @@ describe('Target', function () {
let targetChanged = false;
const listener = () => (targetChanged = true);
context.on('targetchanged', listener);
const targetPromise = new Promise((fulfill) =>
const targetPromise = new Promise<Target>((fulfill) =>
context.once('targetcreated', (target) => fulfill(target))
);
const newPagePromise = context.newPage();
@ -192,7 +194,7 @@ describe('Target', function () {
expect(target.url()).toBe('about:blank');
const newPage = await newPagePromise;
const targetPromise2 = new Promise((fulfill) =>
const targetPromise2 = new Promise<Target>((fulfill) =>
context.once('targetcreated', (target) => fulfill(target))
);
const evaluatePromise = newPage.evaluate(() => window.open('about:blank'));
@ -200,10 +202,7 @@ describe('Target', function () {
expect(target2.url()).toBe('about:blank');
await evaluatePromise;
await newPage.close();
expect(targetChanged).toBe(
false,
'target should not be reported as changed'
);
expect(targetChanged).toBe(false);
context.removeListener('targetchanged', listener);
});
itFailsFirefox(
@ -240,7 +239,7 @@ describe('Target', function () {
await page.goto(server.EMPTY_PAGE);
const [createdTarget] = await Promise.all([
new Promise((fulfill) =>
new Promise<Target>((fulfill) =>
context.once('targetcreated', (target) => fulfill(target))
),
page.goto(server.PREFIX + '/popup/window-open.html'),

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
describeFailsFirefox,
} from './mocha-utils';
describeFailsFirefox('Touchscreen', function () {
setupTestBrowserHooks();
@ -31,7 +32,7 @@ describeFailsFirefox('Touchscreen', function () {
await page.emulate(iPhone);
await page.goto(server.PREFIX + '/input/button.html');
await page.tap('button');
expect(await page.evaluate(() => result)).toBe('Clicked');
expect(await page.evaluate(() => globalThis.result)).toBe('Clicked');
});
it('should report touches', async () => {
const { puppeteer, page, server } = getTestState();
@ -40,7 +41,7 @@ describeFailsFirefox('Touchscreen', function () {
await page.goto(server.PREFIX + '/input/touches.html');
const button = await page.$('button');
await button.tap();
expect(await page.evaluate(() => getResult())).toEqual([
expect(await page.evaluate(() => globalThis.getResult())).toEqual([
'Touchstart: 0',
'Touchend: 0',
]);

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
const fs = require('fs');
const path = require('path');
const expect = require('expect');
const { getTestState } = require('./mocha-utils');
import fs from 'fs';
import path from 'path';
import expect from 'expect';
import { getTestState, describeChromeOnly } from './mocha-utils';
describeChromeOnly('Tracing', function () {
let outputFile;
@ -60,7 +60,9 @@ describeChromeOnly('Tracing', function () {
});
await page.tracing.stop();
const traceJson = JSON.parse(fs.readFileSync(outputFile));
const traceJson = JSON.parse(
fs.readFileSync(outputFile, { encoding: 'utf8' })
);
expect(traceJson.metadata['trace-config']).toContain(
'disabled-by-default-v8.cpu_profiler.hires'
);
@ -100,7 +102,7 @@ describeChromeOnly('Tracing', function () {
await page.tracing.start({ screenshots: true });
await page.goto(server.PREFIX + '/grid.html');
const oldBufferConcat = Buffer.concat;
Buffer.concat = (bufs) => {
Buffer.concat = () => {
throw 'error';
};
const trace = await page.tracing.stop();

7
test/tsconfig.json Normal file
View File

@ -0,0 +1,7 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"noEmit": true
},
"include": ["*.ts", "*.js"]
}

View File

@ -14,6 +14,9 @@
* limitations under the License.
*/
// TODO (@jackfranklin): convert to TS and enable type checking.
// @ts-nocheck
const fs = require('fs');
const path = require('path');
const expect = require('expect');

View File

@ -14,13 +14,14 @@
* limitations under the License.
*/
const utils = require('./utils');
const expect = require('expect');
const {
import utils from './utils';
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
itFailsFirefox,
} from './mocha-utils';
describe('waittask specs', function () {
setupTestBrowserHooks();
@ -86,6 +87,7 @@ describe('waittask specs', function () {
const { page } = getTestState();
let error = null;
// @ts-expect-error
await page.waitFor({ foo: 'bar' }).catch((error_) => (error = error_));
expect(error.message).toContain('Unsupported target type');
});
@ -101,7 +103,7 @@ describe('waittask specs', function () {
const { page } = getTestState();
const watchdog = page.waitForFunction('window.__FOO === 1');
await page.evaluate(() => (window.__FOO = 1));
await page.evaluate(() => (globalThis.__FOO = 1));
await watchdog;
});
itFailsFirefox(
@ -109,9 +111,9 @@ describe('waittask specs', function () {
async () => {
const { page } = getTestState();
await page.evaluateOnNewDocument(() => (window.__RELOADED = true));
await page.evaluateOnNewDocument(() => (globalThis.__RELOADED = true));
await page.waitForFunction(() => {
if (!window.__RELOADED) window.location.reload();
if (!globalThis.__RELOADED) window.location.reload();
return true;
});
}
@ -123,9 +125,9 @@ describe('waittask specs', function () {
const startTime = Date.now();
const polling = 100;
const watchdog = page
.waitForFunction(() => window.__FOO === 'hit', { polling })
.waitForFunction(() => globalThis.__FOO === 'hit', { polling })
.then(() => (success = true));
await page.evaluate(() => (window.__FOO = 'hit'));
await page.evaluate(() => (globalThis.__FOO = 'hit'));
expect(success).toBe(false);
await page.evaluate(() =>
document.body.appendChild(document.createElement('div'))
@ -139,9 +141,9 @@ describe('waittask specs', function () {
const startTime = Date.now();
const polling = 100;
const watchdog = page
.waitForFunction(async () => window.__FOO === 'hit', { polling })
.waitForFunction(async () => globalThis.__FOO === 'hit', { polling })
.then(() => (success = true));
await page.evaluate(async () => (window.__FOO = 'hit'));
await page.evaluate(async () => (globalThis.__FOO = 'hit'));
expect(success).toBe(false);
await page.evaluate(async () =>
document.body.appendChild(document.createElement('div'))
@ -154,9 +156,11 @@ describe('waittask specs', function () {
let success = false;
const watchdog = page
.waitForFunction(() => window.__FOO === 'hit', { polling: 'mutation' })
.waitForFunction(() => globalThis.__FOO === 'hit', {
polling: 'mutation',
})
.then(() => (success = true));
await page.evaluate(() => (window.__FOO = 'hit'));
await page.evaluate(() => (globalThis.__FOO = 'hit'));
expect(success).toBe(false);
await page.evaluate(() =>
document.body.appendChild(document.createElement('div'))
@ -168,11 +172,11 @@ describe('waittask specs', function () {
let success = false;
const watchdog = page
.waitForFunction(async () => window.__FOO === 'hit', {
.waitForFunction(async () => globalThis.__FOO === 'hit', {
polling: 'mutation',
})
.then(() => (success = true));
await page.evaluate(async () => (window.__FOO = 'hit'));
await page.evaluate(async () => (globalThis.__FOO = 'hit'));
expect(success).toBe(false);
await page.evaluate(async () =>
document.body.appendChild(document.createElement('div'))
@ -182,22 +186,22 @@ describe('waittask specs', function () {
it('should poll on raf', async () => {
const { page } = getTestState();
const watchdog = page.waitForFunction(() => window.__FOO === 'hit', {
const watchdog = page.waitForFunction(() => globalThis.__FOO === 'hit', {
polling: 'raf',
});
await page.evaluate(() => (window.__FOO = 'hit'));
await page.evaluate(() => (globalThis.__FOO = 'hit'));
await watchdog;
});
it('should poll on raf async', async () => {
const { page } = getTestState();
const watchdog = page.waitForFunction(
async () => window.__FOO === 'hit',
async () => globalThis.__FOO === 'hit',
{
polling: 'raf',
}
);
await page.evaluate(async () => (window.__FOO = 'hit'));
await page.evaluate(async () => (globalThis.__FOO = 'hit'));
await watchdog;
});
itFailsFirefox('should work with strict CSP policy', async () => {
@ -208,9 +212,9 @@ describe('waittask specs', function () {
let error = null;
await Promise.all([
page
.waitForFunction(() => window.__FOO === 'hit', { polling: 'raf' })
.waitForFunction(() => globalThis.__FOO === 'hit', { polling: 'raf' })
.catch((error_) => (error = error_)),
page.evaluate(() => (window.__FOO = 'hit')),
page.evaluate(() => (globalThis.__FOO = 'hit')),
]);
expect(error).toBe(null);
});
@ -288,13 +292,13 @@ describe('waittask specs', function () {
const watchdog = page.waitForFunction(
() => {
window.__counter = (window.__counter || 0) + 1;
return window.__injected;
globalThis.__counter = (globalThis.__counter || 0) + 1;
return globalThis.__injected;
},
{ timeout: 0, polling: 10 }
);
await page.waitForFunction(() => window.__counter > 10);
await page.evaluate(() => (window.__injected = true));
await page.waitForFunction(() => globalThis.__counter > 10);
await page.evaluate(() => (globalThis.__injected = true));
await watchdog;
});
it('should survive cross-process navigation', async () => {
@ -302,7 +306,7 @@ describe('waittask specs', function () {
let fooFound = false;
const waitForFunction = page
.waitForFunction('window.__FOO === 1')
.waitForFunction('globalThis.__FOO === 1')
.then(() => (fooFound = true));
await page.goto(server.EMPTY_PAGE);
expect(fooFound).toBe(false);
@ -310,17 +314,17 @@ describe('waittask specs', function () {
expect(fooFound).toBe(false);
await page.goto(server.CROSS_PROCESS_PREFIX + '/grid.html');
expect(fooFound).toBe(false);
await page.evaluate(() => (window.__FOO = 1));
await page.evaluate(() => (globalThis.__FOO = 1));
await waitForFunction;
expect(fooFound).toBe(true);
});
it('should survive navigations', async () => {
const { page, server } = getTestState();
const watchdog = page.waitForFunction(() => window.__done);
const watchdog = page.waitForFunction(() => globalThis.__done);
await page.goto(server.EMPTY_PAGE);
await page.goto(server.PREFIX + '/consolelog.html');
await page.evaluate(() => (window.__done = true));
await page.evaluate(() => (globalThis.__done = true));
await watchdog;
});
});
@ -594,7 +598,9 @@ describe('waittask specs', function () {
await page
.waitForSelector('.zombo', { timeout: 10 })
.catch((error_) => (error = error_));
expect(error.stack).toContain('waittask.spec.js');
expect(error.stack).toContain('waiting for selector ".zombo" failed');
// The extension is ts here as Mocha maps back via sourcemaps.
expect(error.stack).toContain('waittask.spec.ts');
});
});

View File

@ -14,13 +14,16 @@
* limitations under the License.
*/
const expect = require('expect');
const {
import expect from 'expect';
import {
getTestState,
setupTestBrowserHooks,
setupTestPageAndContextHooks,
} = require('./mocha-utils');
const utils = require('./utils');
describeFailsFirefox,
} from './mocha-utils';
import utils from './utils';
import { WebWorker } from '../src/common/WebWorker';
import { ConsoleMessage } from '../src/common/ConsoleMessage';
const { waitEvent } = utils;
describeFailsFirefox('Workers', function () {
@ -36,7 +39,7 @@ describeFailsFirefox('Workers', function () {
const worker = page.workers()[0];
expect(worker.url()).toContain('worker.js');
expect(await worker.evaluate(() => self.workerFunction())).toBe(
expect(await worker.evaluate(() => globalThis.workerFunction())).toBe(
'worker function result'
);
@ -46,7 +49,7 @@ describeFailsFirefox('Workers', function () {
it('should emit created and destroyed events', async () => {
const { page } = getTestState();
const workerCreatedPromise = new Promise((x) =>
const workerCreatedPromise = new Promise<WebWorker>((x) =>
page.once('workercreated', x)
);
const workerObj = await page.evaluateHandle(
@ -81,7 +84,9 @@ describeFailsFirefox('Workers', function () {
it('should have JSHandles for console logs', async () => {
const { page } = getTestState();
const logPromise = new Promise((x) => page.on('console', x));
const logPromise = new Promise<ConsoleMessage>((x) =>
page.on('console', x)
);
await page.evaluate(
() => new Worker(`data:text/javascript,console.log(1,2,3,this)`)
);
@ -95,7 +100,7 @@ describeFailsFirefox('Workers', function () {
it('should have an execution context', async () => {
const { page } = getTestState();
const workerCreatedPromise = new Promise((x) =>
const workerCreatedPromise = new Promise<WebWorker>((x) =>
page.once('workercreated', x)
);
await page.evaluate(
@ -107,7 +112,7 @@ describeFailsFirefox('Workers', function () {
it('should report errors', async () => {
const { page } = getTestState();
const errorPromise = new Promise((x) => page.on('pageerror', x));
const errorPromise = new Promise<Error>((x) => page.on('pageerror', x));
await page.evaluate(
() =>
new Worker(`data:text/javascript, throw new Error('this is my error');`)

View File

@ -8,7 +8,8 @@
"module": "CommonJS",
"declaration": true,
"declarationMap": true,
"esModuleInterop": true
"esModuleInterop": true,
"resolveJsonModule": true
},
"include": [
"src"

View File

@ -1,3 +1,5 @@
// @ts-nocheck
/**
* Copyright 2017 Google Inc. All rights reserved.
*
@ -26,6 +28,11 @@ const fulfillSymbol = Symbol('fullfil callback');
const rejectSymbol = Symbol('reject callback');
class TestServer {
PORT = undefined;
PREFIX = undefined;
CROSS_PROCESS_PREFIX = undefined;
EMPTY_PAGE = undefined;
/**
* @param {string} dirPath
* @param {number} port