chore: make tests strict (1) (#27731)

This commit is contained in:
Pavel Feldman 2023-10-23 09:31:30 -07:00 committed by GitHub
parent f48861ddee
commit 5752a28f87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 518 additions and 511 deletions

View File

@ -24,7 +24,7 @@ test('androidDevice.close', async function({ playwright }) {
const devices = await playwright._android.devices(); const devices = await playwright._android.devices();
expect(devices.length).toBe(1); expect(devices.length).toBe(1);
const device = devices[0]; const device = devices[0];
const events = []; const events: string[] = [];
device.on('close', () => events.push('close')); device.on('close', () => events.push('close'));
await device.close(); await device.close();
await device.close(); await device.close();

View File

@ -38,7 +38,7 @@ export const androidTest = baseTest.extend<PageTestFixtures, AndroidWorkerFixtur
const browserVersion = (await androidDevice.shell('dumpsys package com.android.chrome')) const browserVersion = (await androidDevice.shell('dumpsys package com.android.chrome'))
.toString('utf8') .toString('utf8')
.split('\n') .split('\n')
.find(line => line.includes('versionName=')) .find(line => line.includes('versionName='))!
.trim() .trim()
.split('=')[1]; .split('=')[1];
await run(browserVersion); await run(browserVersion);

View File

@ -28,7 +28,7 @@ test('androidDevice.open', async function({ androidDevice }) {
const socket = await androidDevice.open('shell:/bin/cat'); const socket = await androidDevice.open('shell:/bin/cat');
await socket.write(Buffer.from('321\n')); await socket.write(Buffer.from('321\n'));
const output = await new Promise(resolve => socket.on('data', resolve)); const output = await new Promise(resolve => socket.on('data', resolve));
expect(output.toString()).toBe('321\n'); expect(output!.toString()).toBe('321\n');
const closedPromise = new Promise<void>(resolve => socket.on('close', resolve)); const closedPromise = new Promise<void>(resolve => socket.on('close', resolve));
await socket.close(); await socket.close();
await closedPromise; await closedPromise;

View File

@ -31,7 +31,7 @@ test('android.launchServer should connect to a device', async ({ playwright }) =
}); });
test('android.launchServer should handle close event correctly', async ({ playwright }) => { test('android.launchServer should handle close event correctly', async ({ playwright }) => {
const receivedEvents = []; const receivedEvents: string[] = [];
const browserServer = await playwright._android.launchServer(); const browserServer = await playwright._android.launchServer();
const device = await playwright._android.connect(browserServer.wsEndpoint()); const device = await playwright._android.connect(browserServer.wsEndpoint());
device.on('close', () => receivedEvents.push('device')); device.on('close', () => receivedEvents.push('device'));
@ -116,7 +116,7 @@ test('android.launchServer BrowserServer.kill() will disconnect the device', as
test('android.launchServer should terminate WS connection when device gets disconnected', async ({ playwright }) => { test('android.launchServer should terminate WS connection when device gets disconnected', async ({ playwright }) => {
const browserServer = await playwright._android.launchServer(); const browserServer = await playwright._android.launchServer();
const forwardingServer = new ws.Server({ port: 0, path: '/connect' }); const forwardingServer = new ws.Server({ port: 0, path: '/connect' });
let receivedConnection: ws.WebSocket; let receivedConnection: ws.WebSocket | undefined;
forwardingServer.on('connection', connection => { forwardingServer.on('connection', connection => {
receivedConnection = connection; receivedConnection = connection;
const actualConnection = new ws.WebSocket(browserServer.wsEndpoint()); const actualConnection = new ws.WebSocket(browserServer.wsEndpoint());
@ -130,11 +130,11 @@ test('android.launchServer should terminate WS connection when device gets disco
try { try {
const device = await playwright._android.connect(`ws://localhost:${(forwardingServer.address() as ws.AddressInfo).port}/connect`); const device = await playwright._android.connect(`ws://localhost:${(forwardingServer.address() as ws.AddressInfo).port}/connect`);
expect((await device.shell('echo 123')).toString()).toBe('123\n'); expect((await device.shell('echo 123')).toString()).toBe('123\n');
expect(receivedConnection.readyState).toBe(ws.OPEN); expect(receivedConnection!.readyState).toBe(ws.OPEN);
const waitToClose = new Promise(f => receivedConnection.on('close', f)); const waitToClose = new Promise(f => receivedConnection!.on('close', f));
await device.close(); await device.close();
await waitToClose; await waitToClose;
expect(receivedConnection.readyState).toBe(ws.CLOSED); expect(receivedConnection!.readyState).toBe(ws.CLOSED);
} finally { } finally {
await browserServer.close(); await browserServer.close();
await new Promise(f => forwardingServer.close(f)); await new Promise(f => forwardingServer.close(f));

View File

@ -49,7 +49,7 @@ const metadata = {
video: false, video: false,
}; };
config.projects.push({ config.projects!.push({
name: 'android', name: 'android',
use: { use: {
loopback: '10.0.2.2', loopback: '10.0.2.2',
@ -60,7 +60,7 @@ config.projects.push({
metadata, metadata,
}); });
config.projects.push({ config.projects!.push({
name: 'android', name: 'android',
use: { use: {
loopback: '10.0.2.2', loopback: '10.0.2.2',

View File

@ -30,7 +30,7 @@ export const baseTest = mergeTests(base, coverageTest, platformTest, testModeTes
.extend<CommonFixtures, CommonWorkerFixtures>(commonFixtures) .extend<CommonFixtures, CommonWorkerFixtures>(commonFixtures)
.extend<ServerFixtures, ServerWorkerOptions>(serverFixtures); .extend<ServerFixtures, ServerWorkerOptions>(serverFixtures);
export function step<This, Args extends any[], Return>( export function step<This extends Object, Args extends any[], Return>(
target: (this: This, ...args: Args) => Promise<Return>, target: (this: This, ...args: Args) => Promise<Return>,
context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Promise<Return>> context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Promise<Return>>
) { ) {

View File

@ -28,7 +28,7 @@ import { parseHar } from '../config/utils';
export type BrowserTestWorkerFixtures = PageWorkerFixtures & { export type BrowserTestWorkerFixtures = PageWorkerFixtures & {
browserVersion: string; browserVersion: string;
defaultSameSiteCookieValue: string; defaultSameSiteCookieValue: string;
allowsThirdParty allowsThirdParty: boolean;
browserMajorVersion: number; browserMajorVersion: number;
browserType: BrowserType; browserType: BrowserType;
isAndroid: boolean; isAndroid: boolean;

View File

@ -47,7 +47,7 @@ function readAllProcessesLinux(): { pid: number, ppid: number, pgrp: number }[]
const statFile = fs.readFileSync(`/proc/${pid}/stat`, 'utf8'); const statFile = fs.readFileSync(`/proc/${pid}/stat`, 'utf8');
// Format of /proc/*/stat is described https://man7.org/linux/man-pages/man5/proc.5.html // Format of /proc/*/stat is described https://man7.org/linux/man-pages/man5/proc.5.html
const match = statFile.match(/^(?<pid>\d+)\s+\((?<comm>.*)\)\s+(?<state>R|S|D|Z|T|t|W|X|x|K|W|P)\s+(?<ppid>\d+)\s+(?<pgrp>\d+)/); const match = statFile.match(/^(?<pid>\d+)\s+\((?<comm>.*)\)\s+(?<state>R|S|D|Z|T|t|W|X|x|K|W|P)\s+(?<ppid>\d+)\s+(?<pgrp>\d+)/);
if (match) { if (match && match.groups) {
result.push({ result.push({
pid: +match.groups.pid, pid: +match.groups.pid,
ppid: +match.groups.ppid, ppid: +match.groups.ppid,
@ -89,7 +89,7 @@ function buildProcessTreePosix(pid: number): ProcessData {
if (parent && child) if (parent && child)
parent.children.add(child); parent.children.add(child);
} }
return pidToProcess.get(pid); return pidToProcess.get(pid)!;
} }
export class TestChildProcess { export class TestChildProcess {
@ -98,8 +98,8 @@ export class TestChildProcess {
output = ''; output = '';
fullOutput = ''; fullOutput = '';
onOutput?: (chunk: string | Buffer) => void; onOutput?: (chunk: string | Buffer) => void;
exited: Promise<{ exitCode: number, signal: string | null }>; exited: Promise<{ exitCode: number | null, signal: string | null }>;
exitCode: Promise<number>; exitCode: Promise<number | null>;
private _outputCallbacks = new Set<() => void>(); private _outputCallbacks = new Set<() => void>();
@ -133,8 +133,8 @@ export class TestChildProcess {
this._outputCallbacks.clear(); this._outputCallbacks.clear();
}; };
this.process.stderr.on('data', appendChunk); this.process.stderr!.on('data', appendChunk);
this.process.stdout.on('data', appendChunk); this.process.stdout!.on('data', appendChunk);
const killProcessGroup = this._killProcessTree.bind(this, 'SIGKILL'); const killProcessGroup = this._killProcessTree.bind(this, 'SIGKILL');
process.on('exit', killProcessGroup); process.on('exit', killProcessGroup);
@ -214,7 +214,7 @@ export class TestChildProcess {
} }
write(chars: string) { write(chars: string) {
this.process.stdin.write(chars); this.process.stdin!.write(chars);
} }
} }

View File

@ -24,8 +24,8 @@ export interface PlaywrightServer {
} }
export class RunServer implements PlaywrightServer { export class RunServer implements PlaywrightServer {
private _process: TestChildProcess; private _process!: TestChildProcess;
_wsEndpoint: string; _wsEndpoint!: string;
async start(childProcess: CommonFixtures['childProcess'], mode?: 'extension' | 'default', env?: NodeJS.ProcessEnv) { async start(childProcess: CommonFixtures['childProcess'], mode?: 'extension' | 'default', env?: NodeJS.ProcessEnv) {
const command = ['node', path.join(__dirname, '..', '..', 'packages', 'playwright-core', 'lib', 'cli', 'cli.js'), 'run-server']; const command = ['node', path.join(__dirname, '..', '..', 'packages', 'playwright-core', 'lib', 'cli', 'cli.js'), 'run-server'];
@ -40,7 +40,7 @@ export class RunServer implements PlaywrightServer {
}, },
}); });
let wsEndpointCallback; let wsEndpointCallback: (value: string) => void;
const wsEndpointPromise = new Promise<string>(f => wsEndpointCallback = f); const wsEndpointPromise = new Promise<string>(f => wsEndpointCallback = f);
this._process.onOutput = data => { this._process.onOutput = data => {
const prefix = 'Listening on '; const prefix = 'Listening on ';
@ -71,18 +71,15 @@ export type RemoteServerOptions = {
}; };
export class RemoteServer implements PlaywrightServer { export class RemoteServer implements PlaywrightServer {
private _process: TestChildProcess; private _process!: TestChildProcess;
_output: Map<string, string>; readonly _output = new Map<string, string>();
_outputCallback: Map<string, () => void>; readonly _outputCallback = new Map<string, () => void>();
_browserType: BrowserType; _browserType!: BrowserType;
_exitAndDisconnectPromise: Promise<any>; _exitAndDisconnectPromise: Promise<any> | undefined;
_browser: Browser; _browser: Browser | undefined;
_wsEndpoint: string; _wsEndpoint!: string;
async _start(childProcess: CommonFixtures['childProcess'], browserType: BrowserType, remoteServerOptions: RemoteServerOptions = {}) { async _start(childProcess: CommonFixtures['childProcess'], browserType: BrowserType, remoteServerOptions: RemoteServerOptions = {}) {
this._output = new Map();
this._outputCallback = new Map();
this._browserType = browserType; this._browserType = browserType;
const browserOptions = (browserType as any)._defaultLaunchOptions; const browserOptions = (browserType as any)._defaultLaunchOptions;
// Copy options to prevent a large JSON string when launching subprocess. // Copy options to prevent a large JSON string when launching subprocess.
@ -114,7 +111,7 @@ export class RemoteServer implements PlaywrightServer {
const key = match[1]; const key = match[1];
const value = match[2]; const value = match[2];
this._addOutput(key, value); this._addOutput(key, value);
index += match.index + match[0].length; index += match.index! + match[0].length;
} }
}; };
@ -135,10 +132,10 @@ export class RemoteServer implements PlaywrightServer {
cb(); cb();
} }
async out(key: string) { async out(key: string): Promise<string> {
if (!this._output.has(key)) if (!this._output.has(key))
await new Promise<void>(f => this._outputCallback.set(key, f)); await new Promise<void>(f => this._outputCallback.set(key, f));
return this._output.get(key); return this._output.get(key)!;
} }
wsEndpoint() { wsEndpoint() {

View File

@ -37,10 +37,10 @@ test('should create new page @smoke', async function({ browser }) {
test('should throw upon second create new page', async function({ browser }) { test('should throw upon second create new page', async function({ browser }) {
const page = await browser.newPage(); const page = await browser.newPage();
let error; let error: Error;
await page.context().newPage().catch(e => error = e); await page.context().newPage().catch(e => error = e);
await page.close(); await page.close();
expect(error.message).toContain('Please use browser.newContext()'); expect(error!.message).toContain('Please use browser.newContext()');
}); });
test('version should work', async function({ browser, browserName }) { test('version should work', async function({ browser, browserName }) {

View File

@ -87,7 +87,7 @@ it('should roundtrip cookie', async ({ context, page, server }) => {
it('should send cookie header', async ({ server, context }) => { it('should send cookie header', async ({ server, context }) => {
let cookie = ''; let cookie = '';
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
cookie = req.headers.cookie; cookie = req.headers.cookie!;
res.end(); res.end();
}); });
await context.addCookies([{ url: server.EMPTY_PAGE, name: 'cookie', value: 'value' }]); await context.addCookies([{ url: server.EMPTY_PAGE, name: 'cookie', value: 'value' }]);
@ -345,7 +345,7 @@ it('should set cookies for a frame', async ({ context, page, server }) => {
{ url: server.PREFIX, name: 'frame-cookie', value: 'value' } { url: server.PREFIX, name: 'frame-cookie', value: 'value' }
]); ]);
await page.evaluate(src => { await page.evaluate(src => {
let fulfill; let fulfill!: (value: unknown) => void;
const promise = new Promise(x => fulfill = x); const promise = new Promise(x => fulfill = x);
const iframe = document.createElement('iframe'); const iframe = document.createElement('iframe');
document.body.appendChild(iframe); document.body.appendChild(iframe);
@ -360,7 +360,7 @@ it('should set cookies for a frame', async ({ context, page, server }) => {
it('should(not) block third party cookies', async ({ context, page, server, browserName, allowsThirdParty }) => { it('should(not) block third party cookies', async ({ context, page, server, browserName, allowsThirdParty }) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(src => { await page.evaluate(src => {
let fulfill; let fulfill!: (value: unknown) => void;
const promise = new Promise(x => fulfill = x); const promise = new Promise(x => fulfill = x);
const iframe = document.createElement('iframe'); const iframe = document.createElement('iframe');
document.body.appendChild(iframe); document.body.appendChild(iframe);
@ -438,10 +438,10 @@ it('should allow unnamed cookies', async ({ page, context, server, browserName,
// Round-trip behavior // Round-trip behavior
const resp = await page.goto(server.PREFIX + '/cookies'); const resp = await page.goto(server.PREFIX + '/cookies');
if (browserName === 'webkit' && platform === 'darwin') { if (browserName === 'webkit' && platform === 'darwin') {
expect.soft(await resp.text()).toBe('undefined-on-server'); expect.soft(await resp!.text()).toBe('undefined-on-server');
expect.soft(await page.evaluate('document.cookie')).toBe(''); expect.soft(await page.evaluate('document.cookie')).toBe('');
} else { } else {
expect.soft(await resp.text()).toBe('unnamed-via-add-cookies'); expect.soft(await resp!.text()).toBe('unnamed-via-add-cookies');
expect.soft(await page.evaluate('document.cookie')).toBe('unnamed-via-add-cookies'); expect.soft(await page.evaluate('document.cookie')).toBe('unnamed-via-add-cookies');
} }
// Within PW behavior // Within PW behavior

View File

@ -18,51 +18,51 @@
import { contextTest as it, expect } from '../config/browserTest'; import { contextTest as it, expect } from '../config/browserTest';
it('should work with browser context scripts @smoke', async ({ context, server }) => { it('should work with browser context scripts @smoke', async ({ context, server }) => {
await context.addInitScript(() => window['temp'] = 123); await context.addInitScript(() => (window as any)['temp'] = 123);
const page = await context.newPage(); const page = await context.newPage();
await page.addInitScript(() => window['injected'] = window['temp']); await page.addInitScript(() => (window as any)['injected'] = (window as any)['temp']);
await page.goto(server.PREFIX + '/tamperable.html'); await page.goto(server.PREFIX + '/tamperable.html');
expect(await page.evaluate(() => window['result'])).toBe(123); expect(await page.evaluate(() => (window as any)['result'])).toBe(123);
}); });
it('should work without navigation, after all bindings', async ({ context }) => { it('should work without navigation, after all bindings', async ({ context }) => {
let callback; let callback: (arg: unknown) => void;
const promise = new Promise(f => callback = f); const promise = new Promise(f => callback = f);
await context.exposeFunction('woof', function(arg) { await context.exposeFunction('woof', function(arg: any) {
callback(arg); callback(arg);
}); });
await context.addInitScript(() => { await context.addInitScript(() => {
window['woof']('hey'); (window as any)['woof']('hey');
window['temp'] = 123; (window as any)['temp'] = 123;
}); });
const page = await context.newPage(); const page = await context.newPage();
expect(await page.evaluate(() => window['temp'])).toBe(123); expect(await page.evaluate(() => (window as any)['temp'])).toBe(123);
expect(await promise).toBe('hey'); expect(await promise).toBe('hey');
}); });
it('should work without navigation in popup', async ({ context }) => { it('should work without navigation in popup', async ({ context }) => {
await context.addInitScript(() => window['temp'] = 123); await context.addInitScript(() => (window as any)['temp'] = 123);
const page = await context.newPage(); const page = await context.newPage();
const [popup] = await Promise.all([ const [popup] = await Promise.all([
page.waitForEvent('popup'), page.waitForEvent('popup'),
page.evaluate(() => window['win'] = window.open()), page.evaluate(() => (window as any)['win'] = window.open()),
]); ]);
expect(await popup.evaluate(() => window['temp'])).toBe(123); expect(await popup.evaluate(() => (window as any)['temp'])).toBe(123);
}); });
it('should work with browser context scripts with a path', async ({ context, server, asset }) => { it('should work with browser context scripts with a path', async ({ context, server, asset }) => {
await context.addInitScript({ path: asset('injectedfile.js') }); await context.addInitScript({ path: asset('injectedfile.js') });
const page = await context.newPage(); const page = await context.newPage();
await page.goto(server.PREFIX + '/tamperable.html'); await page.goto(server.PREFIX + '/tamperable.html');
expect(await page.evaluate(() => window['result'])).toBe(123); expect(await page.evaluate(() => (window as any)['result'])).toBe(123);
}); });
it('should work with browser context scripts for already created pages', async ({ context, server }) => { it('should work with browser context scripts for already created pages', async ({ context, server }) => {
const page = await context.newPage(); const page = await context.newPage();
await context.addInitScript(() => window['temp'] = 123); await context.addInitScript(() => (window as any)['temp'] = 123);
await page.addInitScript(() => window['injected'] = window['temp']); await page.addInitScript(() => (window as any)['injected'] = (window as any)['temp']);
await page.goto(server.PREFIX + '/tamperable.html'); await page.goto(server.PREFIX + '/tamperable.html');
expect(await page.evaluate(() => window['result'])).toBe(123); expect(await page.evaluate(() => (window as any)['result'])).toBe(123);
}); });

View File

@ -22,7 +22,7 @@ it('should construct a new URL when a baseURL in browser.newContext is passed to
baseURL: server.PREFIX, baseURL: server.PREFIX,
}); });
const page = await context.newPage(); const page = await context.newPage();
expect((await page.goto('/empty.html')).url()).toBe(server.EMPTY_PAGE); expect((await page.goto('/empty.html'))!.url()).toBe(server.EMPTY_PAGE);
await context.close(); await context.close();
}); });
@ -30,7 +30,7 @@ it('should construct a new URL when a baseURL in browser.newPage is passed to pa
const page = await browser.newPage({ const page = await browser.newPage({
baseURL: server.PREFIX, baseURL: server.PREFIX,
}); });
expect((await page.goto('/empty.html')).url()).toBe(server.EMPTY_PAGE); expect((await page.goto('/empty.html'))!.url()).toBe(server.EMPTY_PAGE);
await page.close(); await page.close();
}); });
@ -40,7 +40,7 @@ it('should construct a new URL when a baseURL in browserType.launchPersistentCon
baseURL: server.PREFIX, baseURL: server.PREFIX,
}); });
const page = await context.newPage(); const page = await context.newPage();
expect((await page.goto('/empty.html')).url()).toBe(server.EMPTY_PAGE); expect((await page.goto('/empty.html'))!.url()).toBe(server.EMPTY_PAGE);
await context.close(); await context.close();
}); });
@ -48,9 +48,9 @@ it('should construct the URLs correctly when a baseURL without a trailing slash
const page = await browser.newPage({ const page = await browser.newPage({
baseURL: server.PREFIX + '/url-construction', baseURL: server.PREFIX + '/url-construction',
}); });
expect((await page.goto('mypage.html')).url()).toBe(server.PREFIX + '/mypage.html'); expect((await page.goto('mypage.html'))!.url()).toBe(server.PREFIX + '/mypage.html');
expect((await page.goto('./mypage.html')).url()).toBe(server.PREFIX + '/mypage.html'); expect((await page.goto('./mypage.html'))!.url()).toBe(server.PREFIX + '/mypage.html');
expect((await page.goto('/mypage.html')).url()).toBe(server.PREFIX + '/mypage.html'); expect((await page.goto('/mypage.html'))!.url()).toBe(server.PREFIX + '/mypage.html');
await page.close(); await page.close();
}); });
@ -58,11 +58,11 @@ it('should construct the URLs correctly when a baseURL with a trailing slash in
const page = await browser.newPage({ const page = await browser.newPage({
baseURL: server.PREFIX + '/url-construction/', baseURL: server.PREFIX + '/url-construction/',
}); });
expect((await page.goto('mypage.html')).url()).toBe(server.PREFIX + '/url-construction/mypage.html'); expect((await page.goto('mypage.html'))!.url()).toBe(server.PREFIX + '/url-construction/mypage.html');
expect((await page.goto('./mypage.html')).url()).toBe(server.PREFIX + '/url-construction/mypage.html'); expect((await page.goto('./mypage.html'))!.url()).toBe(server.PREFIX + '/url-construction/mypage.html');
expect((await page.goto('/mypage.html')).url()).toBe(server.PREFIX + '/mypage.html'); expect((await page.goto('/mypage.html'))!.url()).toBe(server.PREFIX + '/mypage.html');
expect((await page.goto('.')).url()).toBe(server.PREFIX + '/url-construction/'); expect((await page.goto('.'))!.url()).toBe(server.PREFIX + '/url-construction/');
expect((await page.goto('/')).url()).toBe(server.PREFIX + '/'); expect((await page.goto('/'))!.url()).toBe(server.PREFIX + '/');
await page.close(); await page.close();
}); });
@ -70,7 +70,7 @@ it('should not construct a new URL when valid URLs are passed', async function({
const page = await browser.newPage({ const page = await browser.newPage({
baseURL: 'http://microsoft.com', baseURL: 'http://microsoft.com',
}); });
expect((await page.goto(server.EMPTY_PAGE)).url()).toBe(server.EMPTY_PAGE); expect((await page.goto(server.EMPTY_PAGE))!.url()).toBe(server.EMPTY_PAGE);
await page.goto('data:text/html,Hello world'); await page.goto('data:text/html,Hello world');
expect(await page.evaluate(() => window.location.href)).toBe('data:text/html,Hello world'); expect(await page.evaluate(() => window.location.href)).toBe('data:text/html,Hello world');

View File

@ -18,6 +18,7 @@
import { kTargetClosedErrorMessage } from '../config/errors'; import { kTargetClosedErrorMessage } from '../config/errors';
import { browserTest as it, expect } from '../config/browserTest'; import { browserTest as it, expect } from '../config/browserTest';
import { attachFrame, verifyViewport } from '../config/utils'; import { attachFrame, verifyViewport } from '../config/utils';
import type { Page } from '@playwright/test';
it('should create new context @smoke', async function({ browser }) { it('should create new context @smoke', async function({ browser }) {
expect(browser.contexts().length).toBe(0); expect(browser.contexts().length).toBe(0);
@ -154,7 +155,7 @@ it('should not report frameless pages on error', async ({ browser, server }) =>
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
res.end(`<a href="${server.EMPTY_PAGE}" target="_blank">Click me</a>`); res.end(`<a href="${server.EMPTY_PAGE}" target="_blank">Click me</a>`);
}); });
let popup; let popup: Page | undefined;
context.on('page', p => popup = p); context.on('page', p => popup = p);
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.click('"Click me"'); await page.click('"Click me"');
@ -194,9 +195,9 @@ it('should disable javascript', async ({ browser, browserName }) => {
let error = null; let error = null;
await page.evaluate('something').catch(e => error = e); await page.evaluate('something').catch(e => error = e);
if (browserName === 'webkit') if (browserName === 'webkit')
expect(error.message).toContain('Can\'t find variable: something'); expect(error!.message).toContain('Can\'t find variable: something');
else else
expect(error.message).toContain('something is not defined'); expect(error!.message).toContain('something is not defined');
await context.close(); await context.close();
} }
@ -240,7 +241,7 @@ it('should work with offline option', async ({ browser, server }) => {
expect(error).toBeTruthy(); expect(error).toBeTruthy();
await context.setOffline(false); await context.setOffline(false);
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(200); expect(response!.status()).toBe(200);
await context.close(); await context.close();
}); });

View File

@ -32,7 +32,7 @@ it('should fail without credentials', async ({ browser, server, isChromiumHeaded
const page = await context.newPage(); const page = await context.newPage();
try { try {
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(401); expect(response!.status()).toBe(401);
} finally { } finally {
await context.close(); await context.close();
} }
@ -45,10 +45,10 @@ it('should work with setHTTPCredentials', async ({ browser, server, isChromiumHe
const context = await browser.newContext(); const context = await browser.newContext();
const page = await context.newPage(); const page = await context.newPage();
let response = await page.goto(server.EMPTY_PAGE); let response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(401); expect(response!.status()).toBe(401);
await context.setHTTPCredentials({ username: 'user', password: 'pass' }); await context.setHTTPCredentials({ username: 'user', password: 'pass' });
response = await page.reload(); response = await page.reload();
expect(response.status()).toBe(200); expect(response!.status()).toBe(200);
await context.close(); await context.close();
}); });
@ -59,7 +59,7 @@ it('should work with correct credentials @smoke', async ({ browser, server }) =>
}); });
const page = await context.newPage(); const page = await context.newPage();
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(200); expect(response!.status()).toBe(200);
await context.close(); await context.close();
}); });
@ -70,7 +70,7 @@ it('should fail with wrong credentials', async ({ browser, server }) => {
}); });
const page = await context.newPage(); const page = await context.newPage();
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(401); expect(response!.status()).toBe(401);
await context.close(); await context.close();
}); });
@ -81,9 +81,9 @@ it('should return resource body', async ({ browser, server }) => {
}); });
const page = await context.newPage(); const page = await context.newPage();
const response = await page.goto(server.PREFIX + '/playground.html'); const response = await page.goto(server.PREFIX + '/playground.html');
expect(response.status()).toBe(200); expect(response!.status()).toBe(200);
expect(await page.title()).toBe('Playground'); expect(await page.title()).toBe('Playground');
expect((await response.body()).toString()).toContain('Playground'); expect((await response!.body()).toString()).toContain('Playground');
await context.close(); await context.close();
}); });
@ -94,7 +94,7 @@ it('should work with correct credentials and matching origin', async ({ browser,
}); });
const page = await context.newPage(); const page = await context.newPage();
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(200); expect(response!.status()).toBe(200);
await context.close(); await context.close();
}); });
@ -105,7 +105,7 @@ it('should work with correct credentials and matching origin case insensitive',
}); });
const page = await context.newPage(); const page = await context.newPage();
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(200); expect(response!.status()).toBe(200);
await context.close(); await context.close();
}); });
@ -117,7 +117,7 @@ it('should fail with correct credentials and mismatching scheme', async ({ brows
}); });
const page = await context.newPage(); const page = await context.newPage();
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(401); expect(response!.status()).toBe(401);
await context.close(); await context.close();
}); });
@ -131,7 +131,7 @@ it('should fail with correct credentials and mismatching hostname', async ({ bro
}); });
const page = await context.newPage(); const page = await context.newPage();
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(401); expect(response!.status()).toBe(401);
await context.close(); await context.close();
}); });
@ -144,6 +144,6 @@ it('should fail with correct credentials and mismatching port', async ({ browser
}); });
const page = await context.newPage(); const page = await context.newPage();
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.status()).toBe(401); expect(response!.status()).toBe(401);
await context.close(); await context.close();
}); });

