diff --git a/src/browser.ts b/src/browser.ts index 04178c73ef..c2ca643607 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -30,12 +30,11 @@ export interface BrowserProcess { close(): Promise; } -export type BrowserOptions = { +export type BrowserOptions = types.UIOptions & { name: string, downloadsPath?: string, headful?: boolean, persistent?: types.BrowserContextOptions, // Undefined means no persistent context. - slowMo?: number, browserProcess: BrowserProcess, proxy?: ProxySettings, }; diff --git a/src/chromium/crBrowser.ts b/src/chromium/crBrowser.ts index e9845dc392..6342b77e56 100644 --- a/src/chromium/crBrowser.ts +++ b/src/chromium/crBrowser.ts @@ -21,7 +21,7 @@ import { Events as CommonEvents } from '../events'; import { assert } from '../helper'; import * as network from '../network'; import { Page, PageBinding, Worker } from '../page'; -import { ConnectionTransport, SlowMoTransport } from '../transport'; +import { ConnectionTransport } from '../transport'; import * as types from '../types'; import { ConnectionEvents, CRConnection, CRSession } from './crConnection'; import { CRPage } from './crPage'; @@ -48,7 +48,7 @@ export class CRBrowser extends BrowserBase { private _tracingClient: CRSession | undefined; static async connect(transport: ConnectionTransport, options: BrowserOptions, devtools?: CRDevTools): Promise { - const connection = new CRConnection(SlowMoTransport.wrap(transport, options.slowMo)); + const connection = new CRConnection(transport); const browser = new CRBrowser(connection, options); browser._devtools = devtools; const session = connection.rootSession; diff --git a/src/dom.ts b/src/dom.ts index 60a991358b..513cc559d9 100644 --- a/src/dom.ts +++ b/src/dom.ts @@ -103,6 +103,10 @@ export class FrameExecutionContext extends js.ExecutionContext { } return this._debugScriptPromise; } + + async doSlowMo() { + return this.frame._page._doSlowMo(); + } } export class ElementHandle extends js.JSHandle { @@ -200,6 +204,7 @@ export class ElementHandle extends js.JSHandle { async dispatchEvent(type: string, eventInit: Object = {}) { await this._evaluateInMain(([injected, node, { type, eventInit }]) => injected.dispatchEvent(node, type, eventInit), { type, eventInit }); + await this._page._doSlowMo(); } async _scrollRectIntoViewIfNeeded(rect?: types.Rect): Promise<'error:notvisible' | 'error:notconnected' | 'done'> { @@ -407,7 +412,9 @@ export class ElementHandle extends js.JSHandle { const selectOptions = [...elements, ...values]; return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => { progress.throwIfAborted(); // Avoid action that has side-effects. - return throwFatalDOMError(await this._evaluateInUtility(([injected, node, selectOptions]) => injected.selectOptions(node, selectOptions), selectOptions)); + const value = await this._evaluateInUtility(([injected, node, selectOptions]) => injected.selectOptions(node, selectOptions), selectOptions); + await this._page._doSlowMo(); + return throwFatalDOMError(value); }); } @@ -480,12 +487,14 @@ export class ElementHandle extends js.JSHandle { progress.throwIfAborted(); // Avoid action that has side-effects. await this._page._delegate.setInputFiles(this as any as ElementHandle, files); }); + await this._page._doSlowMo(); return 'done'; } async focus(): Promise { - return this._page._runAbortableTask(async progress => { + await this._page._runAbortableTask(async progress => { const result = await this._focus(progress); + await this._page._doSlowMo(); return assertDone(throwRetargetableDOMError(result)); }, 0); } diff --git a/src/firefox/ffBrowser.ts b/src/firefox/ffBrowser.ts index 20998a9a2f..63fd490afc 100644 --- a/src/firefox/ffBrowser.ts +++ b/src/firefox/ffBrowser.ts @@ -21,7 +21,7 @@ import { Events } from '../events'; import { assert, helper, RegisteredListener } from '../helper'; import * as network from '../network'; import { Page, PageBinding } from '../page'; -import { ConnectionTransport, SlowMoTransport } from '../transport'; +import { ConnectionTransport } from '../transport'; import * as types from '../types'; import { ConnectionEvents, FFConnection } from './ffConnection'; import { FFPage } from './ffPage'; @@ -35,7 +35,7 @@ export class FFBrowser extends BrowserBase { private _version = ''; static async connect(transport: ConnectionTransport, options: BrowserOptions): Promise { - const connection = new FFConnection(SlowMoTransport.wrap(transport, options.slowMo)); + const connection = new FFConnection(transport); const browser = new FFBrowser(connection, options); const promises: Promise[] = [ connection.send('Browser.enable', { attachToDefaultContext: !!options.persistent }), diff --git a/src/frames.ts b/src/frames.ts index d9e8c0111a..67196601bc 100644 --- a/src/frames.ts +++ b/src/frames.ts @@ -463,7 +463,9 @@ export class Frame { await helper.waitForEvent(progress, this._eventEmitter, kAddLifecycleEvent, (e: types.LifecycleEvent) => e === waitUntil).promise; const request = event.newDocument ? event.newDocument.request : undefined; - return request ? request._finalRequest().response() : null; + const response = request ? request._finalRequest().response() : null; + await this._page._doSlowMo(); + return response; }); } @@ -521,12 +523,16 @@ export class Frame { async _evaluateExpressionHandle(expression: string, isFunction: boolean, arg: any): Promise { const context = await this._mainContext(); - return context.evaluateExpressionHandleInternal(expression, isFunction, arg); + const handle = await context.evaluateExpressionHandleInternal(expression, isFunction, arg); + await this._page._doSlowMo(); + return handle; } async _evaluateExpression(expression: string, isFunction: boolean, arg: any): Promise { const context = await this._mainContext(); - return context.evaluateExpressionInternal(expression, isFunction, arg); + const value = await context.evaluateExpressionInternal(expression, isFunction, arg); + await this._page._doSlowMo(); + return value; } async $(selector: string): Promise | null> { @@ -558,11 +564,12 @@ export class Frame { async dispatchEvent(selector: string, type: string, eventInit?: Object, options: types.TimeoutOptions = {}): Promise { const info = selectors._parseSelector(selector); const task = dom.dispatchEventTask(info, type, eventInit || {}); - return this._page._runAbortableTask(async progress => { + await this._page._runAbortableTask(async progress => { progress.log(`Dispatching "${type}" event on selector "${selector}"...`); // Note: we always dispatch events in the main world. await this._scheduleRerunnableTask(progress, 'main', task); }, this._page._timeoutSettings.timeout(options)); + await this._page._doSlowMo(); } async _$evalExpression(selector: string, expression: string, isFunction: boolean, arg: any): Promise { @@ -618,6 +625,7 @@ export class Frame { document.close(); }, { html, tag }); await Promise.all([contentPromise, lifecyclePromise]); + await this._page._doSlowMo(); }); } @@ -802,6 +810,7 @@ export class Frame { async focus(selector: string, options: types.TimeoutOptions = {}) { await this._retryWithSelectorIfNotConnected(selector, options, (progress, handle) => handle._focus(progress)); + await this._page._doSlowMo(); } async textContent(selector: string, options: types.TimeoutOptions = {}): Promise { diff --git a/src/helper.ts b/src/helper.ts index a9fda3292b..4f7c4c019e 100644 --- a/src/helper.ts +++ b/src/helper.ts @@ -355,6 +355,11 @@ export function getFromENV(name: string) { return value; } +export async function doSlowMo(amount?: number) { + if (!amount) + return; + await new Promise(x => setTimeout(x, amount)); +} export async function mkdirIfNeeded(filePath: string) { // This will harmlessly throw on windows if the dirname is the root directory. diff --git a/src/input.ts b/src/input.ts index 54ef2cfdc3..276aa2e2ab 100644 --- a/src/input.ts +++ b/src/input.ts @@ -17,6 +17,7 @@ import { assert } from './helper'; import * as keyboardLayout from './usKeyboardLayout'; import * as types from './types'; +import type { Page } from './page'; export const keypadLocation = keyboardLayout.keypadLocation; @@ -39,12 +40,14 @@ export interface RawKeyboard { } export class Keyboard { - private _raw: RawKeyboard; private _pressedModifiers = new Set(); private _pressedKeys = new Set(); + private _raw: RawKeyboard; + private _page: Page; - constructor(raw: RawKeyboard) { + constructor(raw: RawKeyboard, page: Page) { this._raw = raw; + this._page = page; } async down(key: string) { @@ -55,6 +58,7 @@ export class Keyboard { this._pressedModifiers.add(description.key as types.KeyboardModifier); const text = description.text; await this._raw.keydown(this._pressedModifiers, description.code, description.keyCode, description.keyCodeWithoutLocation, description.key, description.location, autoRepeat, text); + await this._page._doSlowMo(); } private _keyDescriptionForString(keyString: string): KeyDescription { @@ -75,10 +79,12 @@ export class Keyboard { this._pressedModifiers.delete(description.key as types.KeyboardModifier); this._pressedKeys.delete(description.code); await this._raw.keyup(this._pressedModifiers, description.code, description.keyCode, description.keyCodeWithoutLocation, description.key, description.location); + await this._page._doSlowMo(); } async insertText(text: string) { await this._raw.sendText(text); + await this._page._doSlowMo(); } async type(text: string, options?: { delay?: number }) { @@ -111,15 +117,19 @@ export class Keyboard { } const tokens = split(key); + const promises = []; key = tokens[tokens.length - 1]; for (let i = 0; i < tokens.length - 1; ++i) - await this.down(tokens[i]); - await this.down(key); - if (options.delay) + promises.push(this.down(tokens[i])); + promises.push(this.down(key)); + if (options.delay) { + await Promise.all(promises); await new Promise(f => setTimeout(f, options.delay)); - await this.up(key); + } + promises.push(this.up(key)); for (let i = tokens.length - 2; i >= 0; --i) - await this.up(tokens[i]); + promises.push(this.up(tokens[i])); + await Promise.all(promises); } async _ensureModifiers(modifiers: types.KeyboardModifier[]): Promise { @@ -153,16 +163,18 @@ export interface RawMouse { } export class Mouse { - private _raw: RawMouse; private _keyboard: Keyboard; private _x = 0; private _y = 0; private _lastButton: 'none' | types.MouseButton = 'none'; private _buttons = new Set(); + private _raw: RawMouse; + private _page: Page; - constructor(raw: RawMouse, keyboard: Keyboard) { + constructor(raw: RawMouse, page: Page) { this._raw = raw; - this._keyboard = keyboard; + this._page = page; + this._keyboard = this._page.keyboard; } async move(x: number, y: number, options: { steps?: number } = {}) { @@ -175,6 +187,7 @@ export class Mouse { const middleX = fromX + (x - fromX) * (i / steps); const middleY = fromY + (y - fromY) * (i / steps); await this._raw.move(middleX, middleY, this._lastButton, this._buttons, this._keyboard._modifiers()); + await this._page._doSlowMo(); } } @@ -183,6 +196,7 @@ export class Mouse { this._lastButton = button; this._buttons.add(button); await this._raw.down(this._x, this._y, this._lastButton, this._buttons, this._keyboard._modifiers(), clickCount); + await this._page._doSlowMo(); } async up(options: { button?: types.MouseButton, clickCount?: number } = {}) { @@ -190,6 +204,7 @@ export class Mouse { this._lastButton = 'none'; this._buttons.delete(button); await this._raw.up(this._x, this._y, button, this._buttons, this._keyboard._modifiers(), clickCount); + await this._page._doSlowMo(); } async click(x: number, y: number, options: { delay?: number, button?: types.MouseButton, clickCount?: number } = {}) { diff --git a/src/javascript.ts b/src/javascript.ts index 6a0154a185..48bd64c964 100644 --- a/src/javascript.ts +++ b/src/javascript.ts @@ -73,6 +73,10 @@ export class ExecutionContext { createHandle(remoteObject: RemoteObject): JSHandle { return this._delegate.createHandle(this, remoteObject); } + + async doSlowMo() { + // overrided in FrameExecutionContext + } } export class JSHandle { @@ -106,8 +110,10 @@ export class JSHandle { return evaluate(this._context, false /* returnByValue */, pageFunction, this, arg); } - _evaluateExpression(expression: string, isFunction: boolean, returnByValue: boolean, arg: any) { - return evaluateExpression(this._context, returnByValue, expression, isFunction, this, arg); + async _evaluateExpression(expression: string, isFunction: boolean, returnByValue: boolean, arg: any) { + const value = await evaluateExpression(this._context, returnByValue, expression, isFunction, this, arg);1; + await this._context.doSlowMo(); + return value; } async getProperty(propertyName: string): Promise { diff --git a/src/page.ts b/src/page.ts index a54986b829..f4ec5b7610 100644 --- a/src/page.ts +++ b/src/page.ts @@ -133,8 +133,8 @@ export class Page extends EventEmitter { extraHTTPHeaders: null, }; this.accessibility = new accessibility.Accessibility(delegate.getAccessibilityTree.bind(delegate)); - this.keyboard = new input.Keyboard(delegate.rawKeyboard); - this.mouse = new input.Mouse(delegate.rawMouse, this.keyboard); + this.keyboard = new input.Keyboard(delegate.rawKeyboard, this); + this.mouse = new input.Mouse(delegate.rawMouse, this); this._timeoutSettings = new TimeoutSettings(browserContext._timeoutSettings); this._screenshotter = new Screenshotter(this); this._frameManager = new frames.FrameManager(this); @@ -143,6 +143,13 @@ export class Page extends EventEmitter { this.coverage = delegate.coverage ? delegate.coverage() : null; } + async _doSlowMo() { + const slowMo = this._browserContext._browserBase._options.slowMo; + if (!slowMo) + return; + await new Promise(x => setTimeout(x, slowMo)); + } + _didClose() { this._frameManager.dispose(); assert(this._closedState !== 'closed', 'Page closed twice'); @@ -237,7 +244,9 @@ export class Page extends EventEmitter { async reload(options?: types.NavigateOptions): Promise { const waitPromise = this.mainFrame().waitForNavigation(options); await this._delegate.reload(); - return waitPromise; + const response = waitPromise; + await this._doSlowMo(); + return response; } async goBack(options?: types.NavigateOptions): Promise { @@ -247,7 +256,9 @@ export class Page extends EventEmitter { waitPromise.catch(() => {}); return null; } - return waitPromise; + const response = await waitPromise; + await this._doSlowMo(); + return response; } async goForward(options?: types.NavigateOptions): Promise { @@ -257,7 +268,9 @@ export class Page extends EventEmitter { waitPromise.catch(() => {}); return null; } - return waitPromise; + const response = await waitPromise; + await this._doSlowMo(); + return response; } async emulateMedia(options: { media?: types.MediaType | null, colorScheme?: types.ColorScheme | null }) { @@ -270,11 +283,13 @@ export class Page extends EventEmitter { if (options.colorScheme !== undefined) this._state.colorScheme = options.colorScheme; await this._delegate.updateEmulateMedia(); + await this._doSlowMo(); } async setViewportSize(viewportSize: types.Size) { this._state.viewportSize = { ...viewportSize }; await this._delegate.setViewportSize(this._state.viewportSize); + await this._doSlowMo(); } viewportSize(): types.Size | null { diff --git a/src/transport.ts b/src/transport.ts index 8a9f8b2937..3a3318bd06 100644 --- a/src/transport.ts +++ b/src/transport.ts @@ -44,48 +44,6 @@ export interface ConnectionTransport { onclose?: () => void, } -export class SlowMoTransport implements ConnectionTransport { - private readonly _delay: number; - private readonly _delegate: ConnectionTransport; - - onmessage?: (message: ProtocolResponse) => void; - onclose?: () => void; - - static wrap(transport: ConnectionTransport, delay?: number): ConnectionTransport { - return delay ? new SlowMoTransport(transport, delay) : transport; - } - - constructor(transport: ConnectionTransport, delay: number) { - this._delay = delay; - this._delegate = transport; - this._delegate.onmessage = this._onmessage.bind(this); - this._delegate.onclose = this._onClose.bind(this); - } - - private _onmessage(message: ProtocolResponse) { - if (this.onmessage) - this.onmessage(message); - } - - private _onClose() { - if (this.onclose) - this.onclose(); - this._delegate.onmessage = undefined; - this._delegate.onclose = undefined; - } - - send(s: ProtocolRequest) { - setTimeout(() => { - if (this._delegate.onmessage) - this._delegate.send(s); - }, this._delay); - } - - close() { - this._delegate.close(); - } -} - export class WebSocketTransport implements ConnectionTransport { private _ws: WebSocket; private _progress: Progress; diff --git a/src/types.ts b/src/types.ts index fd075ca7e2..6dbecc60d4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -282,7 +282,7 @@ type LaunchOptionsBase = { chromiumSandbox?: boolean, slowMo?: number, }; -export type LaunchOptions = LaunchOptionsBase & { +export type LaunchOptions = LaunchOptionsBase & UIOptions & { firefoxUserPrefs?: { [key: string]: string | number | boolean }, }; export type LaunchPersistentOptions = LaunchOptionsBase & BrowserContextOptions; @@ -333,3 +333,7 @@ export type Error = { name: string, stack?: string, }; + +export type UIOptions = { + slowMo?: number; +}; diff --git a/src/webkit/wkBrowser.ts b/src/webkit/wkBrowser.ts index ede3ffc647..24a991f6d5 100644 --- a/src/webkit/wkBrowser.ts +++ b/src/webkit/wkBrowser.ts @@ -21,7 +21,7 @@ import { Events } from '../events'; import { helper, RegisteredListener, assert } from '../helper'; import * as network from '../network'; import { Page, PageBinding } from '../page'; -import { ConnectionTransport, SlowMoTransport } from '../transport'; +import { ConnectionTransport } from '../transport'; import * as types from '../types'; import { Protocol } from './protocol'; import { kPageProxyMessageReceived, PageProxyMessageReceivedPayload, WKConnection, WKSession } from './wkConnection'; @@ -38,7 +38,7 @@ export class WKBrowser extends BrowserBase { private readonly _eventListeners: RegisteredListener[]; static async connect(transport: ConnectionTransport, options: BrowserOptions): Promise { - const browser = new WKBrowser(SlowMoTransport.wrap(transport, options.slowMo), options); + const browser = new WKBrowser(transport, options); const promises: Promise[] = [ browser._browserSession.send('Playwright.enable'), ]; diff --git a/test/slowmo.spec.ts b/test/slowmo.spec.ts new file mode 100644 index 0000000000..fb9c92897f --- /dev/null +++ b/test/slowmo.spec.ts @@ -0,0 +1,245 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import './base.fixture'; + +import { attachFrame } from './utils'; + +const {WIRE} = testOptions; + +async function checkSlowMo(toImpl, page, task) { + let didSlowMo = false; + const orig = toImpl(page)._doSlowMo; + toImpl(page)._doSlowMo = async function (...args) { + if (didSlowMo) + throw new Error('already did slowmo'); + await new Promise(x => setTimeout(x, 100)); + didSlowMo = true; + return orig.call(this, ...args) + } + await task(); + expect(!!didSlowMo).toBe(true); +} + +async function checkPageSlowMo(toImpl, page, task) { + await page.setContent(` + + + + + + + `) + await checkSlowMo(toImpl, page, task); +} + +it.skip(WIRE)('Page SlowMo $$eval', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.$$eval('button', () => void 0)); +}); +it.skip(WIRE)('Page SlowMo $eval', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.$eval('button', () => void 0)); +}); +it.skip(WIRE)('Page SlowMo check', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.check('.check')); +}); +it.skip(WIRE)('Page SlowMo click', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.click('button')); +}); +it.skip(WIRE)('Page SlowMo dblclick', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.dblclick('button')); +}); +it.skip(WIRE)('Page SlowMo dispatchEvent', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.dispatchEvent('button', 'click')); +}); +it.skip(WIRE)('Page SlowMo emulateMedia', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.emulateMedia({media: 'print'})); +}); +it.skip(WIRE)('Page SlowMo evaluate', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.evaluate(() => void 0)); +}); +it.skip(WIRE)('Page SlowMo evaluateHandle', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.evaluateHandle(() => window)); +}); +it.skip(WIRE)('Page SlowMo fill', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.fill('.fill', 'foo')); +}); +it.skip(WIRE)('Page SlowMo focus', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.focus('button')); +}); +it.skip(WIRE)('Page SlowMo goto', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.goto('about:blank')); +}); +it.skip(WIRE)('Page SlowMo hover', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.hover('button')); +}); +it.skip(WIRE)('Page SlowMo press', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.press('button', 'Enter')); +}); +it.skip(WIRE)('Page SlowMo reload', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.reload()); +}); +it.skip(WIRE)('Page SlowMo setContent', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.setContent('hello world')); +}); +it.skip(WIRE)('Page SlowMo selectOption', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.selectOption('select', 'foo')); +}); +it.skip(WIRE)('Page SlowMo setInputFiles', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.setInputFiles('.file', [])); +}); +it.skip(WIRE)('Page SlowMo setViewportSize', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.setViewportSize({height: 400, width: 400})); +}); +it.skip(WIRE)('Page SlowMo type', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.type('.fill', 'a')); +}); +it.skip(WIRE)('Page SlowMo uncheck', async ({page, toImpl}) => { + await checkPageSlowMo(toImpl, page, () => page.uncheck('.uncheck')); +}); + +async function checkFrameSlowMo(toImpl, page, server, task) { + const frame = await attachFrame(page, 'frame1', server.EMPTY_PAGE); + await frame.setContent(` + + + + + + + `) + await checkSlowMo(toImpl, page, task.bind(null, frame)); +} + +it.skip(WIRE)('Frame SlowMo $$eval', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.$$eval('button', () => void 0)); +}); +it.skip(WIRE)('Frame SlowMo $eval', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.$eval('button', () => void 0)); +}); +it.skip(WIRE)('Frame SlowMo check', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.check('.check')); +}); +it.skip(WIRE)('Frame SlowMo click', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.click('button')); +}); +it.skip(WIRE)('Frame SlowMo dblclick', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.dblclick('button')); +}); +it.skip(WIRE)('Frame SlowMo dispatchEvent', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.dispatchEvent('button', 'click')); +}); +it.skip(WIRE)('Frame SlowMo evaluate', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.evaluate(() => void 0)); +}); +it.skip(WIRE)('Frame SlowMo evaluateHandle', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.evaluateHandle(() => window)); +}); +it.skip(WIRE)('Frame SlowMo fill', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.fill('.fill', 'foo')); +}); +it.skip(WIRE)('Frame SlowMo focus', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.focus('button')); +}); +it.skip(WIRE)('Frame SlowMo goto', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.goto('about:blank')); +}); +it.skip(WIRE)('Frame SlowMo hover', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.hover('button')); +}); +it.skip(WIRE)('Frame SlowMo press', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.press('button', 'Enter')); +}); +it.skip(WIRE)('Frame SlowMo setContent', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.setContent('hello world')); +}); +it.skip(WIRE)('Frame SlowMo selectOption', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.selectOption('select', 'foo')); +}); +it.skip(WIRE)('Frame SlowMo setInputFiles', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.setInputFiles('.file', [])); +}); +it.skip(WIRE)('Frame SlowMo type', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.type('.fill', 'a')); +}); +it.skip(WIRE)('Frame SlowMo uncheck', async({page, server, toImpl}) => { + await checkFrameSlowMo(toImpl, page, server, frame => frame.uncheck('.uncheck')); +}); + +async function checkElementSlowMo(toImpl, page, selector, task) { + await page.setContent(` + + + + + + + `) + const element = await page.$(selector); + await checkSlowMo(toImpl, page, task.bind(null, element)); +} +it.skip(WIRE)('ElementHandle SlowMo $$eval', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'body', element => element.$$eval('button', () => void 0)); +}); +it.skip(WIRE)('ElementHandle SlowMo $eval', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'body', element => element.$eval('button', () => void 0)); +}); +it.skip(WIRE)('ElementHandle SlowMo check', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, '.check', element => element.check()); +}); +it.skip(WIRE)('ElementHandle SlowMo click', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'button', element => element.click()); +}); +it.skip(WIRE)('ElementHandle SlowMo dblclick', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'button', element => element.dblclick()); +}); +it.skip(WIRE)('ElementHandle SlowMo dispatchEvent', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'button', element => element.dispatchEvent('click')); +}); +it.skip(WIRE)('ElementHandle SlowMo evaluate', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'button', element => element.evaluate(() => void 0)); +}); +it.skip(WIRE)('ElementHandle SlowMo evaluateHandle', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'button', element => element.evaluateHandle(() => void 0)); +}); +it.skip(WIRE)('ElementHandle SlowMo fill', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, '.fill', element => element.fill('foo')); +}); +it.skip(WIRE)('ElementHandle SlowMo focus', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'button', element => element.focus()); +}); +it.skip(WIRE)('ElementHandle SlowMo hover', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'button', element => element.hover()); +}); +it.skip(WIRE)('ElementHandle SlowMo press', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'button', element => element.press('Enter')); +}); +it.skip(WIRE)('ElementHandle SlowMo selectOption', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, 'select', element => element.selectOption('foo')); +}); +it.skip(WIRE)('ElementHandle SlowMo setInputFiles', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, '.file', element => element.setInputFiles([])); +}); +it.skip(WIRE)('ElementHandle SlowMo type', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, '.fill', element => element.type( 'a')); +}); +it.skip(WIRE)('ElementHandle SlowMo uncheck', async ({page, toImpl}) => { + await checkElementSlowMo(toImpl, page, '.uncheck', element => element.uncheck()); +});