chore: add BiDi support for SetContent (#9878)
This commit is contained in:
parent
9ccde6ebf5
commit
cb079378bb
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
||||||
|
|
||||||
|
import {HTTPResponse} from '../../api/HTTPResponse.js';
|
||||||
import {WaitForOptions} from '../../api/Page.js';
|
import {WaitForOptions} from '../../api/Page.js';
|
||||||
import {assert} from '../../util/assert.js';
|
import {assert} from '../../util/assert.js';
|
||||||
import {stringifyFunction} from '../../util/Function.js';
|
import {stringifyFunction} from '../../util/Function.js';
|
||||||
@ -24,7 +25,7 @@ import {EventEmitter} from '../EventEmitter.js';
|
|||||||
import {PuppeteerLifeCycleEvent} from '../LifecycleWatcher.js';
|
import {PuppeteerLifeCycleEvent} from '../LifecycleWatcher.js';
|
||||||
import {TimeoutSettings} from '../TimeoutSettings.js';
|
import {TimeoutSettings} from '../TimeoutSettings.js';
|
||||||
import {EvaluateFunc, HandleFor} from '../types.js';
|
import {EvaluateFunc, HandleFor} from '../types.js';
|
||||||
import {isString} from '../util.js';
|
import {isString, waitWithTimeout} from '../util.js';
|
||||||
|
|
||||||
import {Connection} from './Connection.js';
|
import {Connection} from './Connection.js';
|
||||||
import {ElementHandle} from './ElementHandle.js';
|
import {ElementHandle} from './ElementHandle.js';
|
||||||
@ -34,7 +35,7 @@ import {BidiSerializer} from './Serializer.js';
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
const puppeteerToReadinessState = new Map<
|
const lifeCycleToReadinessState = new Map<
|
||||||
PuppeteerLifeCycleEvent,
|
PuppeteerLifeCycleEvent,
|
||||||
Bidi.BrowsingContext.ReadinessState
|
Bidi.BrowsingContext.ReadinessState
|
||||||
>([
|
>([
|
||||||
@ -42,6 +43,14 @@ const puppeteerToReadinessState = new Map<
|
|||||||
['domcontentloaded', 'interactive'],
|
['domcontentloaded', 'interactive'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
const lifeCycleToSubscribedEvent = new Map<PuppeteerLifeCycleEvent, string>([
|
||||||
|
['load', 'browsingContext.load'],
|
||||||
|
['domcontentloaded', 'browsingContext.domContentLoaded'],
|
||||||
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ -150,42 +159,83 @@ export class Context extends EventEmitter {
|
|||||||
referer?: string | undefined;
|
referer?: string | undefined;
|
||||||
referrerPolicy?: string | undefined;
|
referrerPolicy?: string | undefined;
|
||||||
} = {}
|
} = {}
|
||||||
): Promise<null> {
|
): Promise<HTTPResponse | null> {
|
||||||
const {waitUntil = 'load'} = options;
|
const {
|
||||||
|
waitUntil = 'load',
|
||||||
|
timeout = this._timeoutSettings.navigationTimeout(),
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const readinessState = lifeCycleToReadinessState.get(
|
||||||
|
getWaitUntilSingle(waitUntil)
|
||||||
|
) as Bidi.BrowsingContext.ReadinessState;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await Promise.race([
|
const response = await waitWithTimeout(
|
||||||
this.connection.send('browsingContext.navigate', {
|
this.connection.send('browsingContext.navigate', {
|
||||||
url: url,
|
url: url,
|
||||||
context: this.id,
|
context: this.id,
|
||||||
wait: getWaitUntil(waitUntil),
|
wait: readinessState,
|
||||||
}),
|
}),
|
||||||
new Promise((_, reject) => {
|
'Navigation',
|
||||||
const timeout =
|
timeout
|
||||||
options.timeout ?? this._timeoutSettings.navigationTimeout();
|
|
||||||
if (!timeout) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const error = new TimeoutError(
|
|
||||||
'Navigation timeout of ' + timeout + ' ms exceeded'
|
|
||||||
);
|
);
|
||||||
return setTimeout(() => {
|
this.#url = response.result.url;
|
||||||
return reject(error);
|
|
||||||
}, timeout);
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
this.#url = (response as Bidi.BrowsingContext.NavigateResult).result.url;
|
|
||||||
return null;
|
return null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof ProtocolError) {
|
if (error instanceof ProtocolError) {
|
||||||
error.message += ` at ${url}`;
|
error.message += ` at ${url}`;
|
||||||
|
} else if (error instanceof TimeoutError) {
|
||||||
|
error.message = 'Navigation timeout of ' + timeout + ' ms exceeded';
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getWaitUntil(
|
url(): string {
|
||||||
|
return this.#url;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setContent(
|
||||||
|
html: string,
|
||||||
|
options: WaitForOptions | undefined = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const {
|
||||||
|
waitUntil = 'load',
|
||||||
|
timeout = this._timeoutSettings.navigationTimeout(),
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const waitUntilCommand = lifeCycleToSubscribedEvent.get(
|
||||||
|
getWaitUntilSingle(waitUntil)
|
||||||
|
) as string;
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
|
||||||
|
// lifecycle event. @see https://crrev.com/608658
|
||||||
|
this.evaluate(html => {
|
||||||
|
document.open();
|
||||||
|
document.write(html);
|
||||||
|
document.close();
|
||||||
|
}, html),
|
||||||
|
waitWithTimeout(
|
||||||
|
new Promise<void>(resolve => {
|
||||||
|
this.once(waitUntilCommand, () => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
waitUntilCommand,
|
||||||
|
timeout
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
function getWaitUntilSingle(
|
||||||
event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]
|
event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]
|
||||||
): Bidi.BrowsingContext.ReadinessState {
|
): Extract<PuppeteerLifeCycleEvent, 'load' | 'domcontentloaded'> {
|
||||||
if (Array.isArray(event) && event.length > 1) {
|
if (Array.isArray(event) && event.length > 1) {
|
||||||
throw new Error('BiDi support only single `waitUntil` argument');
|
throw new Error('BiDi support only single `waitUntil` argument');
|
||||||
}
|
}
|
||||||
@ -204,15 +254,7 @@ export class Context extends EventEmitter {
|
|||||||
|
|
||||||
assert(waitUntilSingle, `Invalid waitUntil option ${waitUntilSingle}`);
|
assert(waitUntilSingle, `Invalid waitUntil option ${waitUntilSingle}`);
|
||||||
|
|
||||||
return puppeteerToReadinessState.get(
|
return waitUntilSingle;
|
||||||
waitUntilSingle
|
|
||||||
) as Bidi.BrowsingContext.ReadinessState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
url(): string {
|
|
||||||
return this.#url;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,6 +23,7 @@ import {
|
|||||||
WaitForOptions,
|
WaitForOptions,
|
||||||
} from '../../api/Page.js';
|
} from '../../api/Page.js';
|
||||||
import {ConsoleMessage, ConsoleMessageLocation} from '../ConsoleMessage.js';
|
import {ConsoleMessage, ConsoleMessageLocation} from '../ConsoleMessage.js';
|
||||||
|
import {Handler} from '../EventEmitter.js';
|
||||||
import {EvaluateFunc, HandleFor} from '../types.js';
|
import {EvaluateFunc, HandleFor} from '../types.js';
|
||||||
|
|
||||||
import {Context, getBidiHandle} from './Context.js';
|
import {Context, getBidiHandle} from './Context.js';
|
||||||
@ -33,25 +34,26 @@ import {BidiSerializer} from './Serializer.js';
|
|||||||
*/
|
*/
|
||||||
export class Page extends PageBase {
|
export class Page extends PageBase {
|
||||||
#context: Context;
|
#context: Context;
|
||||||
#subscribedEvents = [
|
#subscribedEvents = new Map<string, Handler<any>>([
|
||||||
'log.entryAdded',
|
['log.entryAdded', this.#onLogEntryAdded.bind(this)],
|
||||||
'browsingContext.load',
|
['browsingContext.load', this.#onLoad.bind(this)],
|
||||||
] as Bidi.Session.SubscribeParameters['events'];
|
['browsingContext.domContentLoaded', this.#onDOMLoad.bind(this)],
|
||||||
|
]) as Map<Bidi.Session.SubscribeParametersEvent, Handler>;
|
||||||
#boundOnLogEntryAdded = this.#onLogEntryAdded.bind(this);
|
|
||||||
#boundOnLoaded = this.#onLoad.bind(this);
|
|
||||||
|
|
||||||
constructor(context: Context) {
|
constructor(context: Context) {
|
||||||
super();
|
super();
|
||||||
this.#context = context;
|
this.#context = context;
|
||||||
|
|
||||||
this.#context.connection.send('session.subscribe', {
|
this.#context.connection.send('session.subscribe', {
|
||||||
events: this.#subscribedEvents,
|
events: [
|
||||||
|
...this.#subscribedEvents.keys(),
|
||||||
|
] as Bidi.Session.SubscribeParameters['events'],
|
||||||
contexts: [this.#context.id],
|
contexts: [this.#context.id],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#context.on('log.entryAdded', this.#boundOnLogEntryAdded);
|
for (const [event, subscriber] of this.#subscribedEvents) {
|
||||||
this.#context.on('browsingContext.load', this.#boundOnLoaded);
|
this.#context.on(event, subscriber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#onLogEntryAdded(event: Bidi.Log.LogEntry): void {
|
#onLogEntryAdded(event: Bidi.Log.LogEntry): void {
|
||||||
@ -95,9 +97,13 @@ export class Page extends PageBase {
|
|||||||
this.emit(PageEmittedEvents.Load);
|
this.emit(PageEmittedEvents.Load);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#onDOMLoad(_event: Bidi.BrowsingContext.NavigationInfo): void {
|
||||||
|
this.emit(PageEmittedEvents.DOMContentLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
override async close(): Promise<void> {
|
override async close(): Promise<void> {
|
||||||
await this.#context.connection.send('session.unsubscribe', {
|
await this.#context.connection.send('session.unsubscribe', {
|
||||||
events: this.#subscribedEvents,
|
events: [...this.#subscribedEvents.keys()],
|
||||||
contexts: [this.#context.id],
|
contexts: [this.#context.id],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -105,8 +111,9 @@ export class Page extends PageBase {
|
|||||||
context: this.#context.id,
|
context: this.#context.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#context.off('log.entryAdded', this.#boundOnLogEntryAdded);
|
for (const [event, subscriber] of this.#subscribedEvents) {
|
||||||
this.#context.off('browsingContext.load', this.#boundOnLogEntryAdded);
|
this.#context.off(event, subscriber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override async evaluateHandle<
|
override async evaluateHandle<
|
||||||
@ -150,6 +157,26 @@ export class Page extends PageBase {
|
|||||||
override setDefaultTimeout(timeout: number): void {
|
override setDefaultTimeout(timeout: number): void {
|
||||||
this.#context._timeoutSettings.setDefaultTimeout(timeout);
|
this.#context._timeoutSettings.setDefaultTimeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override async setContent(
|
||||||
|
html: string,
|
||||||
|
options: WaitForOptions = {}
|
||||||
|
): Promise<void> {
|
||||||
|
await this.#context.setContent(html, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
override async content(): Promise<string> {
|
||||||
|
return await this.evaluate(() => {
|
||||||
|
let retVal = '';
|
||||||
|
if (document.doctype) {
|
||||||
|
retVal = new XMLSerializer().serializeToString(document.doctype);
|
||||||
|
}
|
||||||
|
if (document.documentElement) {
|
||||||
|
retVal += document.documentElement.outerHTML;
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isConsoleLogEntry(
|
function isConsoleLogEntry(
|
||||||
|
@ -339,7 +339,7 @@ export async function waitWithTimeout<T>(
|
|||||||
const timeoutError = new TimeoutError(
|
const timeoutError = new TimeoutError(
|
||||||
`waiting for ${taskName} failed: timeout ${timeout}ms exceeded`
|
`waiting for ${taskName} failed: timeout ${timeout}ms exceeded`
|
||||||
);
|
);
|
||||||
const timeoutPromise = new Promise<T>((_res, rej) => {
|
const timeoutPromise = new Promise<never>((_, rej) => {
|
||||||
return (reject = rej);
|
return (reject = rej);
|
||||||
});
|
});
|
||||||
let timeoutTimer = null;
|
let timeoutTimer = null;
|
||||||
|
@ -1802,8 +1802,8 @@
|
|||||||
{
|
{
|
||||||
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.asElement should return ElementHandle for TextNodes",
|
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.asElement should return ElementHandle for TextNodes",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.toString should work for complicated objects",
|
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.toString should work for complicated objects",
|
||||||
@ -1962,88 +1962,28 @@
|
|||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work",
|
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with both domcontentloaded and load",
|
"testIdPattern": "[navigation.spec] navigation Page.goBack *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with clicking on anchor links",
|
"testIdPattern": "[navigation.spec] navigation Frame.goto *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with history.pushState()",
|
"testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["SKIP"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with history.replaceState()",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with DOM history.back()/history.forward()",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work when subframe issues window.stop()",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL", "TIMEOUT"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.goBack should work",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.goBack should work with HistoryAPI",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation Frame.goto should navigate subframes",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation Frame.goto should reject when frame detaches",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation Frame.goto should return matching responses",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should work",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should fail when frame detaches",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.reload should work",
|
"testIdPattern": "[navigation.spec] navigation Page.reload should work",
|
||||||
@ -2068,5 +2008,47 @@
|
|||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["firefox", "headless", "webDriverBiDi"],
|
"parameters": ["firefox", "headless", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[page.spec] Page Page.url should work",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[page.spec] Page Page.Events.DOMContentLoaded *",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[page.spec] Page Page.setContent *",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[page.spec] Page Page.setContent should work with tricky content",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[page.spec] Page Page.setContent should work with accents",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[page.spec] Page Page.setContent should work with emojis",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[page.spec] Page Page.setContent should work with newline",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -140,11 +140,10 @@ export const waitEvent = (
|
|||||||
}
|
}
|
||||||
): Promise<any> => {
|
): Promise<any> => {
|
||||||
return new Promise(fulfill => {
|
return new Promise(fulfill => {
|
||||||
emitter.on(eventName, function listener(event: any) {
|
emitter.once(eventName, (event: any) => {
|
||||||
if (!predicate(event)) {
|
if (!predicate(event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emitter.off(eventName, listener);
|
|
||||||
fulfill(event);
|
fulfill(event);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user