View File

@ -36,8 +36,8 @@ it.describe('device', () => {
const page = await context.newPage(); const page = await context.newPage();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
const button = await page.$('button'); const button = await page.$('button');
await page.evaluate(button => button.style.marginTop = '200px', button); await page.evaluate(button => button!.style.marginTop = '200px', button);
await button.click(); await button!.click();
expect(await page.evaluate('result')).toBe('Clicked'); expect(await page.evaluate('result')).toBe('Clicked');
await context.close(); await context.close();
}); });
@ -54,8 +54,8 @@ it.describe('device', () => {
const page = await context.newPage(); const page = await context.newPage();
await page.goto(server.PREFIX + '/input/scrollable.html'); await page.goto(server.PREFIX + '/input/scrollable.html');
const element = await page.$('#button-91'); const element = await page.$('#button-91');
await element.click(); await element!.click();
expect(await element.textContent()).toBe('clicked'); expect(await element!.textContent()).toBe('clicked');
await context.close(); await context.close();
}); });

View File

@ -45,7 +45,7 @@ test('console event should work in popup 2', async ({ page, browserName }) => {
const [, message, popup] = await Promise.all([ const [, message, popup] = await Promise.all([
page.evaluate(async () => { page.evaluate(async () => {
const win = window.open('javascript:console.log("hello")'); const win = window.open('javascript:console.log("hello")')!;
await new Promise(f => setTimeout(f, 0)); await new Promise(f => setTimeout(f, 0));
win.close(); win.close();
}), }),
@ -62,7 +62,7 @@ test('console event should work in immediately closed popup', async ({ page, bro
const [, message, popup] = await Promise.all([ const [, message, popup] = await Promise.all([
page.evaluate(async () => { page.evaluate(async () => {
const win = window.open(); const win = window.open()!;
(win as any).console.log('hello'); (win as any).console.log('hello');
win.close(); win.close();
}), }),
@ -122,7 +122,7 @@ test('dialog event should work in popup 2', async ({ page, browserName }) => {
test('dialog event should work in immediately closed popup', async ({ page }) => { test('dialog event should work in immediately closed popup', async ({ page }) => {
const promise = page.evaluate(async () => { const promise = page.evaluate(async () => {
const win = window.open(); const win = window.open()!;
const result = (win as any).prompt('hey?'); const result = (win as any).prompt('hey?');
win.close(); win.close();
return result; return result;

View File

@ -16,9 +16,10 @@
*/ */
import { contextTest as it, expect } from '../config/browserTest'; import { contextTest as it, expect } from '../config/browserTest';
import type { JSHandle } from '@playwright/test';
it('expose binding should work', async ({ context }) => { it('expose binding should work', async ({ context }) => {
let bindingSource; let bindingSource: any;
await context.exposeBinding('add', (source, a, b) => { await context.exposeBinding('add', (source, a, b) => {
bindingSource = source; bindingSource = source;
return a + b; return a + b;
@ -32,10 +33,10 @@ it('expose binding should work', async ({ context }) => {
}); });
it('should work', async ({ context, server }) => { it('should work', async ({ context, server }) => {
await context.exposeFunction('add', (a, b) => a + b); await context.exposeFunction('add', (a: number, b: number) => a + b);
const page = await context.newPage(); const page = await context.newPage();
await page.exposeFunction('mul', (a, b) => a * b); await page.exposeFunction('mul', (a: number, b: number) => a * b);
await context.exposeFunction('sub', (a, b) => a - b); await context.exposeFunction('sub', (a: number, b: number) => a - b);
await context.exposeBinding('addHandle', async ({ frame }, a, b) => { await context.exposeBinding('addHandle', async ({ frame }, a, b) => {
const handle = await frame.evaluateHandle(([a, b]) => a + b, [a, b]); const handle = await frame.evaluateHandle(([a, b]) => a + b, [a, b]);
return handle; return handle;
@ -58,8 +59,8 @@ it('should throw for duplicate registrations', async ({ context, server }) => {
}); });
it('should be callable from-inside addInitScript', async ({ context, server }) => { it('should be callable from-inside addInitScript', async ({ context, server }) => {
let args = []; let args: string[] = [];
await context.exposeFunction('woof', function(arg) { await context.exposeFunction('woof', function(arg: string) {
args.push(arg); args.push(arg);
}); });
await context.addInitScript('window["woof"]("context")'); await context.addInitScript('window["woof"]("context")');
@ -73,14 +74,14 @@ it('should be callable from-inside addInitScript', async ({ context, server }) =
}); });
it('exposeBindingHandle should work', async ({ context }) => { it('exposeBindingHandle should work', async ({ context }) => {
let target; let target!: JSHandle<any>;
await context.exposeBinding('logme', (source, t) => { await context.exposeBinding('logme', (source, t) => {
target = t; target = t;
return 17; return 17;
}, { handle: true }); }, { handle: true });
const page = await context.newPage(); const page = await context.newPage();
const result = await page.evaluate(async function() { const result = await page.evaluate(async function() {
return window['logme']({ foo: 42 }); return (window as any)['logme']({ foo: 42 });
}); });
expect(await target.evaluate(x => x.foo)).toBe(42); expect(await target.evaluate(x => x.foo)).toBe(42);
expect(result).toEqual(17); expect(result).toEqual(17);

View File

@ -134,7 +134,7 @@ for (const method of ['fetch', 'delete', 'get', 'head', 'patch', 'post', 'put']
} }
}), }),
]); ]);
const params = new URLSearchParams(request.url.substr(request.url.indexOf('?'))); const params = new URLSearchParams(request.url!.substr(request.url!.indexOf('?')));
expect(params.get('p1')).toEqual('v1'); expect(params.get('p1')).toEqual('v1');
expect(params.get('парам2')).toEqual('знач2'); expect(params.get('парам2')).toEqual('знач2');
}); });
@ -337,7 +337,7 @@ it('should handle cookies on redirects', async ({ context, server, browserName,
context.request.get(`${server.PREFIX}/redirect1`), context.request.get(`${server.PREFIX}/redirect1`),
]); ]);
expect(req1.headers.cookie).toBe('r1=v1'); expect(req1.headers.cookie).toBe('r1=v1');
expect(req2.headers.cookie.split(';').map(s => s.trim()).sort()).toEqual(['r1=v1', 'r2=v2']); expect(req2.headers.cookie!.split(';').map(s => s.trim()).sort()).toEqual(['r1=v1', 'r2=v2']);
expect(req3.headers.cookie).toBe('r1=v1'); expect(req3.headers.cookie).toBe('r1=v1');
} }
const cookies = await context.cookies(); const cookies = await context.cookies();
@ -369,7 +369,7 @@ it('should return raw headers', async ({ context, page, server }) => {
server.setRoute('/headers', (req, res) => { server.setRoute('/headers', (req, res) => {
// Headers array is only supported since Node v14.14.0 so we write directly to the socket. // Headers array is only supported since Node v14.14.0 so we write directly to the socket.
// res.writeHead(200, ['name-a', 'v1','name-b', 'v4','Name-a', 'v2', 'name-A', 'v3']); // res.writeHead(200, ['name-a', 'v1','name-b', 'v4','Name-a', 'v2', 'name-A', 'v3']);
const conn = res.connection; const conn = res.connection!;
conn.write('HTTP/1.1 200 OK\r\n'); conn.write('HTTP/1.1 200 OK\r\n');
conn.write('Name-A: v1\r\n'); conn.write('Name-A: v1\r\n');
conn.write('name-b: v4\r\n'); conn.write('name-b: v4\r\n');
@ -773,7 +773,7 @@ it('should throw on a redirect with an invalid URL', async ({ context, server })
server.setRedirect('/redirect', '/test'); server.setRedirect('/redirect', '/test');
server.setRoute('/test', (req, res) => { server.setRoute('/test', (req, res) => {
// Node.js prevents us from responding with an invalid header, therefore we manually write the response. // Node.js prevents us from responding with an invalid header, therefore we manually write the response.
const conn = res.connection; const conn = res.connection!;
conn.write('HTTP/1.1 302\r\n'); conn.write('HTTP/1.1 302\r\n');
conn.write('Location: https://здравствуйте/\r\n'); conn.write('Location: https://здравствуйте/\r\n');
conn.write('\r\n'); conn.write('\r\n');
@ -1029,7 +1029,7 @@ it('should accept bool and numeric params', async ({ page, server }) => {
'bool2': false, 'bool2': false,
} }
}); });
const params = new URLSearchParams(request.url.substr(request.url.indexOf('?'))); const params = new URLSearchParams(request!.url.substr(request!.url.indexOf('?')));
expect(params.get('str')).toEqual('s'); expect(params.get('str')).toEqual('s');
expect(params.get('num')).toEqual('10'); expect(params.get('num')).toEqual('10');
expect(params.get('bool')).toEqual('true'); expect(params.get('bool')).toEqual('true');

View File

@ -151,7 +151,7 @@ it('should change document URL after redirected navigation', async ({ context, a
page.goto('https://theverge.com/') page.goto('https://theverge.com/')
]); ]);
await expect(page).toHaveURL('https://www.theverge.com/'); await expect(page).toHaveURL('https://www.theverge.com/');
expect(response.request().url()).toBe('https://www.theverge.com/'); expect(response!.request().url()).toBe('https://www.theverge.com/');
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/'); expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
}); });
@ -166,7 +166,7 @@ it('should change document URL after redirected navigation on click', async ({ s
page.click('text=click me'), page.click('text=click me'),
]); ]);
await expect(page).toHaveURL('https://www.theverge.com/'); await expect(page).toHaveURL('https://www.theverge.com/');
expect(response.request().url()).toBe('https://www.theverge.com/'); expect(response!.request().url()).toBe('https://www.theverge.com/');
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/'); expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
}); });
@ -179,7 +179,7 @@ it('should goBack to redirected navigation', async ({ context, asset, server })
await expect(page).toHaveURL(server.EMPTY_PAGE); await expect(page).toHaveURL(server.EMPTY_PAGE);
const response = await page.goBack(); const response = await page.goBack();
await expect(page).toHaveURL('https://www.theverge.com/'); await expect(page).toHaveURL('https://www.theverge.com/');
expect(response.request().url()).toBe('https://www.theverge.com/'); expect(response!.request().url()).toBe('https://www.theverge.com/');
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/'); expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
}); });
@ -195,7 +195,7 @@ it('should goForward to redirected navigation', async ({ context, asset, server,
await expect(page).toHaveURL(server.EMPTY_PAGE); await expect(page).toHaveURL(server.EMPTY_PAGE);
const response = await page.goForward(); const response = await page.goForward();
await expect(page).toHaveURL('https://www.theverge.com/'); await expect(page).toHaveURL('https://www.theverge.com/');
expect(response.request().url()).toBe('https://www.theverge.com/'); expect(response!.request().url()).toBe('https://www.theverge.com/');
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/'); expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
}); });
@ -207,7 +207,7 @@ it('should reload redirected navigation', async ({ context, asset, server }) =>
await expect(page).toHaveURL('https://www.theverge.com/'); await expect(page).toHaveURL('https://www.theverge.com/');
const response = await page.reload(); const response = await page.reload();
await expect(page).toHaveURL('https://www.theverge.com/'); await expect(page).toHaveURL('https://www.theverge.com/');
expect(response.request().url()).toBe('https://www.theverge.com/'); expect(response!.request().url()).toBe('https://www.theverge.com/');
expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/'); expect(await page.evaluate(() => location.href)).toBe('https://www.theverge.com/');
}); });

View File

@ -16,10 +16,11 @@
*/ */
import { browserTest as it, expect } from '../config/browserTest'; import { browserTest as it, expect } from '../config/browserTest';
import type { Request, Response } from '@playwright/test';
it('BrowserContext.Events.Request', async ({ context, server }) => { it('BrowserContext.Events.Request', async ({ context, server }) => {
const page = await context.newPage(); const page = await context.newPage();
const requests = []; const requests: Request[] = [];
context.on('request', request => requests.push(request)); context.on('request', request => requests.push(request));
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>'); await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>');
@ -38,7 +39,7 @@ it('BrowserContext.Events.Request', async ({ context, server }) => {
it('BrowserContext.Events.Response', async ({ context, server }) => { it('BrowserContext.Events.Response', async ({ context, server }) => {
const page = await context.newPage(); const page = await context.newPage();
const responses = []; const responses: Response[] = [];
context.on('response', response => responses.push(response)); context.on('response', response => responses.push(response));
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>'); await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>');
@ -58,10 +59,10 @@ it('BrowserContext.Events.Response', async ({ context, server }) => {
it('BrowserContext.Events.RequestFailed', async ({ context, server }) => { it('BrowserContext.Events.RequestFailed', async ({ context, server }) => {
server.setRoute('/one-style.css', (_, res) => { server.setRoute('/one-style.css', (_, res) => {
res.setHeader('Content-Type', 'text/css'); res.setHeader('Content-Type', 'text/css');
res.connection.destroy(); res.connection!.destroy();
}); });
const page = await context.newPage(); const page = await context.newPage();
const failedRequests = []; const failedRequests: Request[] = [];
context.on('requestfailed', request => failedRequests.push(request)); context.on('requestfailed', request => failedRequests.push(request));
await page.goto(server.PREFIX + '/one-style.html'); await page.goto(server.PREFIX + '/one-style.html');
expect(failedRequests.length).toBe(1); expect(failedRequests.length).toBe(1);
@ -78,7 +79,7 @@ it('BrowserContext.Events.RequestFinished', async ({ context, server }) => {
page.goto(server.EMPTY_PAGE), page.goto(server.EMPTY_PAGE),
context.waitForEvent('requestfinished') context.waitForEvent('requestfinished')
]); ]);
const request = response.request(); const request = response!.request();
expect(request.url()).toBe(server.EMPTY_PAGE); expect(request.url()).toBe(server.EMPTY_PAGE);
expect(await request.response()).toBeTruthy(); expect(await request.response()).toBeTruthy();
expect(request.frame() === page.mainFrame()).toBe(true); expect(request.frame() === page.mainFrame()).toBe(true);
@ -88,7 +89,7 @@ it('BrowserContext.Events.RequestFinished', async ({ context, server }) => {
it('should fire events in proper order', async ({ context, server }) => { it('should fire events in proper order', async ({ context, server }) => {
const page = await context.newPage(); const page = await context.newPage();
const events = []; const events: string[] = [];
context.on('request', () => events.push('request')); context.on('request', () => events.push('request'));
context.on('response', () => events.push('response')); context.on('response', () => events.push('response'));
context.on('requestfinished', () => events.push('requestfinished')); context.on('requestfinished', () => events.push('requestfinished'));
@ -127,7 +128,7 @@ it('should not fire events for favicon or favicon redirects', async ({ context,
`); `);
}); });
const events = []; const events: string[] = [];
context.on('request', req => events.push(req.url())); context.on('request', req => events.push(req.url()));
context.on('response', res => events.push(res.url())); context.on('response', res => events.push(res.url()));
context.on('requestfinished', req => events.push(req.url())); context.on('requestfinished', req => events.push(req.url()));

View File

@ -39,7 +39,7 @@ it('frame.focus should work multiple times', async ({ contextFactory }) => {
for (const page of [page1, page2]) { for (const page of [page1, page2]) {
await page.setContent(`<button id="foo" onfocus="window.gotFocus=true"></button>`); await page.setContent(`<button id="foo" onfocus="window.gotFocus=true"></button>`);
await page.focus('#foo'); await page.focus('#foo');
expect(await page.evaluate(() => !!window['gotFocus'])).toBe(true); expect(await page.evaluate(() => !!(window as any)['gotFocus'])).toBe(true);
} }
}); });
@ -74,8 +74,8 @@ it('should click the button with deviceScaleFactor set', async ({ browser, serve
await attachFrame(page, 'button-test', server.PREFIX + '/input/button.html'); await attachFrame(page, 'button-test', server.PREFIX + '/input/button.html');
const frame = page.frames()[1]; const frame = page.frames()[1];
const button = await frame.$('button'); const button = await frame.$('button');
await button.click(); await button!.click();
expect(await frame.evaluate(() => window['result'])).toBe('Clicked'); expect(await frame.evaluate(() => (window as any)['result'])).toBe('Clicked');
await context.close(); await context.close();
}); });
@ -91,7 +91,7 @@ it('should click the button with offset with page scale', async ({ browser, serv
}); });
await page.click('button', { position: { x: 20, y: 10 } }); await page.click('button', { position: { x: 20, y: 10 } });
expect(await page.evaluate('result')).toBe('Clicked'); expect(await page.evaluate('result')).toBe('Clicked');
const expectCloseTo = (expected, actual) => { const expectCloseTo = (expected: number, actual: number) => {
if (Math.abs(expected - actual) > 2) if (Math.abs(expected - actual) > 2)
throw new Error(`Expected: ${expected}, received: ${actual}`); throw new Error(`Expected: ${expected}, received: ${actual}`);
}; };
@ -108,7 +108,7 @@ it('should return bounding box with page scale', async ({ browser, server, brows
const context = await browser.newContext({ viewport: { width: 400, height: 400 }, isMobile: true }); const context = await browser.newContext({ viewport: { width: 400, height: 400 }, isMobile: true });
const page = await context.newPage(); const page = await context.newPage();
await page.goto(server.PREFIX + '/input/button.html'); await page.goto(server.PREFIX + '/input/button.html');
const button = await page.$('button'); const button = (await page.$('button'))!;
await button.evaluate(button => { await button.evaluate(button => {
document.body.style.margin = '0'; document.body.style.margin = '0';
button.style.borderWidth = '0'; button.style.borderWidth = '0';
@ -117,7 +117,7 @@ it('should return bounding box with page scale', async ({ browser, server, brows
button.style.marginLeft = '17px'; button.style.marginLeft = '17px';
button.style.marginTop = '23px'; button.style.marginTop = '23px';
}); });
const box = await button.boundingBox(); const box = (await button.boundingBox())!;
expect(Math.round(box.x * 100)).toBe(17 * 100); expect(Math.round(box.x * 100)).toBe(17 * 100);
expect(Math.round(box.y * 100)).toBe(23 * 100); expect(Math.round(box.y * 100)).toBe(23 * 100);
expect(Math.round(box.width * 100)).toBe(200 * 100); expect(Math.round(box.width * 100)).toBe(200 * 100);
@ -130,7 +130,7 @@ it('should not leak listeners during navigation of 20 pages', async ({ contextFa
const context = await contextFactory(); const context = await contextFactory();
let warning = null; let warning = null;
const warningHandler = w => warning = w; const warningHandler = (w: string) => warning = w;
process.on('warning', warningHandler); process.on('warning', warningHandler);
const pages = await Promise.all([...Array(20)].map(() => context.newPage())); const pages = await Promise.all([...Array(20)].map(() => context.newPage()));
await Promise.all(pages.map(page => page.goto(server.EMPTY_PAGE))); await Promise.all(pages.map(page => page.goto(server.EMPTY_PAGE)));

View File

@ -16,6 +16,7 @@
*/ */
import { browserTest as it, expect } from '../config/browserTest'; import { browserTest as it, expect } from '../config/browserTest';
import type { Route } from '@playwright/test';
it('should intercept', async ({ browser, server }) => { it('should intercept', async ({ browser, server }) => {
const context = await browser.newContext(); const context = await browser.newContext();
@ -35,7 +36,7 @@ it('should intercept', async ({ browser, server }) => {
}); });
const page = await context.newPage(); const page = await context.newPage();
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.ok()).toBe(true); expect(response!.ok()).toBe(true);
expect(intercepted).toBe(true); expect(intercepted).toBe(true);
await context.close(); await context.close();
}); });
@ -44,7 +45,7 @@ it('should unroute', async ({ browser, server }) => {
const context = await browser.newContext(); const context = await browser.newContext();
const page = await context.newPage(); const page = await context.newPage();
let intercepted = []; let intercepted: number[] = [];
await context.route('**/*', route => { await context.route('**/*', route => {
intercepted.push(1); intercepted.push(1);
void route.fallback(); void route.fallback();
@ -57,7 +58,7 @@ it('should unroute', async ({ browser, server }) => {
intercepted.push(3); intercepted.push(3);
void route.fallback(); void route.fallback();
}); });
const handler4 = route => { const handler4 = (route: Route) => {
intercepted.push(4); intercepted.push(4);
void route.fallback(); void route.fallback();
}; };
@ -87,7 +88,7 @@ it('should yield to page.route', async ({ browser, server }) => {
await page.route('**/empty.html', route => { await page.route('**/empty.html', route => {
void route.fulfill({ status: 200, body: 'page' }); void route.fulfill({ status: 200, body: 'page' });
}); });
const response = await page.goto(server.EMPTY_PAGE); const response = (await page.goto(server.EMPTY_PAGE))!;
expect(response.ok()).toBe(true); expect(response.ok()).toBe(true);
expect(await response.text()).toBe('page'); expect(await response.text()).toBe('page');
await context.close(); await context.close();
@ -102,7 +103,7 @@ it('should fall back to context.route', async ({ browser, server }) => {
await page.route('**/non-empty.html', route => { await page.route('**/non-empty.html', route => {
void route.fulfill({ status: 200, body: 'page' }); void route.fulfill({ status: 200, body: 'page' });
}); });
const response = await page.goto(server.EMPTY_PAGE); const response = (await page.goto(server.EMPTY_PAGE))!;
expect(response.ok()).toBe(true); expect(response.ok()).toBe(true);
expect(await response.text()).toBe('context'); expect(await response.text()).toBe('context');
await context.close(); await context.close();
@ -178,7 +179,7 @@ it('should use Set-Cookie header in future requests', async ({ contextFactory, s
let cookie = ''; let cookie = '';
server.setRoute('/foo.html', (req, res) => { server.setRoute('/foo.html', (req, res) => {
cookie = req.headers.cookie; cookie = req.headers.cookie!;
res.end(); res.end();
}); });
await page.goto(server.PREFIX + '/foo.html'); await page.goto(server.PREFIX + '/foo.html');
@ -191,12 +192,12 @@ it('should work with ignoreHTTPSErrors', async ({ browser, httpsServer }) => {
await page.route('**/*', route => route.continue()); await page.route('**/*', route => route.continue());
const response = await page.goto(httpsServer.EMPTY_PAGE); const response = await page.goto(httpsServer.EMPTY_PAGE);
expect(response.status()).toBe(200); expect(response!.status()).toBe(200);
await context.close(); await context.close();
}); });
it('should support the times parameter with route matching', async ({ context, page, server }) => { it('should support the times parameter with route matching', async ({ context, page, server }) => {
const intercepted = []; const intercepted: number[] = [];
await context.route('**/empty.html', route => { await context.route('**/empty.html', route => {
intercepted.push(1); intercepted.push(1);
void route.continue(); void route.continue();
@ -247,7 +248,7 @@ it('should overwrite post body with empty string', async ({ context, server, pag
}); });
it('should chain fallback', async ({ context, page, server }) => { it('should chain fallback', async ({ context, page, server }) => {
const intercepted = []; const intercepted: number[] = [];
await context.route('**/empty.html', route => { await context.route('**/empty.html', route => {
intercepted.push(1); intercepted.push(1);
void route.fallback(); void route.fallback();
@ -265,7 +266,7 @@ it('should chain fallback', async ({ context, page, server }) => {
}); });
it('should chain fallback w/ dynamic URL', async ({ context, page, server }) => { it('should chain fallback w/ dynamic URL', async ({ context, page, server }) => {
const intercepted = []; const intercepted: number[] = [];
await context.route('**/bar', route => { await context.route('**/bar', route => {
intercepted.push(1); intercepted.push(1);
void route.fallback({ url: server.EMPTY_PAGE }); void route.fallback({ url: server.EMPTY_PAGE });
@ -296,7 +297,7 @@ it('should not chain fulfill', async ({ context, page, server }) => {
void route.fallback(); void route.fallback();
}); });
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
const body = await response.body(); const body = await response!.body();
expect(body.toString()).toEqual('fulfilled'); expect(body.toString()).toEqual('fulfilled');
expect(failed).toBeFalsy(); expect(failed).toBeFalsy();
}); });
@ -318,7 +319,7 @@ it('should not chain abort', async ({ context, page, server }) => {
}); });
it('should chain fallback into page', async ({ context, page, server }) => { it('should chain fallback into page', async ({ context, page, server }) => {
const intercepted = []; const intercepted: number[] = [];
await context.route('**/empty.html', route => { await context.route('**/empty.html', route => {
intercepted.push(1); intercepted.push(1);
void route.fallback(); void route.fallback();
@ -348,7 +349,7 @@ it('should chain fallback into page', async ({ context, page, server }) => {
}); });
it('should fall back async', async ({ page, context, server }) => { it('should fall back async', async ({ page, context, server }) => {
const intercepted = []; const intercepted: number[] = [];
await context.route('**/empty.html', async route => { await context.route('**/empty.html', async route => {
intercepted.push(1); intercepted.push(1);
await new Promise(r => setTimeout(r, 100)); await new Promise(r => setTimeout(r, 100));

View File

@ -41,7 +41,7 @@ it.describe('mobile viewport', () => {
await context.close(); await context.close();
function dispatchTouch() { function dispatchTouch() {
let fulfill; let fulfill!: (s: string) => void;
const promise = new Promise(x => fulfill = x); const promise = new Promise(x => fulfill = x);
window.ontouchstart = function(e) { window.ontouchstart = function(e) {
fulfill('Received touch'); fulfill('Received touch');
@ -59,7 +59,7 @@ it.describe('mobile viewport', () => {
const context = await browser.newContext({ ...iPhone }); const context = await browser.newContext({ ...iPhone });
const page = await context.newPage(); const page = await context.newPage();
await page.goto(server.PREFIX + '/detect-touch.html'); await page.goto(server.PREFIX + '/detect-touch.html');
expect(await page.evaluate(() => document.body.textContent.trim())).toBe('YES'); expect(await page.evaluate(() => document.body.textContent!.trim())).toBe('YES');
await context.close(); await context.close();
}); });
@ -68,7 +68,7 @@ it.describe('mobile viewport', () => {
const page = await context.newPage(); const page = await context.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.addScriptTag({ url: server.PREFIX + '/modernizr.js' }); await page.addScriptTag({ url: server.PREFIX + '/modernizr.js' });
expect(await page.evaluate(() => window['Modernizr'].touchevents)).toBe(true); expect(await page.evaluate(() => (window as any)['Modernizr'].touchevents)).toBe(true);
await context.close(); await context.close();
}); });
@ -164,7 +164,7 @@ it.describe('mobile viewport', () => {
await page.goto(server.CROSS_PROCESS_PREFIX + '/mobile.html'); await page.goto(server.CROSS_PROCESS_PREFIX + '/mobile.html');
await page.evaluate(() => { await page.evaluate(() => {
document.addEventListener('click', event => { document.addEventListener('click', event => {
window['result'] = { x: event.clientX, y: event.clientY }; (window as any)['result'] = { x: event.clientX, y: event.clientY };
}); });
}); });
@ -224,7 +224,7 @@ it.describe('mobile viewport', () => {
}); });
await page.goto('http://localhost/button.html'); await page.goto('http://localhost/button.html');
await page.getByText('Click me').click({ force: true }); await page.getByText('Click me').click({ force: true });
const box = await page.locator('button').boundingBox(); const box = (await page.locator('button').boundingBox())!;
const clicks = await page.evaluate(() => (window as any).clicks); const clicks = await page.evaluate(() => (window as any).clicks);
expect(clicks.length).toBe(1); expect(clicks.length).toBe(1);
const [{ x, y }] = clicks; const [{ x, y }] = clicks;

View File

@ -15,6 +15,7 @@
*/ */
import { contextTest as it, expect } from '../../config/browserTest'; import { contextTest as it, expect } from '../../config/browserTest';
import type { Frame, Browser } from '@playwright/test';
it.use({ it.use({
launchOptions: async ({ launchOptions }, use) => { launchOptions: async ({ launchOptions }, use) => {
@ -37,7 +38,7 @@ it('should handle oopif detach', async function({ page, browser, server }) {
expect(await frame.evaluate(() => '' + location.href)).toBe(server.CROSS_PROCESS_PREFIX + '/grid.html'); expect(await frame.evaluate(() => '' + location.href)).toBe(server.CROSS_PROCESS_PREFIX + '/grid.html');
const [detachedFrame] = await Promise.all([ const [detachedFrame] = await Promise.all([
page.waitForEvent('framedetached'), page.waitForEvent('framedetached'),
page.evaluate(() => document.querySelector('iframe').remove()), page.evaluate(() => document.querySelector('iframe')!.remove()),
]); ]);
expect(detachedFrame).toBe(frame); expect(detachedFrame).toBe(frame);
}); });
@ -87,9 +88,9 @@ it('should expose function', async ({ page, browser, server }) => {
expect(page.frames().length).toBe(2); expect(page.frames().length).toBe(2);
expect(await countOOPIFs(browser)).toBe(1); expect(await countOOPIFs(browser)).toBe(1);
const oopif = page.frames()[1]; const oopif = page.frames()[1];
await page.exposeFunction('mul', (a, b) => a * b); await page.exposeFunction('mul', (a: number, b: number) => a * b);
const result = await oopif.evaluate(async function() { const result = await oopif.evaluate(async function() {
return await window['mul'](9, 4); return await (window as any)['mul'](9, 4);
}); });
expect(result).toBe(36); expect(result).toBe(36);
}); });
@ -163,9 +164,9 @@ it('should load oopif iframes with subresources and route', async function({ pag
}); });
it('should report main requests', async function({ page, browser, server }) { it('should report main requests', async function({ page, browser, server }) {
const requestFrames = []; const requestFrames: Frame[] = [];
page.on('request', r => requestFrames.push(r.frame())); page.on('request', r => requestFrames.push(r.frame()));
const finishedFrames = []; const finishedFrames: Frame[] = [];
page.on('requestfinished', r => finishedFrames.push(r.frame())); page.on('requestfinished', r => finishedFrames.push(r.frame()));
await page.goto(server.PREFIX + '/empty.html'); await page.goto(server.PREFIX + '/empty.html');
@ -201,34 +202,34 @@ it('should report main requests', async function({ page, browser, server }) {
}); });
it('should support exposeFunction', async function({ page, browser, server }) { it('should support exposeFunction', async function({ page, browser, server }) {
await page.context().exposeFunction('dec', a => a - 1); await page.context().exposeFunction('dec', (a: number) => a - 1);
await page.exposeFunction('inc', a => a + 1); await page.exposeFunction('inc', (a: number) => a + 1);
await page.goto(server.PREFIX + '/dynamic-oopif.html'); await page.goto(server.PREFIX + '/dynamic-oopif.html');
expect(await countOOPIFs(browser)).toBe(1); expect(await countOOPIFs(browser)).toBe(1);
expect(page.frames().length).toBe(2); expect(page.frames().length).toBe(2);
expect(await page.frames()[0].evaluate(() => window['inc'](3))).toBe(4); expect(await page.frames()[0].evaluate(() => (window as any)['inc'](3))).toBe(4);
expect(await page.frames()[1].evaluate(() => window['inc'](4))).toBe(5); expect(await page.frames()[1].evaluate(() => (window as any)['inc'](4))).toBe(5);
expect(await page.frames()[0].evaluate(() => window['dec'](3))).toBe(2); expect(await page.frames()[0].evaluate(() => (window as any)['dec'](3))).toBe(2);
expect(await page.frames()[1].evaluate(() => window['dec'](4))).toBe(3); expect(await page.frames()[1].evaluate(() => (window as any)['dec'](4))).toBe(3);
}); });
it('should support addInitScript', async function({ page, browser, server }) { it('should support addInitScript', async function({ page, browser, server }) {
await page.context().addInitScript(() => window['bar'] = 17); await page.context().addInitScript(() => (window as any)['bar'] = 17);
await page.addInitScript(() => window['foo'] = 42); await page.addInitScript(() => (window as any)['foo'] = 42);
await page.goto(server.PREFIX + '/dynamic-oopif.html'); await page.goto(server.PREFIX + '/dynamic-oopif.html');
expect(await countOOPIFs(browser)).toBe(1); expect(await countOOPIFs(browser)).toBe(1);
expect(page.frames().length).toBe(2); expect(page.frames().length).toBe(2);
expect(await page.frames()[0].evaluate(() => window['foo'])).toBe(42); expect(await page.frames()[0].evaluate(() => (window as any)['foo'])).toBe(42);
expect(await page.frames()[1].evaluate(() => window['foo'])).toBe(42); expect(await page.frames()[1].evaluate(() => (window as any)['foo'])).toBe(42);
expect(await page.frames()[0].evaluate(() => window['bar'])).toBe(17); expect(await page.frames()[0].evaluate(() => (window as any)['bar'])).toBe(17);
expect(await page.frames()[1].evaluate(() => window['bar'])).toBe(17); expect(await page.frames()[1].evaluate(() => (window as any)['bar'])).toBe(17);
}); });
// @see https://github.com/microsoft/playwright/issues/1240 // @see https://github.com/microsoft/playwright/issues/1240
it('should click a button when it overlays oopif', async function({ page, browser, server }) { it('should click a button when it overlays oopif', async function({ page, browser, server }) {
await page.goto(server.PREFIX + '/button-overlay-oopif.html'); await page.goto(server.PREFIX + '/button-overlay-oopif.html');
expect(await countOOPIFs(browser)).toBe(1); expect(await countOOPIFs(browser)).toBe(1);
await page.click('button'); await page.click('button');
expect(await page.evaluate(() => window['BUTTON_CLICKED'])).toBe(true); expect(await page.evaluate(() => (window as any)['BUTTON_CLICKED'])).toBe(true);
}); });
it('should report google.com frame with headed', async ({ browserType, server }) => { it('should report google.com frame with headed', async ({ browserType, server }) => {
@ -268,7 +269,7 @@ it('ElementHandle.boundingBox() should work', async function({ page, browser, se
expect(await countOOPIFs(browser)).toBe(1); expect(await countOOPIFs(browser)).toBe(1);
const handle1 = await page.frames()[1].$('.box:nth-of-type(13)'); const handle1 = await page.frames()[1].$('.box:nth-of-type(13)');
expect(await handle1.boundingBox()).toEqual({ x: 100 + 42, y: 50 + 17, width: 50, height: 50 }); expect(await handle1!.boundingBox()).toEqual({ x: 100 + 42, y: 50 + 17, width: 50, height: 50 });
await Promise.all([ await Promise.all([
page.frames()[1].waitForNavigation(), page.frames()[1].waitForNavigation(),
@ -276,7 +277,7 @@ it('ElementHandle.boundingBox() should work', async function({ page, browser, se
]); ]);
expect(await countOOPIFs(browser)).toBe(0); expect(await countOOPIFs(browser)).toBe(0);
const handle2 = await page.frames()[1].$('.box:nth-of-type(13)'); const handle2 = await page.frames()[1].$('.box:nth-of-type(13)');
expect(await handle2.boundingBox()).toEqual({ x: 100 + 42, y: 50 + 17, width: 50, height: 50 }); expect(await handle2!.boundingBox()).toEqual({ x: 100 + 42, y: 50 + 17, width: 50, height: 50 });
}); });
it('should click', async function({ page, browser, server }) { it('should click', async function({ page, browser, server }) {
@ -290,10 +291,10 @@ it('should click', async function({ page, browser, server }) {
await page.frames()[1].goto(page.frames()[1].url()); await page.frames()[1].goto(page.frames()[1].url());
expect(await countOOPIFs(browser)).toBe(1); expect(await countOOPIFs(browser)).toBe(1);
const handle1 = await page.frames()[1].$('.box:nth-of-type(13)'); const handle1 = (await page.frames()[1].$('.box:nth-of-type(13)'))!;
await handle1.evaluate(div => div.addEventListener('click', () => window['_clicked'] = true, false)); await handle1.evaluate(div => div.addEventListener('click', () => (window as any)['_clicked'] = true, false));
await handle1.click(); await handle1.click();
expect(await handle1.evaluate(() => window['_clicked'])).toBe(true); expect(await handle1.evaluate(() => (window as any)['_clicked'])).toBe(true);
}); });
it('should allow cdp sessions on oopifs', async function({ page, browser, server }) { it('should allow cdp sessions on oopifs', async function({ page, browser, server }) {
@ -331,7 +332,7 @@ it('should not throw on exposeFunction when oopif detaches', async ({ page, brow
expect(await countOOPIFs(browser)).toBe(1); expect(await countOOPIFs(browser)).toBe(1);
await Promise.all([ await Promise.all([
page.exposeFunction('myFunc', () => 2022), page.exposeFunction('myFunc', () => 2022),
page.evaluate(() => document.querySelector('iframe').remove()), page.evaluate(() => document.querySelector('iframe')!.remove()),
]); ]);
expect(await page.evaluate(() => (window as any).myFunc())).toBe(2022); expect(await page.evaluate(() => (window as any).myFunc())).toBe(2022);
}); });
@ -345,7 +346,7 @@ it('should intercept response body from oopif', async function({ page, browser,
expect(await response.text()).toBeTruthy(); expect(await response.text()).toBeTruthy();
}); });
async function countOOPIFs(browser) { async function countOOPIFs(browser: Browser) {
const browserSession = await browser.newBrowserCDPSession(); const browserSession = await browser.newBrowserCDPSession();
const oopifs = []; const oopifs = [];
browserSession.on('Target.targetCreated', async ({ targetInfo }) => { browserSession.on('Target.targetCreated', async ({ targetInfo }) => {

View File

@ -60,8 +60,8 @@ it('should have browser', async ({ browserName, browser, contextFactory, server
const { page, getLog } = await pageWithHar(contextFactory, testInfo); const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const log = await getLog(); const log = await getLog();
expect(log.browser.name.toLowerCase()).toBe(browserName); expect(log.browser!.name.toLowerCase()).toBe(browserName);
expect(log.browser.version).toBe(browser.version()); expect(log.browser!.version).toBe(browser.version());
}); });
it('should have pages', async ({ contextFactory, server }, testInfo) => { it('should have pages', async ({ contextFactory, server }, testInfo) => {
@ -70,8 +70,8 @@ it('should have pages', async ({ contextFactory, server }, testInfo) => {
// For data: load comes before domcontentloaded... // For data: load comes before domcontentloaded...
await page.waitForLoadState('domcontentloaded'); await page.waitForLoadState('domcontentloaded');
const log = await getLog(); const log = await getLog();
expect(log.pages.length).toBe(1); expect(log.pages!.length).toBe(1);
const pageEntry = log.pages[0]; const pageEntry = log.pages![0];
expect(pageEntry.id).toBeTruthy(); expect(pageEntry.id).toBeTruthy();
expect(pageEntry.title).toBe('Hello'); expect(pageEntry.title).toBe('Hello');
expect(new Date(pageEntry.startedDateTime).valueOf()).toBeGreaterThan(Date.now() - 3600 * 1000); expect(new Date(pageEntry.startedDateTime).valueOf()).toBeGreaterThan(Date.now() - 3600 * 1000);
@ -108,7 +108,7 @@ it('should include request', async ({ contextFactory, server }, testInfo) => {
const log = await getLog(); const log = await getLog();
expect(log.entries.length).toBe(1); expect(log.entries.length).toBe(1);
const entry = log.entries[0]; const entry = log.entries[0];
expect(entry.pageref).toBe(log.pages[0].id); expect(entry.pageref).toBe(log.pages![0].id);
expect(entry.request.url).toBe(server.EMPTY_PAGE); expect(entry.request.url).toBe(server.EMPTY_PAGE);
expect(entry.request.method).toBe('GET'); expect(entry.request.method).toBe('GET');
expect(entry.request.httpVersion).toBe('HTTP/1.1'); expect(entry.request.httpVersion).toBe('HTTP/1.1');
@ -126,7 +126,7 @@ it('should include response', async ({ contextFactory, server }, testInfo) => {
expect(entry.response.statusText).toBe('OK'); expect(entry.response.statusText).toBe('OK');
expect(entry.response.httpVersion).toBe('HTTP/1.1'); expect(entry.response.httpVersion).toBe('HTTP/1.1');
expect(entry.response.headers.length).toBeGreaterThan(1); expect(entry.response.headers.length).toBeGreaterThan(1);
expect(entry.response.headers.find(h => h.name.toLowerCase() === 'content-type').value).toContain('text/html'); expect(entry.response.headers.find(h => h.name.toLowerCase() === 'content-type')!.value).toContain('text/html');
}); });
it('should include redirectURL', async ({ contextFactory, server }, testInfo) => { it('should include redirectURL', async ({ contextFactory, server }, testInfo) => {
@ -223,7 +223,7 @@ it('should include set-cookies', async ({ contextFactory, server }, testInfo) =>
const cookies = log.entries[0].response.cookies; const cookies = log.entries[0].response.cookies;
expect(cookies[0]).toEqual({ name: 'name1', value: 'value1', httpOnly: true }); expect(cookies[0]).toEqual({ name: 'name1', value: 'value1', httpOnly: true });
expect(cookies[1]).toEqual({ name: 'name2', value: '"value2"' }); expect(cookies[1]).toEqual({ name: 'name2', value: '"value2"' });
expect(new Date(cookies[2].expires).valueOf()).toBeGreaterThan(Date.now()); expect(new Date(cookies[2].expires!).valueOf()).toBeGreaterThan(Date.now());
}); });
it('should skip invalid Expires', async ({ contextFactory, server }, testInfo) => { it('should skip invalid Expires', async ({ contextFactory, server }, testInfo) => {
@ -316,7 +316,7 @@ it('should include content @smoke', async ({ contextFactory, server }, testInfo)
expect(log.entries[2].response.content.encoding).toBe('base64'); expect(log.entries[2].response.content.encoding).toBe('base64');
expect(log.entries[2].response.content.mimeType).toBe('image/png'); expect(log.entries[2].response.content.mimeType).toBe('image/png');
expect(Buffer.from(log.entries[2].response.content.text, 'base64').byteLength).toBeGreaterThan(0); expect(Buffer.from(log.entries[2].response.content.text!, 'base64').byteLength).toBeGreaterThan(0);
expect(log.entries[2].response.content.size).toBeGreaterThanOrEqual(6000); expect(log.entries[2].response.content.size).toBeGreaterThanOrEqual(6000);
expect(log.entries[2].response.content.compression).toBe(0); expect(log.entries[2].response.content.compression).toBe(0);
}); });
@ -326,9 +326,9 @@ it('should use attach mode for zip extension', async ({ contextFactory, server }
await page.goto(server.PREFIX + '/har.html'); await page.goto(server.PREFIX + '/har.html');
await page.evaluate(() => fetch('/pptr.png').then(r => r.arrayBuffer())); await page.evaluate(() => fetch('/pptr.png').then(r => r.arrayBuffer()));
const zip = await getZip(); const zip = await getZip();
const log = JSON.parse(zip.get('har.har').toString())['log'] as Log; const log = JSON.parse(zip.get('har.har')!.toString())['log'] as Log;
expect(log.entries[0].response.content.text).toBe(undefined); expect(log.entries[0].response.content.text).toBe(undefined);
expect(zip.get('75841480e2606c03389077304342fac2c58ccb1b.html').toString()).toContain('HAR Page'); expect(zip.get('75841480e2606c03389077304342fac2c58ccb1b.html')!.toString()).toContain('HAR Page');
}); });
it('should omit content', async ({ contextFactory, server }, testInfo) => { it('should omit content', async ({ contextFactory, server }, testInfo) => {
@ -354,7 +354,7 @@ it('should attach content', async ({ contextFactory, server }, testInfo) => {
await page.goto(server.PREFIX + '/har.html'); await page.goto(server.PREFIX + '/har.html');
await page.evaluate(() => fetch('/pptr.png').then(r => r.arrayBuffer())); await page.evaluate(() => fetch('/pptr.png').then(r => r.arrayBuffer()));
const zip = await getZip(); const zip = await getZip();
const log = JSON.parse(zip.get('har.har').toString())['log'] as Log; const log = JSON.parse(zip.get('har.har')!.toString())['log'] as Log;
expect(log.entries[0].response.content.encoding).toBe(undefined); expect(log.entries[0].response.content.encoding).toBe(undefined);
expect(log.entries[0].response.content.mimeType).toBe('text/html; charset=utf-8'); expect(log.entries[0].response.content.mimeType).toBe('text/html; charset=utf-8');
@ -374,9 +374,9 @@ it('should attach content', async ({ contextFactory, server }, testInfo) => {
expect(log.entries[2].response.content.size).toBeGreaterThanOrEqual(6000); expect(log.entries[2].response.content.size).toBeGreaterThanOrEqual(6000);
expect(log.entries[2].response.content.compression).toBe(0); expect(log.entries[2].response.content.compression).toBe(0);
expect(zip.get('75841480e2606c03389077304342fac2c58ccb1b.html').toString()).toContain('HAR Page'); expect(zip.get('75841480e2606c03389077304342fac2c58ccb1b.html')!.toString()).toContain('HAR Page');
expect(zip.get('79f739d7bc88e80f55b9891a22bf13a2b4e18adb.css').toString()).toContain('pink'); expect(zip.get('79f739d7bc88e80f55b9891a22bf13a2b4e18adb.css')!.toString()).toContain('pink');
expect(zip.get('a4c3a18f0bb83f5d9fe7ce561e065c36205762fa.png').byteLength).toBe(log.entries[2].response.content.size); expect(zip.get('a4c3a18f0bb83f5d9fe7ce561e065c36205762fa.png')!.byteLength).toBe(log.entries[2].response.content.size);
}); });
it('should filter by glob', async ({ contextFactory, server }, testInfo) => { it('should filter by glob', async ({ contextFactory, server }, testInfo) => {
@ -422,7 +422,7 @@ it('should work with gzip compression', async ({ contextFactory, server, browser
const { page, getLog } = await pageWithHar(contextFactory, testInfo); const { page, getLog } = await pageWithHar(contextFactory, testInfo);
server.enableGzip('/simplezip.json'); server.enableGzip('/simplezip.json');
const response = await page.goto(server.PREFIX + '/simplezip.json'); const response = await page.goto(server.PREFIX + '/simplezip.json');
expect(response.headers()['content-encoding']).toBe('gzip'); expect(response!.headers()['content-encoding']).toBe('gzip');
const log = await getLog(); const log = await getLog();
expect(log.entries.length).toBe(1); expect(log.entries.length).toBe(1);
expect(log.entries[0].response.content.compression).toBeGreaterThan(4000); expect(log.entries[0].response.content.compression).toBeGreaterThan(4000);
@ -456,7 +456,7 @@ it('should have -1 _transferSize when its a failed request', async ({ contextFac
const { page, getLog } = await pageWithHar(contextFactory, testInfo); const { page, getLog } = await pageWithHar(contextFactory, testInfo);
server.setRoute('/one-style.css', (req, res) => { server.setRoute('/one-style.css', (req, res) => {
res.setHeader('Content-Type', 'text/css'); res.setHeader('Content-Type', 'text/css');
res.socket.destroy(); res.socket!.destroy();
}); });
const failedRequests = []; const failedRequests = [];
page.on('requestfailed', request => failedRequests.push(request)); page.on('requestfailed', request => failedRequests.push(request));
@ -469,7 +469,7 @@ it('should have -1 _transferSize when its a failed request', async ({ contextFac
it('should record failed request headers', async ({ contextFactory, server }, testInfo) => { it('should record failed request headers', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo); const { page, getLog } = await pageWithHar(contextFactory, testInfo);
server.setRoute('/har.html', (req, res) => { server.setRoute('/har.html', (req, res) => {
res.socket.destroy(); res.socket!.destroy();
}); });
await page.goto(server.PREFIX + '/har.html').catch(() => {}); await page.goto(server.PREFIX + '/har.html').catch(() => {});
const log = await getLog(); const log = await getLog();
@ -483,7 +483,7 @@ it('should record failed request headers', async ({ contextFactory, server }, te
it('should record failed request overrides', async ({ contextFactory, server }, testInfo) => { it('should record failed request overrides', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo); const { page, getLog } = await pageWithHar(contextFactory, testInfo);
server.setRoute('/empty.html', (req, res) => { server.setRoute('/empty.html', (req, res) => {
res.socket.destroy(); res.socket!.destroy();
}); });
await page.route('**/foo', route => { await page.route('**/foo', route => {
void route.fallback({ void route.fallback({
@ -546,7 +546,7 @@ it('should report the correct request body size when the bodySize is 0', async (
it('should report the correct response body size when the bodySize is 0', async ({ contextFactory, server }, testInfo) => { it('should report the correct response body size when the bodySize is 0', async ({ contextFactory, server }, testInfo) => {
const { page, getLog } = await pageWithHar(contextFactory, testInfo); const { page, getLog } = await pageWithHar(contextFactory, testInfo);
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
await response.finished(); await response!.finished();
const log = await getLog(); const log = await getLog();
expect(log.entries[0].response.bodySize).toBe(0); expect(log.entries[0].response.bodySize).toBe(0);
}); });
@ -562,9 +562,9 @@ it('should have popup requests', async ({ contextFactory, server }, testInfo) =>
await popup.waitForLoadState(); await popup.waitForLoadState();
const log = await getLog(); const log = await getLog();
expect(log.pages.length).toBe(2); expect(log.pages!.length).toBe(2);
const entries = log.entries.filter(entry => entry.pageref === log.pages[1].id); const entries = log.entries.filter(entry => entry.pageref === log.pages![1].id);
expect(entries.length).toBe(2); expect(entries.length).toBe(2);
expect(entries[0].request.url).toBe(server.PREFIX + '/one-style.html'); expect(entries[0].request.url).toBe(server.PREFIX + '/one-style.html');
expect(entries[0].response.status).toBe(200); expect(entries[0].response.status).toBe(200);
@ -589,7 +589,7 @@ it('should not contain internal pages', async ({ browserName, contextFactory, se
await context.storageState(); await context.storageState();
const log = await getLog(); const log = await getLog();
expect(log.pages.length).toBe(1); expect(log.pages!.length).toBe(1);
}); });
it('should have connection details', async ({ contextFactory, server, browserName, platform, mode }, testInfo) => { it('should have connection details', async ({ contextFactory, server, browserName, platform, mode }, testInfo) => {
@ -649,7 +649,7 @@ it('should have connection details for redirects', async ({ contextFactory, serv
it('should have connection details for failed requests', async ({ contextFactory, server, browserName, platform, mode }, testInfo) => { it('should have connection details for failed requests', async ({ contextFactory, server, browserName, platform, mode }, testInfo) => {
server.setRoute('/one-style.css', (_, res) => { server.setRoute('/one-style.css', (_, res) => {
res.setHeader('Content-Type', 'text/css'); res.setHeader('Content-Type', 'text/css');
res.socket.destroy(); res.socket!.destroy();
}); });
const { page, getLog } = await pageWithHar(contextFactory, testInfo); const { page, getLog } = await pageWithHar(contextFactory, testInfo);
await page.goto(server.PREFIX + '/one-style.html'); await page.goto(server.PREFIX + '/one-style.html');
@ -664,7 +664,7 @@ it('should have connection details for failed requests', async ({ contextFactory
it('should return server address directly from response', async ({ page, server, mode }) => { it('should return server address directly from response', async ({ page, server, mode }) => {
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
if (!mode.startsWith('service')) { if (!mode.startsWith('service')) {
const { ipAddress, port } = await response.serverAddr(); const { ipAddress, port } = (await response!.serverAddr())!;
expect(ipAddress).toMatch(/^127\.0\.0\.1|\[::1\]/); expect(ipAddress).toMatch(/^127\.0\.0\.1|\[::1\]/);
expect(port).toBe(server.PORT); expect(port).toBe(server.PORT);
} }
@ -676,7 +676,7 @@ it('should return security details directly from response', async ({ contextFact
const context = await contextFactory({ ignoreHTTPSErrors: true }); const context = await contextFactory({ ignoreHTTPSErrors: true });
const page = await context.newPage(); const page = await context.newPage();
const response = await page.goto(httpsServer.EMPTY_PAGE); const response = await page.goto(httpsServer.EMPTY_PAGE);
const securityDetails = await response.securityDetails(); const securityDetails = await response!.securityDetails();
if (browserName === 'webkit' && platform === 'win32') if (browserName === 'webkit' && platform === 'win32')
expect({ ...securityDetails, protocol: undefined }).toEqual({ subjectName: 'playwright-test', validFrom: 1691708270, validTo: 2007068270 }); expect({ ...securityDetails, protocol: undefined }).toEqual({ subjectName: 'playwright-test', validFrom: 1691708270, validTo: 2007068270 });
else if (browserName === 'webkit') else if (browserName === 'webkit')
@ -775,15 +775,15 @@ it('should have different hars for concurrent contexts', async ({ contextFactory
]); ]);
{ {
expect(log0.pages.length).toBe(1); expect(log0.pages!.length).toBe(1);
const pageEntry = log0.pages[0]; const pageEntry = log0.pages![0];
expect(pageEntry.title).toBe('Zero'); expect(pageEntry.title).toBe('Zero');
} }
{ {
expect(log1.pages.length).toBe(1); expect(log1.pages!.length).toBe(1);
const pageEntry = log1.pages[0]; const pageEntry = log1.pages![0];
expect(pageEntry.id).not.toBe(log0.pages[0].id); expect(pageEntry.id).not.toBe(log0.pages![0].id);
expect(pageEntry.title).toBe('One'); expect(pageEntry.title).toBe('One');
} }
}); });
@ -874,6 +874,6 @@ it('should not hang on slow chunked response', async ({ browserName, browser, co
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => (window as any).receivedFirstData); await page.evaluate(() => (window as any).receivedFirstData);
const log = await getLog(); const log = await getLog();
expect(log.browser.name.toLowerCase()).toBe(browserName); expect(log.browser!.name.toLowerCase()).toBe(browserName);
expect(log.browser.version).toBe(browser.version()); expect(log.browser!.version).toBe(browser.version());
}); });

View File

@ -33,19 +33,19 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('button', { name: 'Submit' }).click();`); await page.getByRole('button', { name: 'Submit' }).click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.get_by_role("button", name="Submit").click()`); page.get_by_role("button", name="Submit").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.get_by_role("button", name="Submit").click()`); await page.get_by_role("button", name="Submit").click()`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Submit")).click()`); page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Submit")).click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).ClickAsync();`); await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).ClickAsync();`);
expect(message.text()).toBe('click'); expect(message.text()).toBe('click');
@ -68,7 +68,7 @@ test.describe('cli codegen', () => {
recorder.trustedClick() recorder.trustedClick()
]); ]);
const clicks = recorder.sources().get('Playwright Test').actions.filter(l => l.includes('Submit')); const clicks = recorder.sources().get('Playwright Test')!.actions!.filter(l => l.includes('Submit'));
expect(clicks.length).toBe(1); expect(clicks.length).toBe(1);
}); });
@ -97,7 +97,7 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('button', { name: 'Submit' }).click();`); await page.getByRole('button', { name: 'Submit' }).click();`);
expect(message.text()).toBe('click'); expect(message.text()).toBe('click');
}); });
@ -125,7 +125,7 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('canvas').click({ await page.locator('canvas').click({
position: { position: {
x: 250, x: 250,
@ -133,17 +133,17 @@ test.describe('cli codegen', () => {
} }
});`); });`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.locator("canvas").click(position={"x":250,"y":250})`); page.locator("canvas").click(position={"x":250,"y":250})`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.locator("canvas").click(position={"x":250,"y":250})`); await page.locator("canvas").click(position={"x":250,"y":250})`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.locator("canvas").click(new Locator.ClickOptions() page.locator("canvas").click(new Locator.ClickOptions()
.setPosition(250, 250));`); .setPosition(250, 250));`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.Locator("canvas").ClickAsync(new LocatorClickOptions await page.Locator("canvas").ClickAsync(new LocatorClickOptions
{ {
Position = new Position Position = new Position
@ -175,19 +175,19 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('button', { name: 'Submit' }).click();`); await page.getByRole('button', { name: 'Submit' }).click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.get_by_role("button", name="Submit").click()`); page.get_by_role("button", name="Submit").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.get_by_role("button", name="Submit").click()`); await page.get_by_role("button", name="Submit").click()`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Submit")).click()`); page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Submit")).click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).ClickAsync();`); await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).ClickAsync();`);
expect(message.text()).toBe('click'); expect(message.text()).toBe('click');
@ -219,7 +219,7 @@ test.describe('cli codegen', () => {
recorder.waitForOutput('JavaScript', 'click'), recorder.waitForOutput('JavaScript', 'click'),
recorder.trustedMove('div').then(() => recorder.trustedClick()), recorder.trustedMove('div').then(() => recorder.trustedClick()),
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.getByText('Some long text here').click();`); await page.getByText('Some long text here').click();`);
expect(message.text()).toBe('click'); expect(message.text()).toBe('click');
}); });
@ -237,18 +237,18 @@ test.describe('cli codegen', () => {
page.fill('input', 'John') page.fill('input', 'John')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#input').fill('John');`); await page.locator('#input').fill('John');`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.locator("#input").fill("John");`); page.locator("#input").fill("John");`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.locator("#input").fill(\"John\")`); page.locator("#input").fill(\"John\")`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.locator("#input").fill(\"John\")`); await page.locator("#input").fill(\"John\")`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.Locator("#input").FillAsync(\"John\");`); await page.Locator("#input").FillAsync(\"John\");`);
expect(message.text()).toBe('John'); expect(message.text()).toBe('John');
@ -271,18 +271,18 @@ test.describe('cli codegen', () => {
await recorder.page.dispatchEvent('input', 'keyup', { key: 'Process' }); await recorder.page.dispatchEvent('input', 'keyup', { key: 'Process' });
})() })()
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#input').fill('てすと');`); await page.locator('#input').fill('てすと');`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.locator("#input").fill("てすと");`); page.locator("#input").fill("てすと");`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.locator("#input").fill(\"てすと\")`); page.locator("#input").fill(\"てすと\")`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.locator("#input").fill(\"てすと\")`); await page.locator("#input").fill(\"てすと\")`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.Locator("#input").FillAsync(\"てすと\");`); await page.Locator("#input").FillAsync(\"てすと\");`);
expect(message.text()).toBe('てすと'); expect(message.text()).toBe('てすと');
@ -300,7 +300,7 @@ test.describe('cli codegen', () => {
recorder.waitForOutput('JavaScript', 'fill'), recorder.waitForOutput('JavaScript', 'fill'),
page.fill('textarea', 'John') page.fill('textarea', 'John')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#textarea').fill('John');`); await page.locator('#textarea').fill('John');`);
expect(message.text()).toBe('John'); expect(message.text()).toBe('John');
}); });
@ -316,8 +316,8 @@ test.describe('cli codegen', () => {
// Issue was that the input event was not fired for the last newline, so we check for that. // Issue was that the input event was not fired for the last newline, so we check for that.
await page.waitForFunction(() => (window as any).lastInputValue === 'Hello\n'); await page.waitForFunction(() => (window as any).lastInputValue === 'Hello\n');
const sources = await waitForOutputPromise; const sources = await waitForOutputPromise;
expect(sources.get('JavaScript').text).toContain(`await page.locator('#textarea').fill('Hello\\n');`); expect(sources.get('JavaScript')!.text).toContain(`await page.locator('#textarea').fill('Hello\\n');`);
expect(sources.get('JavaScript').text).not.toContain(`Enter`); expect(sources.get('JavaScript')!.text).not.toContain(`Enter`);
}); });
test('should fill [contentEditable]', async ({ page, openRecorder }) => { test('should fill [contentEditable]', async ({ page, openRecorder }) => {
@ -332,7 +332,7 @@ test.describe('cli codegen', () => {
recorder.waitForOutput('JavaScript', 'fill'), recorder.waitForOutput('JavaScript', 'fill'),
page.fill('div', 'John Doe') page.fill('div', 'John Doe')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#content').fill('John Doe');`); await page.locator('#content').fill('John Doe');`);
expect(message.text()).toBe('John Doe'); expect(message.text()).toBe('John Doe');
}); });
@ -353,19 +353,19 @@ test.describe('cli codegen', () => {
page.press('input', 'Shift+Enter') page.press('input', 'Shift+Enter')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('textbox').press('Shift+Enter');`); await page.getByRole('textbox').press('Shift+Enter');`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.getByRole(AriaRole.TEXTBOX).press("Shift+Enter");`); page.getByRole(AriaRole.TEXTBOX).press("Shift+Enter");`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.get_by_role("textbox").press("Shift+Enter")`); page.get_by_role("textbox").press("Shift+Enter")`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.get_by_role("textbox").press("Shift+Enter")`); await page.get_by_role("textbox").press("Shift+Enter")`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.GetByRole(AriaRole.Textbox).PressAsync("Shift+Enter");`); await page.GetByRole(AriaRole.Textbox).PressAsync("Shift+Enter");`);
expect(messages[0].text()).toBe('press'); expect(messages[0].text()).toBe('press');
@ -389,7 +389,7 @@ test.describe('cli codegen', () => {
await page.keyboard.type('barfoo321'); await page.keyboard.type('barfoo321');
await recorder.waitForOutput('JavaScript', 'barfoo321'); await recorder.waitForOutput('JavaScript', 'barfoo321');
const text = recorder.sources().get('JavaScript').text; const text = recorder.sources().get('JavaScript')!.text;
expect(text).toContain(` expect(text).toContain(`
await page.locator('input[name="one"]').fill('foobar123');`); await page.locator('input[name="one"]').fill('foobar123');`);
@ -417,7 +417,7 @@ test.describe('cli codegen', () => {
recorder.waitForOutput('JavaScript', 'press'), recorder.waitForOutput('JavaScript', 'press'),
page.press('input', 'ArrowDown') page.press('input', 'ArrowDown')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('textbox').press('ArrowDown');`); await page.getByRole('textbox').press('ArrowDown');`);
expect(messages[0].text()).toBe('press:ArrowDown'); expect(messages[0].text()).toBe('press:ArrowDown');
}); });
@ -440,7 +440,7 @@ test.describe('cli codegen', () => {
recorder.waitForOutput('JavaScript', 'press'), recorder.waitForOutput('JavaScript', 'press'),
page.press('input', 'ArrowDown') page.press('input', 'ArrowDown')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('textbox').press('ArrowDown');`); await page.getByRole('textbox').press('ArrowDown');`);
expect(messages.length).toBe(2); expect(messages.length).toBe(2);
expect(messages[0].text()).toBe('down:ArrowDown'); expect(messages[0].text()).toBe('down:ArrowDown');
@ -461,19 +461,19 @@ test.describe('cli codegen', () => {
page.click('input') page.click('input')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#checkbox').check();`); await page.locator('#checkbox').check();`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.locator("#checkbox").check();`); page.locator("#checkbox").check();`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.locator("#checkbox").check()`); page.locator("#checkbox").check()`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.locator("#checkbox").check()`); await page.locator("#checkbox").check()`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.Locator("#checkbox").CheckAsync();`); await page.Locator("#checkbox").CheckAsync();`);
expect(message.text()).toBe('true'); expect(message.text()).toBe('true');
@ -493,7 +493,7 @@ test.describe('cli codegen', () => {
page.click('input') page.click('input')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#checkbox').check();`); await page.locator('#checkbox').check();`);
expect(message.text()).toBe('true'); expect(message.text()).toBe('true');
}); });
@ -512,7 +512,7 @@ test.describe('cli codegen', () => {
page.keyboard.press('Space') page.keyboard.press('Space')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#checkbox').check();`); await page.locator('#checkbox').check();`);
expect(message.text()).toBe('true'); expect(message.text()).toBe('true');
}); });
@ -531,19 +531,19 @@ test.describe('cli codegen', () => {
page.click('input') page.click('input')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#checkbox').uncheck();`); await page.locator('#checkbox').uncheck();`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.locator("#checkbox").uncheck();`); page.locator("#checkbox").uncheck();`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.locator("#checkbox").uncheck()`); page.locator("#checkbox").uncheck()`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.locator("#checkbox").uncheck()`); await page.locator("#checkbox").uncheck()`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.Locator("#checkbox").UncheckAsync();`); await page.Locator("#checkbox").UncheckAsync();`);
expect(message.text()).toBe('false'); expect(message.text()).toBe('false');
@ -563,19 +563,19 @@ test.describe('cli codegen', () => {
page.selectOption('select', '2') page.selectOption('select', '2')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#age').selectOption('2');`); await page.locator('#age').selectOption('2');`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.locator("#age").selectOption("2");`); page.locator("#age").selectOption("2");`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.locator("#age").select_option("2")`); page.locator("#age").select_option("2")`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.locator("#age").select_option("2")`); await page.locator("#age").select_option("2")`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.Locator("#age").SelectOptionAsync(new[] { "2" });`); await page.Locator("#age").SelectOptionAsync(new[] { "2" });`);
expect(message.text()).toBe('2'); expect(message.text()).toBe('2');
@ -604,19 +604,19 @@ test.describe('cli codegen', () => {
page.mouse.click(10, 25) page.mouse.click(10, 25)
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#age').selectOption('2');`); await page.locator('#age').selectOption('2');`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.locator("#age").selectOption("2");`); page.locator("#age").selectOption("2");`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.locator(\"#age\").select_option(\"2\")`); page.locator(\"#age\").select_option(\"2\")`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.locator(\"#age\").select_option(\"2\")`); await page.locator(\"#age\").select_option(\"2\")`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.Locator(\"#age\").SelectOptionAsync(new[] { \"2\" });`); await page.Locator(\"#age\").SelectOptionAsync(new[] { \"2\" });`);
expect(message.text()).toBe('2'); expect(message.text()).toBe('2');
@ -635,27 +635,27 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
const page1Promise = page.waitForEvent('popup'); const page1Promise = page.waitForEvent('popup');
await page.getByRole('link', { name: 'link' }).click(); await page.getByRole('link', { name: 'link' }).click();
const page1 = await page1Promise;`); const page1 = await page1Promise;`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
Page page1 = page.waitForPopup(() -> { Page page1 = page.waitForPopup(() -> {
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("link")).click(); page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("link")).click();
});`); });`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
with page.expect_popup() as page1_info: with page.expect_popup() as page1_info:
page.get_by_role("link", name="link").click() page.get_by_role("link", name="link").click()
page1 = page1_info.value`); page1 = page1_info.value`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
async with page.expect_popup() as page1_info: async with page.expect_popup() as page1_info:
await page.get_by_role("link", name="link").click() await page.get_by_role("link", name="link").click()
page1 = await page1_info.value`); page1 = await page1_info.value`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
var page1 = await page.RunAndWaitForPopupAsync(async () => var page1 = await page.RunAndWaitForPopupAsync(async () =>
{ {
await page.GetByRole(AriaRole.Link, new() { Name = "link" }).ClickAsync(); await page.GetByRole(AriaRole.Link, new() { Name = "link" }).ClickAsync();
@ -677,25 +677,25 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.getByText('link').click();`); await page.getByText('link').click();`);
expect.soft(sources.get('Playwright Test').text).toContain(` expect.soft(sources.get('Playwright Test')!.text).toContain(`
await page.getByText('link').click();`); await page.getByText('link').click();`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.getByText("link").click();`); page.getByText("link").click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.get_by_text("link").click()`); page.get_by_text("link").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.get_by_text("link").click()`); await page.get_by_text("link").click()`);
expect.soft(sources.get('Pytest').text).toContain(` expect.soft(sources.get('Pytest')!.text).toContain(`
page.get_by_text("link").click()`); page.get_by_text("link").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.GetByText("link").ClickAsync();`); await page.GetByText("link").ClickAsync();`);
expect(page.url()).toContain('about:blank#foo'); expect(page.url()).toContain('about:blank#foo');
@ -711,8 +711,8 @@ test.describe('cli codegen', () => {
await recorder.page.keyboard.insertText('@'); await recorder.page.keyboard.insertText('@');
await recorder.page.keyboard.type('example.com'); await recorder.page.keyboard.type('example.com');
await recorder.waitForOutput('JavaScript', 'example.com'); await recorder.waitForOutput('JavaScript', 'example.com');
expect(recorder.sources().get('JavaScript').text).not.toContain(`await page.getByRole('textbox').press('AltGraph');`); expect(recorder.sources().get('JavaScript')!.text).not.toContain(`await page.getByRole('textbox').press('AltGraph');`);
expect(recorder.sources().get('JavaScript').text).toContain(`await page.getByRole('textbox').fill('playwright@example.com');`); expect(recorder.sources().get('JavaScript')!.text).toContain(`await page.getByRole('textbox').fill('playwright@example.com');`);
}); });
test('should middle click', async ({ page, openRecorder, server }) => { test('should middle click', async ({ page, openRecorder, server }) => {
@ -725,22 +725,22 @@ test.describe('cli codegen', () => {
page.click('a', { button: 'middle' }), page.click('a', { button: 'middle' }),
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.getByText('Click me').click({ await page.getByText('Click me').click({
button: 'middle' button: 'middle'
});`); });`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.get_by_text("Click me").click(button="middle")`); page.get_by_text("Click me").click(button="middle")`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.get_by_text("Click me").click(button="middle")`); await page.get_by_text("Click me").click(button="middle")`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.getByText("Click me").click(new Locator.ClickOptions() page.getByText("Click me").click(new Locator.ClickOptions()
.setButton(MouseButton.MIDDLE));`); .setButton(MouseButton.MIDDLE));`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.GetByText("Click me").ClickAsync(new LocatorClickOptions await page.GetByText("Click me").ClickAsync(new LocatorClickOptions
{ {
Button = MouseButton.Middle, Button = MouseButton.Middle,

View File

@ -27,19 +27,19 @@ test.describe('cli codegen', () => {
await recorder.setContentAndWait(``); await recorder.setContentAndWait(``);
const sources = await recorder.waitForOutput('JavaScript', `page.goto`); const sources = await recorder.waitForOutput('JavaScript', `page.goto`);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
const page = await context.newPage();`); const page = await context.newPage();`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
Page page = context.newPage();`); Page page = context.newPage();`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page = context.new_page()`); page = context.new_page()`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
page = await context.new_page()`); page = await context.new_page()`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
var page = await context.NewPageAsync();`); var page = await context.NewPageAsync();`);
}); });
@ -50,19 +50,19 @@ test.describe('cli codegen', () => {
await page.context().newPage(); await page.context().newPage();
const sources = await recorder.waitForOutput('JavaScript', 'page1'); const sources = await recorder.waitForOutput('JavaScript', 'page1');
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
const page1 = await context.newPage();`); const page1 = await context.newPage();`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
Page page1 = context.newPage();`); Page page1 = context.newPage();`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page1 = context.new_page()`); page1 = context.new_page()`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
page1 = await context.new_page()`); page1 = await context.new_page()`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
var page1 = await context.NewPageAsync();`); var page1 = await context.NewPageAsync();`);
}); });
@ -74,19 +74,19 @@ test.describe('cli codegen', () => {
await recorder.page.close(); await recorder.page.close();
const sources = await recorder.waitForOutput('JavaScript', 'page.close();'); const sources = await recorder.waitForOutput('JavaScript', 'page.close();');
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.close();`); await page.close();`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.close();`); page.close();`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.close()`); page.close()`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.close()`); await page.close()`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.CloseAsync();`); await page.CloseAsync();`);
}); });
@ -97,7 +97,7 @@ test.describe('cli codegen', () => {
await page.context().newPage(); await page.context().newPage();
const errors: any[] = []; const errors: any[] = [];
recorder.page.on('pageerror', e => errors.push(e)); recorder.page.on('pageerror', e => errors.push(e));
await recorder.page.evaluate(() => document.querySelector('body').remove()); await recorder.page.evaluate(() => document.querySelector('body')!.remove());
await page.dispatchEvent('html', 'mousemove', { detail: 1 }); await page.dispatchEvent('html', 'mousemove', { detail: 1 });
await recorder.page.close(); await recorder.page.close();
await recorder.waitForOutput('JavaScript', 'page.close();'); await recorder.waitForOutput('JavaScript', 'page.close();');
@ -119,19 +119,19 @@ test.describe('cli codegen', () => {
const sources = await recorder.waitForOutput('JavaScript', 'setInputFiles'); const sources = await recorder.waitForOutput('JavaScript', 'setInputFiles');
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('textbox').setInputFiles('file-to-upload.txt');`); await page.getByRole('textbox').setInputFiles('file-to-upload.txt');`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.getByRole(AriaRole.TEXTBOX).setInputFiles(Paths.get("file-to-upload.txt"));`); page.getByRole(AriaRole.TEXTBOX).setInputFiles(Paths.get("file-to-upload.txt"));`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.get_by_role("textbox").set_input_files(\"file-to-upload.txt\")`); page.get_by_role("textbox").set_input_files(\"file-to-upload.txt\")`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.get_by_role("textbox").set_input_files(\"file-to-upload.txt\")`); await page.get_by_role("textbox").set_input_files(\"file-to-upload.txt\")`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.GetByRole(AriaRole.Textbox).SetInputFilesAsync(new[] { \"file-to-upload.txt\" });`); await page.GetByRole(AriaRole.Textbox).SetInputFilesAsync(new[] { \"file-to-upload.txt\" });`);
}); });
@ -150,19 +150,19 @@ test.describe('cli codegen', () => {
const sources = await recorder.waitForOutput('JavaScript', 'setInputFiles'); const sources = await recorder.waitForOutput('JavaScript', 'setInputFiles');
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('textbox').setInputFiles(['file-to-upload.txt', 'file-to-upload-2.txt']);`); await page.getByRole('textbox').setInputFiles(['file-to-upload.txt', 'file-to-upload-2.txt']);`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.getByRole(AriaRole.TEXTBOX).setInputFiles(new Path[] {Paths.get("file-to-upload.txt"), Paths.get("file-to-upload-2.txt")});`); page.getByRole(AriaRole.TEXTBOX).setInputFiles(new Path[] {Paths.get("file-to-upload.txt"), Paths.get("file-to-upload-2.txt")});`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.get_by_role("textbox").set_input_files([\"file-to-upload.txt\", \"file-to-upload-2.txt\"]`); page.get_by_role("textbox").set_input_files([\"file-to-upload.txt\", \"file-to-upload-2.txt\"]`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.get_by_role("textbox").set_input_files([\"file-to-upload.txt\", \"file-to-upload-2.txt\"]`); await page.get_by_role("textbox").set_input_files([\"file-to-upload.txt\", \"file-to-upload-2.txt\"]`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.GetByRole(AriaRole.Textbox).SetInputFilesAsync(new[] { \"file-to-upload.txt\", \"file-to-upload-2.txt\" });`); await page.GetByRole(AriaRole.Textbox).SetInputFilesAsync(new[] { \"file-to-upload.txt\", \"file-to-upload-2.txt\" });`);
}); });
@ -181,19 +181,19 @@ test.describe('cli codegen', () => {
const sources = await recorder.waitForOutput('JavaScript', 'setInputFiles'); const sources = await recorder.waitForOutput('JavaScript', 'setInputFiles');
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('textbox').setInputFiles([]);`); await page.getByRole('textbox').setInputFiles([]);`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.getByRole(AriaRole.TEXTBOX).setInputFiles(new Path[0]);`); page.getByRole(AriaRole.TEXTBOX).setInputFiles(new Path[0]);`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.get_by_role("textbox").set_input_files([])`); page.get_by_role("textbox").set_input_files([])`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.get_by_role("textbox").set_input_files([])`); await page.get_by_role("textbox").set_input_files([])`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.GetByRole(AriaRole.Textbox).SetInputFilesAsync(new[] { });`); await page.GetByRole(AriaRole.Textbox).SetInputFilesAsync(new[] { });`);
}); });
@ -225,48 +225,48 @@ test.describe('cli codegen', () => {
]); ]);
const sources = await recorder.waitForOutput('JavaScript', 'download1Promise'); const sources = await recorder.waitForOutput('JavaScript', 'download1Promise');
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
const downloadPromise = page.waitForEvent('download'); const downloadPromise = page.waitForEvent('download');
await page.getByRole('link', { name: 'Download' }).click(); await page.getByRole('link', { name: 'Download' }).click();
const download = await downloadPromise;`); const download = await downloadPromise;`);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
const download1Promise = page.waitForEvent('download'); const download1Promise = page.waitForEvent('download');
await page.getByRole('link', { name: 'Download' }).click(); await page.getByRole('link', { name: 'Download' }).click();
const download1 = await download1Promise;`); const download1 = await download1Promise;`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
Download download = page.waitForDownload(() -> { Download download = page.waitForDownload(() -> {
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("Download")).click(); page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("Download")).click();
});`); });`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
Download download1 = page.waitForDownload(() -> { Download download1 = page.waitForDownload(() -> {
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("Download")).click(); page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("Download")).click();
});`); });`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
with page.expect_download() as download_info: with page.expect_download() as download_info:
page.get_by_role("link", name="Download").click() page.get_by_role("link", name="Download").click()
download = download_info.value`); download = download_info.value`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
with page.expect_download() as download1_info: with page.expect_download() as download1_info:
page.get_by_role("link", name="Download").click() page.get_by_role("link", name="Download").click()
download1 = download1_info.value`); download1 = download1_info.value`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
async with page.expect_download() as download_info: async with page.expect_download() as download_info:
await page.get_by_role("link", name="Download").click() await page.get_by_role("link", name="Download").click()
download = await download_info.value`); download = await download_info.value`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
async with page.expect_download() as download1_info: async with page.expect_download() as download1_info:
await page.get_by_role("link", name="Download").click() await page.get_by_role("link", name="Download").click()
download1 = await download1_info.value`); download1 = await download1_info.value`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
var download = await page.RunAndWaitForDownloadAsync(async () => var download = await page.RunAndWaitForDownloadAsync(async () =>
{ {
await page.GetByRole(AriaRole.Link, new() { Name = "Download" }).ClickAsync(); await page.GetByRole(AriaRole.Link, new() { Name = "Download" }).ClickAsync();
});`); });`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
var download1 = await page.RunAndWaitForDownloadAsync(async () => var download1 = await page.RunAndWaitForDownloadAsync(async () =>
{ {
await page.GetByRole(AriaRole.Link, new() { Name = "Download" }).ClickAsync(); await page.GetByRole(AriaRole.Link, new() { Name = "Download" }).ClickAsync();
@ -287,29 +287,29 @@ test.describe('cli codegen', () => {
const sources = await recorder.waitForOutput('JavaScript', 'once'); const sources = await recorder.waitForOutput('JavaScript', 'once');
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
page.once('dialog', dialog => { page.once('dialog', dialog => {
console.log(\`Dialog message: \${dialog.message()}\`); console.log(\`Dialog message: \${dialog.message()}\`);
dialog.dismiss().catch(() => {}); dialog.dismiss().catch(() => {});
}); });
await page.getByRole('button', { name: 'click me' }).click();`); await page.getByRole('button', { name: 'click me' }).click();`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.onceDialog(dialog -> { page.onceDialog(dialog -> {
System.out.println(String.format("Dialog message: %s", dialog.message())); System.out.println(String.format("Dialog message: %s", dialog.message()));
dialog.dismiss(); dialog.dismiss();
}); });
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("click me")).click();`); page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("click me")).click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.once(\"dialog\", lambda dialog: dialog.dismiss()) page.once(\"dialog\", lambda dialog: dialog.dismiss())
page.get_by_role("button", name="click me").click()`); page.get_by_role("button", name="click me").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
page.once(\"dialog\", lambda dialog: dialog.dismiss()) page.once(\"dialog\", lambda dialog: dialog.dismiss())
await page.get_by_role("button", name="click me").click()`); await page.get_by_role("button", name="click me").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
void page_Dialog_EventHandler(object sender, IDialog dialog) void page_Dialog_EventHandler(object sender, IDialog dialog)
{ {
Console.WriteLine($\"Dialog message: {dialog.Message}\"); Console.WriteLine($\"Dialog message: {dialog.Message}\");
@ -348,17 +348,17 @@ test.describe('cli codegen', () => {
const sources = await recorder.waitForOutput('JavaScript', 'page1'); const sources = await recorder.waitForOutput('JavaScript', 'page1');
if (browserName !== 'firefox') { if (browserName !== 'firefox') {
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
const page1 = await context.newPage(); const page1 = await context.newPage();
await page1.goto('about:blank?foo');`); await page1.goto('about:blank?foo');`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
page1 = await context.new_page() page1 = await context.new_page()
await page1.goto("about:blank?foo")`); await page1.goto("about:blank?foo")`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
var page1 = await context.NewPageAsync(); var page1 = await context.NewPageAsync();
await page1.GotoAsync("about:blank?foo");`); await page1.GotoAsync("about:blank?foo");`);
} else { } else {
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
const page1Promise = page.waitForEvent('popup'); const page1Promise = page.waitForEvent('popup');
await page.getByRole('link', { name: 'link' }).click({ await page.getByRole('link', { name: 'link' }).click({
modifiers: ['${platform === 'darwin' ? 'Meta' : 'Control'}'] modifiers: ['${platform === 'darwin' ? 'Meta' : 'Control'}']
@ -388,20 +388,20 @@ test.describe('cli codegen', () => {
await recorder.waitForOutput('JavaScript', 'TextB'); await recorder.waitForOutput('JavaScript', 'TextB');
const sources = recorder.sources(); const sources = recorder.sources();
expect(sources.get('JavaScript').text).toContain(`await page1.locator('#name').fill('TextA');`); expect(sources.get('JavaScript')!.text).toContain(`await page1.locator('#name').fill('TextA');`);
expect(sources.get('JavaScript').text).toContain(`await page2.locator('#name').fill('TextB');`); expect(sources.get('JavaScript')!.text).toContain(`await page2.locator('#name').fill('TextB');`);
expect(sources.get('Java').text).toContain(`page1.locator("#name").fill("TextA");`); expect(sources.get('Java')!.text).toContain(`page1.locator("#name").fill("TextA");`);
expect(sources.get('Java').text).toContain(`page2.locator("#name").fill("TextB");`); expect(sources.get('Java')!.text).toContain(`page2.locator("#name").fill("TextB");`);
expect(sources.get('Python').text).toContain(`page1.locator("#name").fill("TextA")`); expect(sources.get('Python')!.text).toContain(`page1.locator("#name").fill("TextA")`);
expect(sources.get('Python').text).toContain(`page2.locator("#name").fill("TextB")`); expect(sources.get('Python')!.text).toContain(`page2.locator("#name").fill("TextB")`);
expect(sources.get('Python Async').text).toContain(`await page1.locator("#name").fill("TextA")`); expect(sources.get('Python Async')!.text).toContain(`await page1.locator("#name").fill("TextA")`);
expect(sources.get('Python Async').text).toContain(`await page2.locator("#name").fill("TextB")`); expect(sources.get('Python Async')!.text).toContain(`await page2.locator("#name").fill("TextB")`);
expect(sources.get('C#').text).toContain(`await page1.Locator("#name").FillAsync("TextA");`); expect(sources.get('C#')!.text).toContain(`await page1.Locator("#name").FillAsync("TextA");`);
expect(sources.get('C#').text).toContain(`await page2.Locator("#name").FillAsync("TextB");`); expect(sources.get('C#')!.text).toContain(`await page2.Locator("#name").FillAsync("TextB");`);
}); });
test('click should emit events in order', async ({ page, openRecorder }) => { test('click should emit events in order', async ({ page, openRecorder }) => {
@ -528,19 +528,19 @@ test.describe('cli codegen', () => {
page.fill('textarea', 'Hello\'\"\`\nWorld') page.fill('textarea', 'Hello\'\"\`\nWorld')
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.locator('#textarea').fill('Hello\\'"\`\\nWorld');`); await page.locator('#textarea').fill('Hello\\'"\`\\nWorld');`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.locator("#textarea").fill("Hello'\\"\`\\nWorld");`); page.locator("#textarea").fill("Hello'\\"\`\\nWorld");`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.locator("#textarea").fill(\"Hello'\\"\`\\nWorld\")`); page.locator("#textarea").fill(\"Hello'\\"\`\\nWorld\")`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.locator("#textarea").fill(\"Hello'\\"\`\\nWorld\")`); await page.locator("#textarea").fill(\"Hello'\\"\`\\nWorld\")`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.Locator("#textarea").FillAsync(\"Hello'\\"\`\\nWorld\");`); await page.Locator("#textarea").FillAsync(\"Hello'\\"\`\\nWorld\");`);
expect(message.text()).toBe('Hello\'\"\`\nWorld'); expect(message.text()).toBe('Hello\'\"\`\nWorld');
@ -555,9 +555,9 @@ test('should --test-id-attribute', async ({ page, openRecorder }) => {
await page.click('[my-test-id=foo]'); await page.click('[my-test-id=foo]');
const sources = await recorder.waitForOutput('JavaScript', `page.getByTestId`); const sources = await recorder.waitForOutput('JavaScript', `page.getByTestId`);
expect.soft(sources.get('JavaScript').text).toContain(`await page.getByTestId('foo').click()`); expect.soft(sources.get('JavaScript')!.text).toContain(`await page.getByTestId('foo').click()`);
expect.soft(sources.get('Java').text).toContain(`page.getByTestId("foo").click()`); expect.soft(sources.get('Java')!.text).toContain(`page.getByTestId("foo").click()`);
expect.soft(sources.get('Python').text).toContain(`page.get_by_test_id("foo").click()`); expect.soft(sources.get('Python')!.text).toContain(`page.get_by_test_id("foo").click()`);
expect.soft(sources.get('Python Async').text).toContain(`await page.get_by_test_id("foo").click()`); expect.soft(sources.get('Python Async')!.text).toContain(`await page.get_by_test_id("foo").click()`);
expect.soft(sources.get('C#').text).toContain(`await page.GetByTestId("foo").ClickAsync();`); expect.soft(sources.get('C#')!.text).toContain(`await page.GetByTestId("foo").ClickAsync();`);
}); });

View File

@ -36,19 +36,19 @@ test.describe('cli codegen', () => {
recorder.trustedClick() recorder.trustedClick()
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('button', { name: 'Submit' }).first().click();`); await page.getByRole('button', { name: 'Submit' }).first().click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.get_by_role("button", name="Submit").first.click()`); page.get_by_role("button", name="Submit").first.click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.get_by_role("button", name="Submit").first.click()`); await page.get_by_role("button", name="Submit").first.click()`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Submit")).first().click();`); page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Submit")).first().click();`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).First.ClickAsync();`); await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).First.ClickAsync();`);
expect(message.text()).toBe('click1'); expect(message.text()).toBe('click1');
@ -71,19 +71,19 @@ test.describe('cli codegen', () => {
recorder.trustedClick() recorder.trustedClick()
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.getByRole('button', { name: 'Submit' }).nth(1).click();`); await page.getByRole('button', { name: 'Submit' }).nth(1).click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.get_by_role("button", name="Submit").nth(1).click()`); page.get_by_role("button", name="Submit").nth(1).click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.get_by_role("button", name="Submit").nth(1).click()`); await page.get_by_role("button", name="Submit").nth(1).click()`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Submit")).nth(1).click();`); page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Submit")).nth(1).click();`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).Nth(1).ClickAsync();`); await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).Nth(1).ClickAsync();`);
expect(message.text()).toBe('click2'); expect(message.text()).toBe('click2');
@ -108,11 +108,11 @@ test.describe('cli codegen', () => {
`, server.EMPTY_PAGE, 6); `, server.EMPTY_PAGE, 6);
const frameHello1 = page.mainFrame().childFrames()[0]; const frameHello1 = page.mainFrame().childFrames()[0];
const frameHello2 = frameHello1.childFrames()[0]; const frameHello2 = frameHello1.childFrames()[0];
const frameOne = page.frame({ name: 'one' }); const frameOne = page.frame({ name: 'one' })!;
await frameOne.setContent(`<div>HelloNameOne</div>`); await frameOne.setContent(`<div>HelloNameOne</div>`);
const frameTwo = page.frame({ name: 'two' }); const frameTwo = page.frame({ name: 'two' })!;
await frameTwo.setContent(`<div>HelloNameTwo</div>`); await frameTwo.setContent(`<div>HelloNameTwo</div>`);
const frameAnonymous = frameHello2.childFrames().find(f => !f.name()); const frameAnonymous = frameHello2.childFrames().find(f => !f.name())!;
await frameAnonymous.setContent(`<div>HelloNameAnonymous</div>`); await frameAnonymous.setContent(`<div>HelloNameAnonymous</div>`);
let [sources] = await Promise.all([ let [sources] = await Promise.all([
@ -120,19 +120,19 @@ test.describe('cli codegen', () => {
frameHello1.click('text=Hello1'), frameHello1.click('text=Hello1'),
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect(sources.get('JavaScript')!.text).toContain(`
await page.frameLocator('#frame1').getByText('Hello1').click();`); await page.frameLocator('#frame1').getByText('Hello1').click();`);
expect(sources.get('Java').text).toContain(` expect(sources.get('Java')!.text).toContain(`
page.frameLocator("#frame1").getByText("Hello1").click();`); page.frameLocator("#frame1").getByText("Hello1").click();`);
expect(sources.get('Python').text).toContain(` expect(sources.get('Python')!.text).toContain(`
page.frame_locator("#frame1").get_by_text("Hello1").click()`); page.frame_locator("#frame1").get_by_text("Hello1").click()`);
expect(sources.get('Python Async').text).toContain(` expect(sources.get('Python Async')!.text).toContain(`
await page.frame_locator("#frame1").get_by_text("Hello1").click()`); await page.frame_locator("#frame1").get_by_text("Hello1").click()`);
expect(sources.get('C#').text).toContain(` expect(sources.get('C#')!.text).toContain(`
await page.FrameLocator("#frame1").GetByText("Hello1").ClickAsync();`); await page.FrameLocator("#frame1").GetByText("Hello1").ClickAsync();`);
@ -141,19 +141,19 @@ test.describe('cli codegen', () => {
frameHello2.click('text=Hello2'), frameHello2.click('text=Hello2'),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.frameLocator('#frame1').frameLocator('iframe').getByText('Hello2').click();`); await page.frameLocator('#frame1').frameLocator('iframe').getByText('Hello2').click();`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.frameLocator("#frame1").frameLocator("iframe").getByText("Hello2").click();`); page.frameLocator("#frame1").frameLocator("iframe").getByText("Hello2").click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.frame_locator("#frame1").frame_locator("iframe").get_by_text("Hello2").click()`); page.frame_locator("#frame1").frame_locator("iframe").get_by_text("Hello2").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.frame_locator("#frame1").frame_locator("iframe").get_by_text("Hello2").click()`); await page.frame_locator("#frame1").frame_locator("iframe").get_by_text("Hello2").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.FrameLocator("#frame1").FrameLocator("iframe").GetByText("Hello2").ClickAsync();`); await page.FrameLocator("#frame1").FrameLocator("iframe").GetByText("Hello2").ClickAsync();`);
@ -162,21 +162,21 @@ test.describe('cli codegen', () => {
frameOne.click('text=HelloNameOne'), frameOne.click('text=HelloNameOne'),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.frame({ await page.frame({
name: 'one' name: 'one'
}).getByText('HelloNameOne').click();`); }).getByText('HelloNameOne').click();`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.frame("one").getByText("HelloNameOne").click();`); page.frame("one").getByText("HelloNameOne").click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.frame(name=\"one\").get_by_text(\"HelloNameOne\").click()`); page.frame(name=\"one\").get_by_text(\"HelloNameOne\").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.frame(name=\"one\").get_by_text(\"HelloNameOne\").click()`); await page.frame(name=\"one\").get_by_text(\"HelloNameOne\").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.Frame(\"one\").GetByText(\"HelloNameOne\").ClickAsync();`); await page.Frame(\"one\").GetByText(\"HelloNameOne\").ClickAsync();`);
@ -185,21 +185,21 @@ test.describe('cli codegen', () => {
frameAnonymous.click('text=HelloNameAnonymous'), frameAnonymous.click('text=HelloNameAnonymous'),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.frame({ await page.frame({
url: 'about:blank' url: 'about:blank'
}).getByText('HelloNameAnonymous').click();`); }).getByText('HelloNameAnonymous').click();`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.frameByUrl("about:blank").getByText("HelloNameAnonymous").click();`); page.frameByUrl("about:blank").getByText("HelloNameAnonymous").click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.frame(url=\"about:blank\").get_by_text(\"HelloNameAnonymous\").click()`); page.frame(url=\"about:blank\").get_by_text(\"HelloNameAnonymous\").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.frame(url=\"about:blank\").get_by_text(\"HelloNameAnonymous\").click()`); await page.frame(url=\"about:blank\").get_by_text(\"HelloNameAnonymous\").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.FrameByUrl(\"about:blank\").GetByText(\"HelloNameAnonymous\").ClickAsync();`); await page.FrameByUrl(\"about:blank\").GetByText(\"HelloNameAnonymous\").ClickAsync();`);
}); });
@ -214,23 +214,23 @@ test.describe('cli codegen', () => {
page.frameLocator('[title="hello world"]').getByRole('button', { name: 'Click me' }).click(), page.frameLocator('[title="hello world"]').getByRole('button', { name: 'Click me' }).click(),
]); ]);
expect(sources.get('JavaScript').text).toContain( expect(sources.get('JavaScript')!.text).toContain(
`await page.frameLocator('iframe[title="hello world"]').getByRole('button', { name: 'Click me' }).click();` `await page.frameLocator('iframe[title="hello world"]').getByRole('button', { name: 'Click me' }).click();`
); );
expect(sources.get('Java').text).toContain( expect(sources.get('Java')!.text).toContain(
`page.frameLocator(\"iframe[title=\\\"hello world\\\"]\").getByRole(AriaRole.BUTTON, new FrameLocator.GetByRoleOptions().setName(\"Click me\")).click();` `page.frameLocator(\"iframe[title=\\\"hello world\\\"]\").getByRole(AriaRole.BUTTON, new FrameLocator.GetByRoleOptions().setName(\"Click me\")).click();`
); );
expect(sources.get('Python').text).toContain( expect(sources.get('Python')!.text).toContain(
`page.frame_locator(\"iframe[title=\\\"hello world\\\"]\").get_by_role(\"button\", name=\"Click me\").click()` `page.frame_locator(\"iframe[title=\\\"hello world\\\"]\").get_by_role(\"button\", name=\"Click me\").click()`
); );
expect(sources.get('Python Async').text).toContain( expect(sources.get('Python Async')!.text).toContain(
`await page.frame_locator("iframe[title=\\\"hello world\\\"]").get_by_role("button", name="Click me").click()` `await page.frame_locator("iframe[title=\\\"hello world\\\"]").get_by_role("button", name="Click me").click()`
); );
expect(sources.get('C#').text).toContain( expect(sources.get('C#')!.text).toContain(
`await page.FrameLocator("iframe[title=\\\"hello world\\\"]").GetByRole(AriaRole.Button, new() { Name = "Click me" }).ClickAsync();` `await page.FrameLocator("iframe[title=\\\"hello world\\\"]").GetByRole(AriaRole.Button, new() { Name = "Click me" }).ClickAsync();`
); );
}); });
@ -246,23 +246,23 @@ test.describe('cli codegen', () => {
page.frameLocator('[name="hello world"]').getByRole('button', { name: 'Click me' }).click(), page.frameLocator('[name="hello world"]').getByRole('button', { name: 'Click me' }).click(),
]); ]);
expect(sources.get('JavaScript').text).toContain( expect(sources.get('JavaScript')!.text).toContain(
`await page.frameLocator('iframe[name="hello world"]').getByRole('button', { name: 'Click me' }).click();` `await page.frameLocator('iframe[name="hello world"]').getByRole('button', { name: 'Click me' }).click();`
); );
expect(sources.get('Java').text).toContain( expect(sources.get('Java')!.text).toContain(
`page.frameLocator(\"iframe[name=\\\"hello world\\\"]\").getByRole(AriaRole.BUTTON, new FrameLocator.GetByRoleOptions().setName(\"Click me\")).click();` `page.frameLocator(\"iframe[name=\\\"hello world\\\"]\").getByRole(AriaRole.BUTTON, new FrameLocator.GetByRoleOptions().setName(\"Click me\")).click();`
); );
expect(sources.get('Python').text).toContain( expect(sources.get('Python')!.text).toContain(
`page.frame_locator(\"iframe[name=\\\"hello world\\\"]\").get_by_role(\"button\", name=\"Click me\").click()` `page.frame_locator(\"iframe[name=\\\"hello world\\\"]\").get_by_role(\"button\", name=\"Click me\").click()`
); );
expect(sources.get('Python Async').text).toContain( expect(sources.get('Python Async')!.text).toContain(
`await page.frame_locator("iframe[name=\\\"hello world\\\"]").get_by_role("button", name="Click me").click()` `await page.frame_locator("iframe[name=\\\"hello world\\\"]").get_by_role("button", name="Click me").click()`
); );
expect(sources.get('C#').text).toContain( expect(sources.get('C#')!.text).toContain(
`await page.FrameLocator("iframe[name=\\\"hello world\\\"]").GetByRole(AriaRole.Button, new() { Name = "Click me" }).ClickAsync();` `await page.FrameLocator("iframe[name=\\\"hello world\\\"]").GetByRole(AriaRole.Button, new() { Name = "Click me" }).ClickAsync();`
); );
}); });
@ -278,23 +278,23 @@ test.describe('cli codegen', () => {
page.frameLocator('[id="hello-world"]').getByRole('button', { name: 'Click me' }).click(), page.frameLocator('[id="hello-world"]').getByRole('button', { name: 'Click me' }).click(),
]); ]);
expect(sources.get('JavaScript').text).toContain( expect(sources.get('JavaScript')!.text).toContain(
`await page.frameLocator('#hello-world').getByRole('button', { name: 'Click me' }).click();` `await page.frameLocator('#hello-world').getByRole('button', { name: 'Click me' }).click();`
); );
expect(sources.get('Java').text).toContain( expect(sources.get('Java')!.text).toContain(
`page.frameLocator(\"#hello-world\").getByRole(AriaRole.BUTTON, new FrameLocator.GetByRoleOptions().setName(\"Click me\")).click();` `page.frameLocator(\"#hello-world\").getByRole(AriaRole.BUTTON, new FrameLocator.GetByRoleOptions().setName(\"Click me\")).click();`
); );
expect(sources.get('Python').text).toContain( expect(sources.get('Python')!.text).toContain(
`page.frame_locator(\"#hello-world\").get_by_role(\"button\", name=\"Click me\").click()` `page.frame_locator(\"#hello-world\").get_by_role(\"button\", name=\"Click me\").click()`
); );
expect(sources.get('Python Async').text).toContain( expect(sources.get('Python Async')!.text).toContain(
`await page.frame_locator("#hello-world").get_by_role("button", name="Click me").click()` `await page.frame_locator("#hello-world").get_by_role("button", name="Click me").click()`
); );
expect(sources.get('C#').text).toContain( expect(sources.get('C#')!.text).toContain(
`await page.FrameLocator("#hello-world").GetByRole(AriaRole.Button, new() { Name = "Click me" }).ClickAsync();` `await page.FrameLocator("#hello-world").GetByRole(AriaRole.Button, new() { Name = "Click me" }).ClickAsync();`
); );
}); });
@ -310,23 +310,23 @@ test.describe('cli codegen', () => {
page.frameLocator('iframe[data-testid="my-testid"]').getByRole('button', { name: 'Click me' }).click(), page.frameLocator('iframe[data-testid="my-testid"]').getByRole('button', { name: 'Click me' }).click(),
]); ]);
expect(sources.get('JavaScript').text).toContain( expect(sources.get('JavaScript')!.text).toContain(
`await page.frameLocator('[data-testid="my-testid"]').getByRole('button', { name: 'Click me' }).click();` `await page.frameLocator('[data-testid="my-testid"]').getByRole('button', { name: 'Click me' }).click();`
); );
expect(sources.get('Java').text).toContain( expect(sources.get('Java')!.text).toContain(
`page.frameLocator(\"[data-testid=\\\"my-testid\\\"]\").getByRole(AriaRole.BUTTON, new FrameLocator.GetByRoleOptions().setName(\"Click me\")).click();` `page.frameLocator(\"[data-testid=\\\"my-testid\\\"]\").getByRole(AriaRole.BUTTON, new FrameLocator.GetByRoleOptions().setName(\"Click me\")).click();`
); );
expect(sources.get('Python').text).toContain( expect(sources.get('Python')!.text).toContain(
`page.frame_locator(\"[data-testid=\\\"my-testid\\\"]\").get_by_role(\"button\", name=\"Click me\").click()` `page.frame_locator(\"[data-testid=\\\"my-testid\\\"]\").get_by_role(\"button\", name=\"Click me\").click()`
); );
expect(sources.get('Python Async').text).toContain( expect(sources.get('Python Async')!.text).toContain(
`await page.frame_locator("[data-testid=\\\"my-testid\\\"]").get_by_role("button", name="Click me").click()` `await page.frame_locator("[data-testid=\\\"my-testid\\\"]").get_by_role("button", name="Click me").click()`
); );
expect(sources.get('C#').text).toContain( expect(sources.get('C#')!.text).toContain(
`await page.FrameLocator("[data-testid=\\\"my-testid\\\"]").GetByRole(AriaRole.Button, new() { Name = "Click me" }).ClickAsync();` `await page.FrameLocator("[data-testid=\\\"my-testid\\\"]").GetByRole(AriaRole.Button, new() { Name = "Click me" }).ClickAsync();`
); );
}); });
@ -341,19 +341,19 @@ test.describe('cli codegen', () => {
frame.click('button'), frame.click('button'),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.frameLocator('#frame1').getByRole('button', { name: 'Submit' }).click();`); await page.frameLocator('#frame1').getByRole('button', { name: 'Submit' }).click();`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.frameLocator("#frame1").getByRole(AriaRole.BUTTON, new FrameLocator.GetByRoleOptions().setName("Submit")).click();`); page.frameLocator("#frame1").getByRole(AriaRole.BUTTON, new FrameLocator.GetByRoleOptions().setName("Submit")).click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.frame_locator("#frame1").get_by_role("button", name="Submit").click()`); page.frame_locator("#frame1").get_by_role("button", name="Submit").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.frame_locator("#frame1").get_by_role("button", name="Submit").click()`); await page.frame_locator("#frame1").get_by_role("button", name="Submit").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.FrameLocator("#frame1").GetByRole(AriaRole.Button, new() { Name = "Submit" }).ClickAsync();`); await page.FrameLocator("#frame1").GetByRole(AriaRole.Button, new() { Name = "Submit" }).ClickAsync();`);
}); });
@ -371,19 +371,19 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.getByTestId('testid').click();`); await page.getByTestId('testid').click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.get_by_test_id("testid").click()`); page.get_by_test_id("testid").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.get_by_test_id("testid").click()`); await page.get_by_test_id("testid").click()`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.getByTestId("testid").click()`); page.getByTestId("testid").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.GetByTestId("testid").ClickAsync();`); await page.GetByTestId("testid").ClickAsync();`);
expect(message.text()).toBe('click'); expect(message.text()).toBe('click');
@ -402,19 +402,19 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.getByPlaceholder('Country').click();`); await page.getByPlaceholder('Country').click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.get_by_placeholder("Country").click()`); page.get_by_placeholder("Country").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.get_by_placeholder("Country").click()`); await page.get_by_placeholder("Country").click()`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.getByPlaceholder("Country").click()`); page.getByPlaceholder("Country").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.GetByPlaceholder("Country").ClickAsync();`); await page.GetByPlaceholder("Country").ClickAsync();`);
}); });
@ -431,19 +431,19 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.getByAltText('Country').click();`); await page.getByAltText('Country').click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.get_by_alt_text("Country").click()`); page.get_by_alt_text("Country").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.get_by_alt_text("Country").click()`); await page.get_by_alt_text("Country").click()`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.getByAltText("Country").click()`); page.getByAltText("Country").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.GetByAltText("Country").ClickAsync();`); await page.GetByAltText("Country").ClickAsync();`);
}); });
@ -460,19 +460,19 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.getByLabel('Country').click();`); await page.getByLabel('Country').click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.get_by_label("Country").click()`); page.get_by_label("Country").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.get_by_label("Country").click()`); await page.get_by_label("Country").click()`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.getByLabel("Country").click()`); page.getByLabel("Country").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.GetByLabel("Country").ClickAsync();`); await page.GetByLabel("Country").ClickAsync();`);
}); });
@ -489,19 +489,19 @@ test.describe('cli codegen', () => {
recorder.trustedClick(), recorder.trustedClick(),
]); ]);
expect.soft(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript')!.text).toContain(`
await page.getByLabel('Coun\"try').click();`); await page.getByLabel('Coun\"try').click();`);
expect.soft(sources.get('Python').text).toContain(` expect.soft(sources.get('Python')!.text).toContain(`
page.get_by_label("Coun\\"try").click()`); page.get_by_label("Coun\\"try").click()`);
expect.soft(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async')!.text).toContain(`
await page.get_by_label("Coun\\"try").click()`); await page.get_by_label("Coun\\"try").click()`);
expect.soft(sources.get('Java').text).toContain(` expect.soft(sources.get('Java')!.text).toContain(`
page.getByLabel("Coun\\"try").click()`); page.getByLabel("Coun\\"try").click()`);
expect.soft(sources.get('C#').text).toContain(` expect.soft(sources.get('C#')!.text).toContain(`
await page.GetByLabel("Coun\\"try").ClickAsync();`); await page.GetByLabel("Coun\\"try").ClickAsync();`);
}); });
}); });

View File

@ -18,7 +18,7 @@ import { test as it, expect } from './inspectorTest';
it.skip(({ mode }) => mode !== 'default'); it.skip(({ mode }) => mode !== 'default');
let scriptPromise; let scriptPromise: Promise<void>;
it.beforeEach(async ({ page, recorderPageGetter }) => { it.beforeEach(async ({ page, recorderPageGetter }) => {
scriptPromise = (async () => { scriptPromise = (async () => {

View File

@ -181,10 +181,10 @@ it.describe('pause', () => {
const iframeActionPoint = await iframe.$('x-pw-action-point'); const iframeActionPoint = await iframe.$('x-pw-action-point');
expect(await iframeActionPoint?.boundingBox()).toBeFalsy(); expect(await iframeActionPoint?.boundingBox()).toBeFalsy();
const x1 = box1.x + box1.width / 2; const x1 = box1!.x + box1!.width / 2;
const y1 = box1.y + box1.height / 2; const y1 = box1!.y + box1!.height / 2;
const x2 = box2.x + box2.width / 2; const x2 = box2!.x + box2!.width / 2;
const y2 = box2.y + box2.height / 2; const y2 = box2!.y + box2!.height / 2;
expect(Math.abs(x1 - x2) < 2).toBeTruthy(); expect(Math.abs(x1 - x2) < 2).toBeTruthy();
expect(Math.abs(y1 - y2) < 2).toBeTruthy(); expect(Math.abs(y1 - y2) < 2).toBeTruthy();
@ -391,8 +391,8 @@ it.describe('pause', () => {
const box1 = await box1Promise; const box1 = await box1Promise;
const button = await page.$('text=Submit'); const button = await page.$('text=Submit');
const box2 = await button.boundingBox(); const box2 = await button!.boundingBox();
expect(roundBox(box1)).toEqual(roundBox(box2)); expect(roundBox(box1)).toEqual(roundBox(box2!));
await recorderPage.click('[title="Resume (F8)"]'); await recorderPage.click('[title="Resume (F8)"]');
await scriptPromise; await scriptPromise;
}); });
@ -473,7 +473,7 @@ it.describe('pause', () => {
const box1Promise = waitForTestLog<Box>(page, 'Highlight box for test: '); const box1Promise = waitForTestLog<Box>(page, 'Highlight box for test: ');
await recorderPage.click('[title="Step over (F10)"]'); await recorderPage.click('[title="Step over (F10)"]');
const box2 = roundBox(await page.locator('#target').boundingBox()); const box2 = roundBox((await page.locator('#target').boundingBox())!);
const box1 = roundBox(await box1Promise); const box1 = roundBox(await box1Promise);
expect(box1).toEqual(box2); expect(box1).toEqual(box2);
@ -485,7 +485,7 @@ it.describe('pause', () => {
async function sanitizeLog(recorderPage: Page): Promise<string[]> { async function sanitizeLog(recorderPage: Page): Promise<string[]> {
const results = []; const results = [];
for (const entry of await recorderPage.$$('.call-log-call')) { for (const entry of await recorderPage.$$('.call-log-call')) {
const header = (await (await entry.$('.call-log-call-header')).textContent()).replace(/— [\d.]+(ms|s)/, '- XXms'); const header = (await (await entry.$('.call-log-call-header'))!.textContent())!.replace(/— [\d.]+(ms|s)/, '- XXms');
results.push(header.replace(/page\.waitForEvent\(console\).*/, 'page.waitForEvent(console)')); results.push(header.replace(/page\.waitForEvent\(console\).*/, 'page.waitForEvent(console)'));
results.push(...await entry.$$eval('.call-log-message', ee => ee.map(e => { results.push(...await entry.$$eval('.call-log-message', ee => ee.map(e => {
return (e.classList.contains('error') ? 'error: ' : '') + e.textContent; return (e.classList.contains('error') ? 'error: ' : '') + e.textContent;

View File

@ -14,10 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
import type { Page, Frame, ElementHandle } from '@playwright/test';
import { contextTest as it, expect } from '../config/browserTest'; import { contextTest as it, expect } from '../config/browserTest';
import { attachFrame } from '../config/utils'; import { attachFrame } from '../config/utils';
import type { TestServer } from '../config/testserver';
async function checkSlowMo(toImpl, page, task) { async function checkSlowMo(toImpl: (api: any) => any, page: Page, task: () => Promise<unknown>) {
let didSlowMo = false; let didSlowMo = false;
const contextDebugger = toImpl(page.context()).debugger(); const contextDebugger = toImpl(page.context()).debugger();
contextDebugger._slowMo = 100; contextDebugger._slowMo = 100;
@ -33,7 +35,7 @@ async function checkSlowMo(toImpl, page, task) {
expect(!!didSlowMo).toBe(true); expect(!!didSlowMo).toBe(true);
} }
async function checkPageSlowMo(toImpl, page, task) { async function checkPageSlowMo(toImpl: (api: any) => any, page: Page, task: () => Promise<unknown>) {
await page.setContent(` await page.setContent(`
<button>a</button> <button>a</button>
<input type="checkbox" class="check"> <input type="checkbox" class="check">
@ -169,7 +171,7 @@ it.describe('slowMo', () => {
}); });
}); });
async function checkFrameSlowMo(toImpl, page, server, task) { async function checkFrameSlowMo(toImpl: (api: any) => any, page: Page, server: TestServer, task: (frame: Frame) => Promise<unknown>) {
const frame = await attachFrame(page, 'frame1', server.EMPTY_PAGE); const frame = await attachFrame(page, 'frame1', server.EMPTY_PAGE);
await frame.setContent(` await frame.setContent(`
<button>a</button> <button>a</button>
@ -185,7 +187,7 @@ async function checkFrameSlowMo(toImpl, page, server, task) {
} }
async function checkElementSlowMo(toImpl, page, selector, task) { async function checkElementSlowMo(toImpl: (api: any) => any, page: Page, selector: string, task: (element: ElementHandle<HTMLElement>) => Promise<unknown>) {
await page.setContent(` await page.setContent(`
<button>a</button> <button>a</button>
<input type="checkbox" class="check"> <input type="checkbox" class="check">
@ -196,6 +198,6 @@ async function checkElementSlowMo(toImpl, page, selector, task) {
</select> </select>
<input type="file" class="file"> <input type="file" class="file">
`); `);
const element = await page.$(selector); const element = (await page.$(selector)) as ElementHandle<HTMLElement>;
await checkSlowMo(toImpl, page, task.bind(null, element)); await checkSlowMo(toImpl, page, task.bind(null, element));
} }

View File

@ -15,22 +15,23 @@
* limitations under the License. * limitations under the License.
*/ */
import type { Frame } from '@playwright/test';
import { test as it, expect } from './pageTest'; import { test as it, expect } from './pageTest';
import { attachFrame, detachFrame } from '../config/utils'; import { attachFrame, detachFrame } from '../config/utils';
async function giveItTimeToLog(frame) { async function giveItTimeToLog(frame: Frame) {
await frame.evaluate(() => new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f)))); await frame.evaluate(() => new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f))));
await frame.evaluate(() => new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f)))); await frame.evaluate(() => new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f))));
} }
const addElement = tag => document.body.appendChild(document.createElement(tag)); const addElement = (tag: string) => document.body.appendChild(document.createElement(tag));
it('should throw on waitFor', async ({ page, server }) => { it('should throw on waitFor', async ({ page, server }) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
let error; let error;
// @ts-expect-error waitFor is undocumented // @ts-expect-error waitFor is undocumented
await page.waitForSelector('*', { waitFor: 'attached' }).catch(e => error = e); await page.waitForSelector('*', { waitFor: 'attached' }).catch(e => error = e);
expect(error.message).toContain('options.waitFor is not supported, did you mean options.state?'); expect(error!.message).toContain('options.waitFor is not supported, did you mean options.state?');
}); });
it('should tolerate waitFor=visible', async ({ page, server }) => { it('should tolerate waitFor=visible', async ({ page, server }) => {
@ -51,14 +52,14 @@ it('should immediately resolve promise if node exists', async ({ page, server })
it('elementHandle.waitForSelector should immediately resolve if node exists', async ({ page }) => { it('elementHandle.waitForSelector should immediately resolve if node exists', async ({ page }) => {
await page.setContent(`<span>extra</span><div><span>target</span></div>`); await page.setContent(`<span>extra</span><div><span>target</span></div>`);
const div = await page.$('div'); const div = (await page.$('div'))!;
const span = await div.waitForSelector('span', { state: 'attached' }); const span = await div.waitForSelector('span', { state: 'attached' });
expect(await span.evaluate(e => e.textContent)).toBe('target'); expect(await span.evaluate(e => e.textContent)).toBe('target');
}); });
it('elementHandle.waitForSelector should wait', async ({ page }) => { it('elementHandle.waitForSelector should wait', async ({ page }) => {
await page.setContent(`<div></div>`); await page.setContent(`<div></div>`);
const div = await page.$('div'); const div = (await page.$('div'))!;
const promise = div.waitForSelector('span', { state: 'attached' }); const promise = div.waitForSelector('span', { state: 'attached' });
await div.evaluate(div => div.innerHTML = '<span>target</span>'); await div.evaluate(div => div.innerHTML = '<span>target</span>');
const span = await promise; const span = await promise;
@ -67,14 +68,14 @@ it('elementHandle.waitForSelector should wait', async ({ page }) => {
it('elementHandle.waitForSelector should timeout', async ({ page }) => { it('elementHandle.waitForSelector should timeout', async ({ page }) => {
await page.setContent(`<div></div>`); await page.setContent(`<div></div>`);
const div = await page.$('div'); const div = (await page.$('div'))!;
const error = await div.waitForSelector('span', { timeout: 100 }).catch(e => e); const error = await div.waitForSelector('span', { timeout: 100 }).catch(e => e);
expect(error.message).toContain('Timeout 100ms exceeded.'); expect(error.message).toContain('Timeout 100ms exceeded.');
}); });
it('elementHandle.waitForSelector should throw on navigation', async ({ page, server }) => { it('elementHandle.waitForSelector should throw on navigation', async ({ page, server }) => {
await page.setContent(`<div></div>`); await page.setContent(`<div></div>`);
const div = await page.$('div'); const div = (await page.$('div'))!;
const promise = div.waitForSelector('span').catch(e => e); const promise = div.waitForSelector('span').catch(e => e);
// Give it some time before navigating. // Give it some time before navigating.
for (let i = 0; i < 10; i++) for (let i = 0; i < 10; i++)
@ -84,8 +85,8 @@ it('elementHandle.waitForSelector should throw on navigation', async ({ page, se
expect(error.message).toContain(`waiting for locator('span') to be visible`); expect(error.message).toContain(`waiting for locator('span') to be visible`);
}); });
it('should work with removed MutationObserver', async ({ page, server }) => { it('should work with removed MutationObserver', async ({ page }) => {
await page.evaluate(() => delete window.MutationObserver); await page.evaluate(() => delete (window as any).MutationObserver);
const [handle] = await Promise.all([ const [handle] = await Promise.all([
page.waitForSelector('.zombo'), page.waitForSelector('.zombo'),
page.setContent(`<div class='zombo'>anything</div>`), page.setContent(`<div class='zombo'>anything</div>`),
@ -120,7 +121,7 @@ it('should report logs while waiting for visible', async ({ page, server }) => {
}); });
await giveItTimeToLog(frame); await giveItTimeToLog(frame);
await frame.evaluate(() => document.querySelector('div').remove()); await frame.evaluate(() => document.querySelector('div')!.remove());
await giveItTimeToLog(frame); await giveItTimeToLog(frame);
await frame.evaluate(() => { await frame.evaluate(() => {
@ -153,7 +154,7 @@ it('should report logs while waiting for hidden', async ({ page, server }) => {
await giveItTimeToLog(frame); await giveItTimeToLog(frame);
await frame.evaluate(() => { await frame.evaluate(() => {
document.querySelector('div').remove(); document.querySelector('div')!.remove();
const div = document.createElement('div'); const div = document.createElement('div');
div.className = 'another'; div.className = 'another';
div.textContent = 'hello'; div.textContent = 'hello';
@ -192,7 +193,7 @@ it('should resolve promise when node is added in shadow dom', async ({ page, ser
await page.evaluate(() => { await page.evaluate(() => {
const span = document.createElement('span'); const span = document.createElement('span');
span.textContent = 'Hello from shadow'; span.textContent = 'Hello from shadow';
document.querySelector('div').shadowRoot.appendChild(span); document.querySelector('div')!.shadowRoot!.appendChild(span);
}); });
const handle = await watchdog; const handle = await watchdog;
expect(await handle.evaluate(e => e.textContent)).toBe('Hello from shadow'); expect(await handle.evaluate(e => e.textContent)).toBe('Hello from shadow');
@ -202,7 +203,7 @@ it('should work when node is added through innerHTML', async ({ page, server })
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const watchdog = page.waitForSelector('h3 div', { state: 'attached' }); const watchdog = page.waitForSelector('h3 div', { state: 'attached' });
await page.evaluate(addElement, 'span'); await page.evaluate(addElement, 'span');
await page.evaluate(() => document.querySelector('span').innerHTML = '<h3><div></div></h3>'); await page.evaluate(() => document.querySelector('span')!.innerHTML = '<h3><div></div></h3>');
await watchdog; await watchdog;
}); });
@ -237,5 +238,5 @@ it('should throw when frame is detached', async ({ page, server }) => {
await detachFrame(page, 'frame1'); await detachFrame(page, 'frame1');
await waitPromise; await waitPromise;
expect(waitError).toBeTruthy(); expect(waitError).toBeTruthy();
expect(waitError.message).toContain('frame.waitForSelector: Frame was detached'); expect(waitError!.message).toContain('frame.waitForSelector: Frame was detached');
}); });

View File

@ -18,7 +18,7 @@
import { test as it, expect } from './pageTest'; import { test as it, expect } from './pageTest';
import { attachFrame, detachFrame } from '../config/utils'; import { attachFrame, detachFrame } from '../config/utils';
const addElement = tag => document.body.appendChild(document.createElement(tag)); const addElement = (tag: string) => document.body.appendChild(document.createElement(tag));
it('should survive cross-process navigation', async ({ page, server }) => { it('should survive cross-process navigation', async ({ page, server }) => {
let boxFound = false; let boxFound = false;
@ -37,9 +37,9 @@ it('should wait for visible', async ({ page, server }) => {
const waitForSelector = page.waitForSelector('div').then(() => divFound = true); const waitForSelector = page.waitForSelector('div').then(() => divFound = true);
await page.setContent(`<div style='display: none; visibility: hidden;'>1</div>`); await page.setContent(`<div style='display: none; visibility: hidden;'>1</div>`);
expect(divFound).toBe(false); expect(divFound).toBe(false);
await page.evaluate(() => document.querySelector('div').style.removeProperty('display')); await page.evaluate(() => document.querySelector('div')!.style.removeProperty('display'));
expect(divFound).toBe(false); expect(divFound).toBe(false);
await page.evaluate(() => document.querySelector('div').style.removeProperty('visibility')); await page.evaluate(() => document.querySelector('div')!.style.removeProperty('visibility'));
expect(await waitForSelector).toBe(true); expect(await waitForSelector).toBe(true);
expect(divFound).toBe(true); expect(divFound).toBe(true);
}); });
@ -48,10 +48,10 @@ it('should not consider visible when zero-sized', async ({ page, server }) => {
await page.setContent(`<div style='width: 0; height: 0;'>1</div>`); await page.setContent(`<div style='width: 0; height: 0;'>1</div>`);
let error = await page.waitForSelector('div', { timeout: 1000 }).catch(e => e); let error = await page.waitForSelector('div', { timeout: 1000 }).catch(e => e);
expect(error.message).toContain('page.waitForSelector: Timeout 1000ms exceeded'); expect(error.message).toContain('page.waitForSelector: Timeout 1000ms exceeded');
await page.evaluate(() => document.querySelector('div').style.width = '10px'); await page.evaluate(() => document.querySelector('div')!.style.width = '10px');
error = await page.waitForSelector('div', { timeout: 1000 }).catch(e => e); error = await page.waitForSelector('div', { timeout: 1000 }).catch(e => e);
expect(error.message).toContain('page.waitForSelector: Timeout 1000ms exceeded'); expect(error.message).toContain('page.waitForSelector: Timeout 1000ms exceeded');
await page.evaluate(() => document.querySelector('div').style.height = '10px'); await page.evaluate(() => document.querySelector('div')!.style.height = '10px');
expect(await page.waitForSelector('div', { timeout: 1000 })).toBeTruthy(); expect(await page.waitForSelector('div', { timeout: 1000 })).toBeTruthy();
}); });
@ -60,9 +60,9 @@ it('should wait for visible recursively', async ({ page, server }) => {
const waitForSelector = page.waitForSelector('div#inner').then(() => divVisible = true); const waitForSelector = page.waitForSelector('div#inner').then(() => divVisible = true);
await page.setContent(`<div style='display: none; visibility: hidden;'><div id="inner">hi</div></div>`); await page.setContent(`<div style='display: none; visibility: hidden;'><div id="inner">hi</div></div>`);
expect(divVisible).toBe(false); expect(divVisible).toBe(false);
await page.evaluate(() => document.querySelector('div').style.removeProperty('display')); await page.evaluate(() => document.querySelector('div')!.style.removeProperty('display'));
expect(divVisible).toBe(false); expect(divVisible).toBe(false);
await page.evaluate(() => document.querySelector('div').style.removeProperty('visibility')); await page.evaluate(() => document.querySelector('div')!.style.removeProperty('visibility'));
expect(await waitForSelector).toBe(true); expect(await waitForSelector).toBe(true);
expect(divVisible).toBe(true); expect(divVisible).toBe(true);
}); });
@ -94,7 +94,7 @@ it('hidden should wait for hidden', async ({ page, server }) => {
const waitForSelector = page.waitForSelector('div', { state: 'hidden' }).then(() => divHidden = true); const waitForSelector = page.waitForSelector('div', { state: 'hidden' }).then(() => divHidden = true);
await page.waitForSelector('div'); // do a round trip await page.waitForSelector('div'); // do a round trip
expect(divHidden).toBe(false); expect(divHidden).toBe(false);
await page.evaluate(() => document.querySelector('div').style.setProperty('visibility', 'hidden')); await page.evaluate(() => document.querySelector('div')!.style.setProperty('visibility', 'hidden'));
expect(await waitForSelector).toBe(true); expect(await waitForSelector).toBe(true);
expect(divHidden).toBe(true); expect(divHidden).toBe(true);
}); });
@ -105,7 +105,7 @@ it('hidden should wait for display: none', async ({ page, server }) => {
const waitForSelector = page.waitForSelector('div', { state: 'hidden' }).then(() => divHidden = true); const waitForSelector = page.waitForSelector('div', { state: 'hidden' }).then(() => divHidden = true);
await page.waitForSelector('div'); // do a round trip await page.waitForSelector('div'); // do a round trip
expect(divHidden).toBe(false); expect(divHidden).toBe(false);
await page.evaluate(() => document.querySelector('div').style.setProperty('display', 'none')); await page.evaluate(() => document.querySelector('div')!.style.setProperty('display', 'none'));
expect(await waitForSelector).toBe(true); expect(await waitForSelector).toBe(true);
expect(divHidden).toBe(true); expect(divHidden).toBe(true);
}); });
@ -116,7 +116,7 @@ it('hidden should wait for removal', async ({ page, server }) => {
const waitForSelector = page.waitForSelector('div', { state: 'hidden' }).then(() => divRemoved = true); const waitForSelector = page.waitForSelector('div', { state: 'hidden' }).then(() => divRemoved = true);
await page.waitForSelector('div'); // do a round trip await page.waitForSelector('div'); // do a round trip
expect(divRemoved).toBe(false); expect(divRemoved).toBe(false);
await page.evaluate(() => document.querySelector('div').remove()); await page.evaluate(() => document.querySelector('div')!.remove());
expect(await waitForSelector).toBe(true); expect(await waitForSelector).toBe(true);
expect(divRemoved).toBe(true); expect(divRemoved).toBe(true);
}); });
@ -127,21 +127,21 @@ it('should return null if waiting to hide non-existing element', async ({ page,
}); });
it('should respect timeout', async ({ page, playwright }) => { it('should respect timeout', async ({ page, playwright }) => {
let error = null; let error: Error | undefined;
await page.waitForSelector('div', { timeout: 3000, state: 'attached' }).catch(e => error = e); await page.waitForSelector('div', { timeout: 3000, state: 'attached' }).catch(e => error = e);
expect(error).toBeTruthy(); expect(error).toBeTruthy();
expect(error.message).toContain('page.waitForSelector: Timeout 3000ms exceeded'); expect(error!.message).toContain('page.waitForSelector: Timeout 3000ms exceeded');
expect(error.message).toContain('waiting for locator(\'div\')'); expect(error!.message).toContain('waiting for locator(\'div\')');
expect(error).toBeInstanceOf(playwright.errors.TimeoutError); expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
}); });
it('should have an error message specifically for awaiting an element to be hidden', async ({ page, server }) => { it('should have an error message specifically for awaiting an element to be hidden', async ({ page, server }) => {
await page.setContent(`<div>content</div>`); await page.setContent(`<div>content</div>`);
let error = null; let error: Error | undefined;
await page.waitForSelector('div', { state: 'hidden', timeout: 1000 }).catch(e => error = e); await page.waitForSelector('div', { state: 'hidden', timeout: 1000 }).catch(e => error = e);
expect(error).toBeTruthy(); expect(error).toBeTruthy();
expect(error.message).toContain('page.waitForSelector: Timeout 1000ms exceeded'); expect(error!.message).toContain('page.waitForSelector: Timeout 1000ms exceeded');
expect(error.message).toContain('waiting for locator(\'div\') to be hidden'); expect(error!.message).toContain('waiting for locator(\'div\') to be hidden');
}); });
it('should respond to node attribute mutation', async ({ page, server }) => { it('should respond to node attribute mutation', async ({ page, server }) => {
@ -149,7 +149,7 @@ it('should respond to node attribute mutation', async ({ page, server }) => {
const waitForSelector = page.waitForSelector('.zombo', { state: 'attached' }).then(() => divFound = true); const waitForSelector = page.waitForSelector('.zombo', { state: 'attached' }).then(() => divFound = true);
await page.setContent(`<div class='notZombo'></div>`); await page.setContent(`<div class='notZombo'></div>`);
expect(divFound).toBe(false); expect(divFound).toBe(false);
await page.evaluate(() => document.querySelector('div').className = 'zombo'); await page.evaluate(() => document.querySelector('div')!.className = 'zombo');
expect(await waitForSelector).toBe(true); expect(await waitForSelector).toBe(true);
}); });
@ -162,7 +162,7 @@ it('should return the element handle', async ({ page, server }) => {
it('should have correct stack trace for timeout', async ({ page, server }) => { it('should have correct stack trace for timeout', async ({ page, server }) => {
let error; let error;
await page.waitForSelector('.zombo', { timeout: 10 }).catch(e => error = e); await page.waitForSelector('.zombo', { timeout: 10 }).catch(e => error = e);
expect(error.stack).toContain('wait-for-selector'); expect(error!.stack).toContain('wait-for-selector');
}); });
it('should throw for unknown state option', async ({ page, server }) => { it('should throw for unknown state option', async ({ page, server }) => {
@ -199,7 +199,7 @@ it('should support >> selector syntax', async ({ page, server }) => {
const watchdog = frame.waitForSelector('css=div >> css=span', { state: 'attached' }); const watchdog = frame.waitForSelector('css=div >> css=span', { state: 'attached' });
await frame.evaluate(addElement, 'br'); await frame.evaluate(addElement, 'br');
await frame.evaluate(addElement, 'div'); await frame.evaluate(addElement, 'div');
await frame.evaluate(() => document.querySelector('div').appendChild(document.createElement('span'))); await frame.evaluate(() => document.querySelector('div')!.appendChild(document.createElement('span')));
const eHandle = await watchdog; const eHandle = await watchdog;
const tagName = await eHandle.getProperty('tagName').then(e => e.jsonValue()); const tagName = await eHandle.getProperty('tagName').then(e => e.jsonValue());
expect(tagName).toBe('SPAN'); expect(tagName).toBe('SPAN');
@ -229,11 +229,11 @@ it('should support some fancy xpath', async ({ page, server }) => {
}); });
it('should respect timeout xpath', async ({ page, playwright }) => { it('should respect timeout xpath', async ({ page, playwright }) => {
let error = null; let error: Error | undefined;
await page.waitForSelector('//div', { state: 'attached', timeout: 3000 }).catch(e => error = e); await page.waitForSelector('//div', { state: 'attached', timeout: 3000 }).catch(e => error = e);
expect(error).toBeTruthy(); expect(error).toBeTruthy();
expect(error.message).toContain('page.waitForSelector: Timeout 3000ms exceeded'); expect(error!.message).toContain('page.waitForSelector: Timeout 3000ms exceeded');
expect(error.message).toContain('waiting for locator(\'//div\')'); expect(error!.message).toContain('waiting for locator(\'//div\')');
expect(error).toBeInstanceOf(playwright.errors.TimeoutError); expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
}); });
@ -252,12 +252,12 @@ it('should run in specified frame xpath', async ({ page, server }) => {
it('should throw when frame is detached xpath', async ({ page, server }) => { it('should throw when frame is detached xpath', async ({ page, server }) => {
await attachFrame(page, 'frame1', server.EMPTY_PAGE); await attachFrame(page, 'frame1', server.EMPTY_PAGE);
const frame = page.frames()[1]; const frame = page.frames()[1];
let waitError = null; let waitError: Error | undefined;
const waitPromise = frame.waitForSelector('//*[@class="box"]').catch(e => waitError = e); const waitPromise = frame.waitForSelector('//*[@class="box"]').catch(e => waitError = e);
await detachFrame(page, 'frame1'); await detachFrame(page, 'frame1');
await waitPromise; await waitPromise;
expect(waitError).toBeTruthy(); expect(waitError).toBeTruthy();
expect(waitError.message).toContain('frame.waitForSelector: Frame was detached'); expect(waitError!.message).toContain('frame.waitForSelector: Frame was detached');
}); });
it('should return the element handle xpath', async ({ page, server }) => { it('should return the element handle xpath', async ({ page, server }) => {

View File

@ -15,9 +15,10 @@
* limitations under the License. * limitations under the License.
*/ */
import type { Page } from '@playwright/test';
import { test as it, expect } from './pageTest'; import { test as it, expect } from './pageTest';
async function giveItAChanceToResolve(page) { async function giveItAChanceToResolve(page: Page) {
for (let i = 0; i < 5; i++) for (let i = 0; i < 5; i++)
await page.evaluate(() => new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f)))); await page.evaluate(() => new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f))));
} }
@ -40,7 +41,7 @@ it('element state checks should work as expected for label with zero-sized input
it('should wait for enclosing disabled button', async ({ page }) => { it('should wait for enclosing disabled button', async ({ page }) => {
await page.setContent('<button><span>Target</span></button>'); await page.setContent('<button><span>Target</span></button>');
const span = await page.$('text=Target'); const span = (await page.$('text=Target'))!;
let done = false; let done = false;
const promise = span.waitForElementState('disabled').then(() => done = true); const promise = span.waitForElementState('disabled').then(() => done = true);
await giveItAChanceToResolve(page); await giveItAChanceToResolve(page);
@ -51,18 +52,18 @@ it('should wait for enclosing disabled button', async ({ page }) => {
it('should wait for enclosing button with a disabled fieldset', async ({ page }) => { it('should wait for enclosing button with a disabled fieldset', async ({ page }) => {
await page.setContent('<fieldset disabled=true><button><span>Target</span></button></div>'); await page.setContent('<fieldset disabled=true><button><span>Target</span></button></div>');
const span = await page.$('text=Target'); const span = (await page.$('text=Target'))!;
let done = false; let done = false;
const promise = span.waitForElementState('enabled').then(() => done = true); const promise = span.waitForElementState('enabled').then(() => done = true);
await giveItAChanceToResolve(page); await giveItAChanceToResolve(page);
expect(done).toBe(false); expect(done).toBe(false);
await span.evaluate(span => (span.parentElement.parentElement as HTMLFieldSetElement).disabled = false); await span.evaluate((span: HTMLElement) => (span.parentElement!.parentElement as HTMLFieldSetElement).disabled = false);
await promise; await promise;
}); });
it('should wait for enclosing enabled button', async ({ page, server }) => { it('should wait for enclosing enabled button', async ({ page, server }) => {
await page.setContent('<button disabled><span>Target</span></button>'); await page.setContent('<button disabled><span>Target</span></button>');
const span = await page.$('text=Target'); const span = (await page.$('text=Target'))!;
let done = false; let done = false;
const promise = span.waitForElementState('enabled').then(() => done = true); const promise = span.waitForElementState('enabled').then(() => done = true);
await giveItAChanceToResolve(page); await giveItAChanceToResolve(page);
@ -91,8 +92,8 @@ it('should check the box outside shadow dom label', async ({ page }) => {
it('setInputFiles should work with label', async ({ page, asset }) => { it('setInputFiles should work with label', async ({ page, asset }) => {
await page.setContent(`<label for=target>Choose a file</label><input id=target type=file>`); await page.setContent(`<label for=target>Choose a file</label><input id=target type=file>`);
await page.setInputFiles('text=Choose a file', asset('file-to-upload.txt')); await page.setInputFiles('text=Choose a file', asset('file-to-upload.txt'));
expect(await page.$eval('input', input => input.files.length)).toBe(1); expect(await page.$eval('input', (input: HTMLInputElement) => input.files!.length)).toBe(1);
expect(await page.$eval('input', input => input.files[0].name)).toBe('file-to-upload.txt'); expect(await page.$eval('input', (input: HTMLInputElement) => input.files?.[0].name)).toBe('file-to-upload.txt');
}); });
type Options = { disabled?: boolean, hidden?: boolean, readonly?: boolean }; type Options = { disabled?: boolean, hidden?: boolean, readonly?: boolean };
@ -123,7 +124,7 @@ it('enabled/disabled retargeting', async ({ page, asset }) => {
await it.step(`"${locator}" in "${dom}" should be enabled=${enabled}`, async () => { await it.step(`"${locator}" in "${dom}" should be enabled=${enabled}`, async () => {
await page.setContent(dom); await page.setContent(dom);
const target = page.locator(locator); const target = page.locator(locator);
const handle = await page.$(locator); const handle = (await page.$(locator))!;
expect(await target.isEnabled()).toBe(enabled); expect(await target.isEnabled()).toBe(enabled);
expect(await target.isDisabled()).toBe(!enabled); expect(await target.isDisabled()).toBe(!enabled);
if (enabled) { if (enabled) {
@ -161,7 +162,7 @@ it('visible/hidden retargeting', async ({ page, asset }) => {
await it.step(`"${locator}" in "${dom}" should be visible=${visible}`, async () => { await it.step(`"${locator}" in "${dom}" should be visible=${visible}`, async () => {
await page.setContent(dom); await page.setContent(dom);
const target = page.locator(locator); const target = page.locator(locator);
const handle = await page.$(locator); const handle = (await page.$(locator))!;
expect(await target.isVisible()).toBe(visible); expect(await target.isVisible()).toBe(visible);
expect(await target.isHidden()).toBe(!visible); expect(await target.isHidden()).toBe(!visible);
if (visible) { if (visible) {
@ -197,7 +198,7 @@ it('editable retargeting', async ({ page, asset }) => {
await it.step(`"${locator}" in "${dom}" should be editable=${editable}`, async () => { await it.step(`"${locator}" in "${dom}" should be editable=${editable}`, async () => {
await page.setContent(dom); await page.setContent(dom);
const target = page.locator(locator); const target = page.locator(locator);
const handle = await page.$(locator); const handle = (await page.$(locator))!;
expect(await target.isEditable()).toBe(editable); expect(await target.isEditable()).toBe(editable);
if (editable) { if (editable) {
await expect(target).toBeEditable(); await expect(target).toBeEditable();
@ -222,7 +223,7 @@ it('input value retargeting', async ({ page, browserName }) => {
await it.step(`"${locator}" in "${dom}" input value`, async () => { await it.step(`"${locator}" in "${dom}" input value`, async () => {
await page.setContent(dom); await page.setContent(dom);
const target = page.locator(locator); const target = page.locator(locator);
const handle = await page.$(locator); const handle = (await page.$(locator))!;
expect(await target.inputValue()).toBe(''); expect(await target.inputValue()).toBe('');
expect(await handle.inputValue()).toBe(''); expect(await handle.inputValue()).toBe('');
@ -243,7 +244,7 @@ it('input value retargeting', async ({ page, browserName }) => {
expect(await page.locator('#target').evaluate((el: HTMLInputElement) => el.selectionStart)).toBe(0); expect(await page.locator('#target').evaluate((el: HTMLInputElement) => el.selectionStart)).toBe(0);
expect(await page.locator('#target').evaluate((el: HTMLInputElement) => el.selectionEnd)).toBe(3); expect(await page.locator('#target').evaluate((el: HTMLInputElement) => el.selectionEnd)).toBe(3);
} else { } else {
expect(await page.evaluate(() => window.getSelection().toString())).toBe('bar'); expect(await page.evaluate(() => window.getSelection()!.toString())).toBe('bar');
} }
}); });
} }
@ -260,7 +261,7 @@ it.fixme('selection retargeting', async ({ page, browserName }) => {
await it.step(`"${locator}" in "${dom}" text selection`, async () => { await it.step(`"${locator}" in "${dom}" text selection`, async () => {
await page.setContent(dom); await page.setContent(dom);
const target = page.locator(locator); const target = page.locator(locator);
const handle = await page.$(locator); const handle = (await page.$(locator))!;
expect(await target.isEditable()).toBe(true); expect(await target.isEditable()).toBe(true);
expect(await handle.isEditable()).toBe(true); expect(await handle.isEditable()).toBe(true);
@ -272,11 +273,11 @@ it.fixme('selection retargeting', async ({ page, browserName }) => {
await target.selectText(); await target.selectText();
if (browserName === 'firefox') { if (browserName === 'firefox') {
expect(await page.$eval('#target', target => { expect(await page.$eval('#target', target => {
const selection = window.getSelection(); const selection = window.getSelection()!;
return selection.anchorNode === target && selection.focusNode === target; return selection.anchorNode === target && selection.focusNode === target;
})).toBe(true); })).toBe(true);
} else { } else {
expect(await page.evaluate(() => window.getSelection().toString())).toBe('foo'); expect(await page.evaluate(() => window.getSelection()!.toString())).toBe('foo');
} }
}); });
} }
@ -295,7 +296,7 @@ it('select options retargeting', async ({ page }) => {
await it.step(`"${locator}" in "${dom}" select option`, async () => { await it.step(`"${locator}" in "${dom}" select option`, async () => {
await page.setContent(dom); await page.setContent(dom);
const target = page.locator(locator); const target = page.locator(locator);
const handle = await page.$(locator); const handle = (await page.$(locator))!;
expect(await target.inputValue()).toBe('dog'); expect(await target.inputValue()).toBe('dog');
expect(await handle.inputValue()).toBe('dog'); expect(await handle.inputValue()).toBe('dog');

View File

@ -15,6 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import type { ElementHandle } from '@playwright/test';
import { test as it, expect } from './pageTest'; import { test as it, expect } from './pageTest';
it('should work with large DOM @smoke', async ({ page, server }) => { it('should work with large DOM @smoke', async ({ page, server }) => {
@ -90,10 +91,10 @@ it('should work for open shadow roots', async ({ page, server }) => {
expect(await page.$eval(`css=section > div div span:nth-child(2)`, e => e.textContent)).toBe('Hello from root3 #2'); expect(await page.$eval(`css=section > div div span:nth-child(2)`, e => e.textContent)).toBe('Hello from root3 #2');
expect(await page.$(`css=section div div div div`)).toBe(null); expect(await page.$(`css=section div div div div`)).toBe(null);
const root2 = await page.$(`css=div div`); const root2 = (await page.$(`css=div div`))!;
expect(await root2.$eval(`css=#target`, e => e.textContent)).toBe('Hello from root2'); expect(await root2.$eval(`css=#target`, e => e.textContent)).toBe('Hello from root2');
expect(await root2.$(`css:light=#target`)).toBe(null); expect(await root2.$(`css:light=#target`)).toBe(null);
const root2Shadow = await root2.evaluateHandle(r => r.shadowRoot); const root2Shadow = (await root2.evaluateHandle(r => r.shadowRoot) as ElementHandle<ShadowRoot>)!;
expect(await root2Shadow.$eval(`css:light=#target`, e => e.textContent)).toBe('Hello from root2'); expect(await root2Shadow.$eval(`css:light=#target`, e => e.textContent)).toBe('Hello from root2');
const root3 = (await page.$$(`css=div div`))[1]; const root3 = (await page.$$(`css=div div`))[1];
expect(await root3.$eval(`text=root3`, e => e.textContent)).toBe('Hello from root3'); expect(await root3.$eval(`text=root3`, e => e.textContent)).toBe('Hello from root3');
@ -178,7 +179,7 @@ it('should work with comma inside text', async ({ page }) => {
it('should work with attribute selectors', async ({ page }) => { it('should work with attribute selectors', async ({ page }) => {
await page.setContent(`<div attr="hello world" attr2="hello-''>>foo=bar[]" attr3="] span"><span></span></div>`); await page.setContent(`<div attr="hello world" attr2="hello-''>>foo=bar[]" attr3="] span"><span></span></div>`);
await page.evaluate(() => window['div'] = document.querySelector('div')); await page.evaluate(() => (window as any)['div'] = document.querySelector('div'));
const selectors = [ const selectors = [
`[attr="hello world"]`, `[attr="hello world"]`,
`[attr = "hello world"]`, `[attr = "hello world"]`,
@ -194,10 +195,10 @@ it('should work with attribute selectors', async ({ page }) => {
`[attr2 $="foo=bar[]"]`, `[attr2 $="foo=bar[]"]`,
]; ];
for (const selector of selectors) for (const selector of selectors)
expect(await page.$eval(selector, e => e === window['div'])).toBe(true); expect(await page.$eval(selector, e => e === (window as any)['div'])).toBe(true);
expect(await page.$eval(`[attr*=hello] span`, e => e.parentNode === window['div'])).toBe(true); expect(await page.$eval(`[attr*=hello] span`, e => e.parentNode === (window as any)['div'])).toBe(true);
expect(await page.$eval(`[attr*=hello] >> span`, e => e.parentNode === window['div'])).toBe(true); expect(await page.$eval(`[attr*=hello] >> span`, e => e.parentNode === (window as any)['div'])).toBe(true);
expect(await page.$eval(`[attr3="] span"] >> span`, e => e.parentNode === window['div'])).toBe(true); expect(await page.$eval(`[attr3="] span"] >> span`, e => e.parentNode === (window as any)['div'])).toBe(true);
}); });
it('should not match root after >>', async ({ page, server }) => { it('should not match root after >>', async ({ page, server }) => {
@ -236,7 +237,7 @@ it('should work with *', async ({ page }) => {
expect(await page.$$eval('div *', els => els.length)).toBe(2); expect(await page.$$eval('div *', els => els.length)).toBe(2);
expect(await page.$$eval('* > *', els => els.length)).toBe(6); expect(await page.$$eval('* > *', els => els.length)).toBe(6);
const body = await page.$('body'); const body = (await page.$('body')) as ElementHandle<HTMLBodyElement>;
// Does not include html, head or body. // Does not include html, head or body.
expect(await body.$$eval('*', els => els.length)).toBe(4); expect(await body.$$eval('*', els => els.length)).toBe(4);
expect(await body.$$eval('*#div1', els => els.length)).toBe(1); expect(await body.$$eval('*#div1', els => els.length)).toBe(1);
@ -386,7 +387,7 @@ it('should work with :scope', async ({ page, server }) => {
// 'has' does change the scope, so it becomes the 'div' we are querying. // 'has' does change the scope, so it becomes the 'div' we are querying.
expect(await page.$$eval(`css=div:has(:scope > #target)`, els => els.length)).toBe(1); expect(await page.$$eval(`css=div:has(:scope > #target)`, els => els.length)).toBe(1);
const handle = await page.$(`css=span`); const handle = await page.$(`css=span`) as ElementHandle;
for (const scope of [page, handle]) { for (const scope of [page, handle]) {
expect(await scope.$$eval(`css=:scope`, els => els.length)).toBe(1); expect(await scope.$$eval(`css=:scope`, els => els.length)).toBe(1);
expect(await scope.$$eval(`css=* :scope`, els => els.length)).toBe(0); expect(await scope.$$eval(`css=* :scope`, els => els.length)).toBe(0);
@ -439,7 +440,7 @@ it('css on the handle should be relative', async ({ page }) => {
`); `);
expect(await page.$eval(`.find-me`, e => e.id)).toBe('target1'); expect(await page.$eval(`.find-me`, e => e.id)).toBe('target1');
const div = await page.$('div'); const div = await page.$('div') as ElementHandle;
expect(await div.$eval(`.find-me`, e => e.id)).toBe('target2'); expect(await div.$eval(`.find-me`, e => e.id)).toBe('target2');
expect(await page.$eval(`div >> .find-me`, e => e.id)).toBe('target2'); expect(await page.$eval(`div >> .find-me`, e => e.id)).toBe('target2');
}); });