mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat: add support for async waitForTarget (#7885)
* feat: add support for async waitForTarget * fix: add timeout * fix: potential async bugs
This commit is contained in:
parent
543a4d44bc
commit
dbf0639822
@ -983,7 +983,7 @@ the method will return an array with all the targets in all browser contexts.
|
|||||||
|
|
||||||
#### browser.waitForTarget(predicate[, options])
|
#### browser.waitForTarget(predicate[, options])
|
||||||
|
|
||||||
- `predicate` <[function]\([Target]\):[boolean]> A function to be run for every target
|
- `predicate` <[function]\([Target]\):[boolean]|[Promise<boolean>]> A function to be run for every target
|
||||||
- `options` <[Object]>
|
- `options` <[Object]>
|
||||||
- `timeout` <[number]> Maximum wait time in milliseconds. Pass `0` to disable the timeout. Defaults to 30 seconds.
|
- `timeout` <[number]> Maximum wait time in milliseconds. Pass `0` to disable the timeout. Defaults to 30 seconds.
|
||||||
- returns: <[Promise]<[Target]>> Promise which resolves to the first target found that matches the `predicate` function.
|
- returns: <[Promise]<[Target]>> Promise which resolves to the first target found that matches the `predicate` function.
|
||||||
@ -1135,7 +1135,7 @@ An array of all active targets inside the browser context.
|
|||||||
|
|
||||||
#### browserContext.waitForTarget(predicate[, options])
|
#### browserContext.waitForTarget(predicate[, options])
|
||||||
|
|
||||||
- `predicate` <[function]\([Target]\):[boolean]> A function to be run for every target
|
- `predicate` <[function]\([Target]\):[boolean]|[Promise<boolean>]> A function to be run for every target
|
||||||
- `options` <[Object]>
|
- `options` <[Object]>
|
||||||
- `timeout` <[number]> Maximum wait time in milliseconds. Pass `0` to disable the timeout. Defaults to 30 seconds.
|
- `timeout` <[number]> Maximum wait time in milliseconds. Pass `0` to disable the timeout. Defaults to 30 seconds.
|
||||||
- returns: <[Promise]<[Target]>> Promise which resolves to the first target found that matches the `predicate` function.
|
- returns: <[Promise]<[Target]>> Promise which resolves to the first target found that matches the `predicate` function.
|
||||||
|
@ -114,7 +114,7 @@ class Browser extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {function(!Target):boolean} predicate
|
* @param {function(!Target):boolean|Promise<boolean>} predicate
|
||||||
* @param {{timeout?: number}=} options
|
* @param {{timeout?: number}=} options
|
||||||
* @return {!Promise<!Target>}
|
* @return {!Promise<!Target>}
|
||||||
*/
|
*/
|
||||||
@ -122,9 +122,6 @@ class Browser extends EventEmitter {
|
|||||||
const {
|
const {
|
||||||
timeout = 30000
|
timeout = 30000
|
||||||
} = options;
|
} = options;
|
||||||
const existingTarget = this.targets().find(predicate);
|
|
||||||
if (existingTarget)
|
|
||||||
return existingTarget;
|
|
||||||
let resolve;
|
let resolve;
|
||||||
const targetPromise = new Promise(x => resolve = x);
|
const targetPromise = new Promise(x => resolve = x);
|
||||||
this.on(Events.Browser.TargetCreated, check);
|
this.on(Events.Browser.TargetCreated, check);
|
||||||
@ -132,7 +129,21 @@ class Browser extends EventEmitter {
|
|||||||
try {
|
try {
|
||||||
if (!timeout)
|
if (!timeout)
|
||||||
return await targetPromise;
|
return await targetPromise;
|
||||||
return await helper.waitWithTimeout(targetPromise, 'target', timeout);
|
return await helper.waitWithTimeout(
|
||||||
|
Promise.race([
|
||||||
|
targetPromise,
|
||||||
|
(async () => {
|
||||||
|
for (const target of this.targets()) {
|
||||||
|
if (await predicate(target)) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await targetPromise;
|
||||||
|
})(),
|
||||||
|
]),
|
||||||
|
'target',
|
||||||
|
timeout
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
this.removeListener(Events.Browser.TargetCreated, check);
|
this.removeListener(Events.Browser.TargetCreated, check);
|
||||||
this.removeListener('targetchanged', check);
|
this.removeListener('targetchanged', check);
|
||||||
@ -141,8 +152,8 @@ class Browser extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* @param {!Target} target
|
* @param {!Target} target
|
||||||
*/
|
*/
|
||||||
function check(target) {
|
async function check(target) {
|
||||||
if (predicate(target))
|
if (await predicate(target))
|
||||||
resolve(target);
|
resolve(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -334,7 +345,7 @@ class BrowserContext extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {function(Target):boolean} predicate
|
* @param {function(Target):boolean|Promise<boolean>} predicate
|
||||||
* @param {{timeout?: number}=} options
|
* @param {{timeout?: number}=} options
|
||||||
* @return {!Promise<Target>}
|
* @return {!Promise<Target>}
|
||||||
*/
|
*/
|
||||||
|
@ -539,12 +539,10 @@ export class Browser extends EventEmitter {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
async waitForTarget(
|
async waitForTarget(
|
||||||
predicate: (x: Target) => boolean,
|
predicate: (x: Target) => boolean | Promise<boolean>,
|
||||||
options: WaitForTargetOptions = {}
|
options: WaitForTargetOptions = {}
|
||||||
): Promise<Target> {
|
): Promise<Target> {
|
||||||
const { timeout = 30000 } = options;
|
const { timeout = 30000 } = options;
|
||||||
const existingTarget = this.targets().find(predicate);
|
|
||||||
if (existingTarget) return existingTarget;
|
|
||||||
let resolve: (value: Target | PromiseLike<Target>) => void;
|
let resolve: (value: Target | PromiseLike<Target>) => void;
|
||||||
const targetPromise = new Promise<Target>((x) => (resolve = x));
|
const targetPromise = new Promise<Target>((x) => (resolve = x));
|
||||||
this.on(BrowserEmittedEvents.TargetCreated, check);
|
this.on(BrowserEmittedEvents.TargetCreated, check);
|
||||||
@ -552,7 +550,17 @@ export class Browser extends EventEmitter {
|
|||||||
try {
|
try {
|
||||||
if (!timeout) return await targetPromise;
|
if (!timeout) return await targetPromise;
|
||||||
return await helper.waitWithTimeout<Target>(
|
return await helper.waitWithTimeout<Target>(
|
||||||
targetPromise,
|
Promise.race([
|
||||||
|
targetPromise,
|
||||||
|
(async () => {
|
||||||
|
for (const target of this.targets()) {
|
||||||
|
if (await predicate(target)) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await targetPromise;
|
||||||
|
})(),
|
||||||
|
]),
|
||||||
'target',
|
'target',
|
||||||
timeout
|
timeout
|
||||||
);
|
);
|
||||||
@ -561,8 +569,8 @@ export class Browser extends EventEmitter {
|
|||||||
this.removeListener(BrowserEmittedEvents.TargetChanged, check);
|
this.removeListener(BrowserEmittedEvents.TargetChanged, check);
|
||||||
}
|
}
|
||||||
|
|
||||||
function check(target: Target): void {
|
async function check(target: Target): Promise<void> {
|
||||||
if (predicate(target)) resolve(target);
|
if (await predicate(target)) resolve(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -736,7 +744,7 @@ export class BrowserContext extends EventEmitter {
|
|||||||
* that matches the `predicate` function.
|
* that matches the `predicate` function.
|
||||||
*/
|
*/
|
||||||
waitForTarget(
|
waitForTarget(
|
||||||
predicate: (x: Target) => boolean,
|
predicate: (x: Target) => boolean | Promise<boolean>,
|
||||||
options: { timeout?: number } = {}
|
options: { timeout?: number } = {}
|
||||||
): Promise<Target> {
|
): Promise<Target> {
|
||||||
return this._browser.waitForTarget(
|
return this._browser.waitForTarget(
|
||||||
|
@ -67,6 +67,30 @@ describe('Target', function () {
|
|||||||
).toBe('Hello world');
|
).toBe('Hello world');
|
||||||
expect(await originalPage.$('body')).toBeTruthy();
|
expect(await originalPage.$('body')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
itFailsFirefox('should be able to use async waitForTarget', async () => {
|
||||||
|
const { page, server, context } = getTestState();
|
||||||
|
|
||||||
|
const [otherPage] = await Promise.all([
|
||||||
|
context
|
||||||
|
.waitForTarget((target) =>
|
||||||
|
target
|
||||||
|
.page()
|
||||||
|
.then(
|
||||||
|
(page) =>
|
||||||
|
page.url() === server.CROSS_PROCESS_PREFIX + '/empty.html'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then((target) => target.page()),
|
||||||
|
page.evaluate(
|
||||||
|
(url: string) => window.open(url),
|
||||||
|
server.CROSS_PROCESS_PREFIX + '/empty.html'
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
expect(otherPage.url()).toEqual(
|
||||||
|
server.CROSS_PROCESS_PREFIX + '/empty.html'
|
||||||
|
);
|
||||||
|
expect(page).not.toEqual(otherPage);
|
||||||
|
});
|
||||||
itFailsFirefox(
|
itFailsFirefox(
|
||||||
'should report when a new page is created and closed',
|
'should report when a new page is created and closed',
|
||||||
async () => {
|
async () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user