fix(api): split waitForSelectorMissing from waitForSelector
This also drops the notion of visibility, which is pretty vague.
This commit is contained in:
parent
6acc439450
commit
4b58d0076f
|
|
@ -138,7 +138,7 @@ Puppeteer is a Node library which provides a high-level API to control Chrome or
|
|||
|
||||
We are the same team that originally built Puppeteer at Google, but has since then moved on. Puppeteer proved that there is a lot of interest in the new generation of ever-green, capable and reliable automation drivers. With Playwright, we'd like to take it one step further and offer the same functionality for **all** the popular rendering engines. We'd like to see Playwright vendor-neutral and shared governed.
|
||||
|
||||
With Playwright, we are making the APIs more testing-friendly as well. We are taking the lessons learned from Puppeteer and incorporate them into the API, for example, user agent / device emulation is set up consistently on the `BrowserContext` level to enable multi-page scenarios, `click` waits for the element to be available and visible by default, there is a way to wait for network and other events, etc.
|
||||
With Playwright, we are making the APIs more testing-friendly as well. We are taking the lessons learned from Puppeteer and incorporate them into the API, for example, user agent / device emulation is set up consistently on the `BrowserContext` level to enable multi-page scenarios, `click` waits for the element to be available and clickable by default, there is a way to wait for network and other events, etc.
|
||||
|
||||
Playwright also aims at being cloud-native. Rather than a single page, `BrowserContext` abstraction is now central to the library operation. `BrowserContext`s are isolated, they can be either created locally or provided as a service.
|
||||
|
||||
|
|
|
|||
44
docs/api.md
44
docs/api.md
|
|
@ -531,6 +531,7 @@ page.removeListener('request', logRequest);
|
|||
- [page.waitForRequest(urlOrPredicate[, options])](#pagewaitforrequesturlorpredicate-options)
|
||||
- [page.waitForResponse(urlOrPredicate[, options])](#pagewaitforresponseurlorpredicate-options)
|
||||
- [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options)
|
||||
- [page.waitForSelectorMissing(selector[, options])](#pagewaitforselectormissingselector-options)
|
||||
- [page.workers()](#pageworkers)
|
||||
<!-- GEN:stop -->
|
||||
|
||||
|
|
@ -705,9 +706,8 @@ Shortcut for [page.mainFrame().$eval(selector, pageFunction)](#frameevalselector
|
|||
#### page.$wait(selector[, options])
|
||||
- `selector` <[string]> A selector of an element to wait for
|
||||
- `options` <[Object]>
|
||||
- `visibility` <"visible"|"hidden"|"any"> Wait for element to become visible (`visible`), hidden (`hidden`), present in dom (`any`). Defaults to `any`.
|
||||
- `timeout` <[number]> Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM. Resolves to `null` if waiting for `hidden: true` and selector is not found in DOM.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM.
|
||||
|
||||
Wait for the `selector` to appear in page. If at the moment of calling
|
||||
the method the `selector` already exists, the method will return
|
||||
|
|
@ -1447,7 +1447,6 @@ This is a shortcut for [page.mainFrame().url()](#frameurl)
|
|||
#### page.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])
|
||||
- `selectorOrFunctionOrTimeout` <[string]|[number]|[function]> A [selector], predicate or timeout to wait for
|
||||
- `options` <[Object]> Optional waiting parameters
|
||||
- `visibility` <"visible"|"hidden"|"any"> Wait for element to become visible (`visible`), hidden (`hidden`), present in dom (`any`). Defaults to `any`.
|
||||
- `polling` <[number]|"raf"|"mutation"> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
|
||||
- `'raf'` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
|
||||
- `'mutation'` - to execute `pageFunction` on every DOM mutation.
|
||||
|
|
@ -1456,8 +1455,7 @@ This is a shortcut for [page.mainFrame().url()](#frameurl)
|
|||
- returns: <[Promise]<[JSHandle]>> Promise which resolves to a JSHandle of the success value
|
||||
|
||||
This method behaves differently with respect to the type of the first parameter:
|
||||
- if `selectorOrFunctionOrTimeout` is a `string`, then the first argument is treated as a [selector] or [xpath], depending on whether or not it starts with '//', and the method is a shortcut for
|
||||
[page.waitForSelector](#pagewaitforselectorselector-options)
|
||||
- if `selectorOrFunctionOrTimeout` is a `string`, then the first argument is treated as a [selector], and the method is a shortcut for [page.waitForSelector](#pagewaitforselectorselector-options)
|
||||
- if `selectorOrFunctionOrTimeout` is a `function`, then the first argument is treated as a predicate to wait for and the method is a shortcut for [page.waitForFunction()](#pagewaitforfunctionpagefunction-options-args).
|
||||
- if `selectorOrFunctionOrTimeout` is a `number`, then the first argument is treated as a timeout in milliseconds and the method returns a promise which resolves after the timeout
|
||||
- otherwise, an exception is thrown
|
||||
|
|
@ -1601,9 +1599,8 @@ return finalResponse.ok();
|
|||
#### page.waitForSelector(selector[, options])
|
||||
- `selector` <[string]> A selector of an element to wait for
|
||||
- `options` <[Object]>
|
||||
- `visibility` <"visible"|"hidden"|"any"> Wait for element to become visible (`visible`), hidden (`hidden`), present in dom (`any`). Defaults to `any`.
|
||||
- `timeout` <[number]> Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM. Resolves to `null` if waiting for `hidden: true` and selector is not found in DOM.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM.
|
||||
|
||||
Wait for the `selector` to appear in page. If at the moment of calling
|
||||
the method the `selector` already exists, the method will return
|
||||
|
|
@ -1628,6 +1625,19 @@ const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.
|
|||
```
|
||||
Shortcut for [page.mainFrame().waitForSelector(selector[, options])](#framewaitforselectorselector-options).
|
||||
|
||||
|
||||
#### page.waitForSelectorMissing(selector[, options])
|
||||
- `selector` <[string]> A selector of an element to wait for missing.
|
||||
- `options` <[Object]>
|
||||
- `timeout` <[number]> Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is removed from DOM.
|
||||
|
||||
Wait for the `selector` to disappear from the page. If at the moment of calling
|
||||
the method the `selector` already does not exist, the method will return
|
||||
immediately. If the selector doesn't disappear after the `timeout` milliseconds of waiting, the function will throw. This method works across navigations.
|
||||
|
||||
Shortcut for [page.mainFrame().waitForSelectorMissing(selector[, options])](#framewaitforselectormissingselector-options).
|
||||
|
||||
#### page.workers()
|
||||
- returns: <[Array]<[Worker]>>
|
||||
This method returns all of the dedicated [WebWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) associated with the page.
|
||||
|
|
@ -1708,6 +1718,7 @@ An example of getting text from an iframe element:
|
|||
- [frame.waitForLoadState([options])](#framewaitforloadstateoptions)
|
||||
- [frame.waitForNavigation([options])](#framewaitfornavigationoptions)
|
||||
- [frame.waitForSelector(selector[, options])](#framewaitforselectorselector-options)
|
||||
- [frame.waitForSelectorMissing(selector[, options])](#framewaitforselectormissingselector-options)
|
||||
<!-- GEN:stop -->
|
||||
|
||||
#### frame.$(selector)
|
||||
|
|
@ -1757,9 +1768,8 @@ const html = await frame.$eval('.main-container', e => e.outerHTML);
|
|||
#### frame.$wait(selector[, options])
|
||||
- `selector` <[string]> A selector of an element to wait for
|
||||
- `options` <[Object]>
|
||||
- `visibility` <"visible"|"hidden"|"any"> Wait for element to become visible (`visible`), hidden (`hidden`), present in dom (`any`). Defaults to `any`.
|
||||
- `timeout` <[number]> Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM. Resolves to `null` if waiting for `hidden: true` and selector is not found in DOM.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM.
|
||||
|
||||
Wait for the `selector` to appear in page. If at the moment of calling
|
||||
the method the `selector` already exists, the method will return
|
||||
|
|
@ -2102,7 +2112,6 @@ Returns frame's url.
|
|||
#### frame.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])
|
||||
- `selectorOrFunctionOrTimeout` <[string]|[number]|[function]> A [selector], predicate or timeout to wait for
|
||||
- `options` <[Object]> Optional waiting parameters
|
||||
- `visibility` <"visible"|"hidden"|"any"> Wait for element to become visible (`visible`), hidden (`hidden`), present in dom (`any`). Defaults to `any`.
|
||||
- `polling` <[number]|"raf"|"mutation"> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
|
||||
- `'raf'` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
|
||||
- `'mutation'` - to execute `pageFunction` on every DOM mutation.
|
||||
|
|
@ -2111,8 +2120,7 @@ Returns frame's url.
|
|||
- returns: <[Promise]<[JSHandle]>> Promise which resolves to a JSHandle of the success value
|
||||
|
||||
This method behaves differently with respect to the type of the first parameter:
|
||||
- if `selectorOrFunctionOrTimeout` is a `string`, then the first argument is treated as a [selector] or [xpath], depending on whether or not it starts with '//', and the method is a shortcut for
|
||||
[frame.waitForSelector](#framewaitforselectorselector-options)
|
||||
- if `selectorOrFunctionOrTimeout` is a `string`, then the first argument is treated as a [selector], and the method is a shortcut for [frame.waitForSelector](#framewaitforselectorselector-options)
|
||||
- if `selectorOrFunctionOrTimeout` is a `function`, then the first argument is treated as a predicate to wait for and the method is a shortcut for [frame.waitForFunction()](#framewaitforfunctionpagefunction-options-args).
|
||||
- if `selectorOrFunctionOrTimeout` is a `number`, then the first argument is treated as a timeout in milliseconds and the method returns a promise which resolves after the timeout
|
||||
- otherwise, an exception is thrown
|
||||
|
|
@ -2209,9 +2217,8 @@ const [response] = await Promise.all([
|
|||
#### frame.waitForSelector(selector[, options])
|
||||
- `selector` <[string]> A selector of an element to wait for
|
||||
- `options` <[Object]>
|
||||
- `visibility` <"visible"|"hidden"|"any"> Wait for element to become visible (`visible`), hidden (`hidden`), present in dom (`any`). Defaults to `any`.
|
||||
- `timeout` <[number]> Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM. Resolves to `null` if waiting for `hidden: true` and selector is not found in DOM.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is added to DOM.
|
||||
|
||||
Wait for the `selector` to appear in page. If at the moment of calling
|
||||
the method the `selector` already exists, the method will return
|
||||
|
|
@ -2235,6 +2242,15 @@ const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.
|
|||
})();
|
||||
```
|
||||
|
||||
#### frame.waitForSelectorMissing(selector[, options])
|
||||
- `selector` <[string]> A selector of an element to wait for missing.
|
||||
- `options` <[Object]>
|
||||
- `timeout` <[number]> Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
|
||||
- returns: <[Promise]<?[ElementHandle]>> Promise which resolves when element specified by selector string is removed from DOM.
|
||||
|
||||
Wait for the `selector` to disappear from the page. If at the moment of calling
|
||||
the method the `selector` already does not exist, the method will return
|
||||
immediately. If the selector doesn't disappear after the `timeout` milliseconds of waiting, the function will throw. This method works across navigations.
|
||||
|
||||
### class: ElementHandle
|
||||
* extends: [JSHandle]
|
||||
|
|
|
|||
15
src/dom.ts
15
src/dom.ts
|
|
@ -581,18 +581,13 @@ export function waitForFunctionTask(selector: string | undefined, pageFunction:
|
|||
}, await context._injected(), selector, predicateBody, polling, options.timeout || 0, ...args);
|
||||
}
|
||||
|
||||
export function waitForSelectorTask(selector: string, visibility: types.Visibility, timeout: number): Task {
|
||||
export function waitForSelectorTask(selector: string, present: boolean, timeout: number): Task {
|
||||
selector = normalizeSelector(selector);
|
||||
return async (context: FrameExecutionContext) => context.evaluateHandle((injected: Injected, selector: string, visibility: types.Visibility, timeout: number) => {
|
||||
const polling = visibility === 'any' ? 'mutation' : 'raf';
|
||||
return injected.poll(polling, selector, timeout, (element: Element | undefined): Element | boolean => {
|
||||
if (!element)
|
||||
return visibility === 'hidden';
|
||||
if (visibility === 'any')
|
||||
return element;
|
||||
return injected.isVisible(element) === (visibility === 'visible') ? element : false;
|
||||
return async (context: FrameExecutionContext) => context.evaluateHandle((injected: Injected, selector: string, present: boolean, timeout: number) => {
|
||||
return injected.poll('mutation', selector, timeout, (element: Element | undefined) => {
|
||||
return present ? element : !element;
|
||||
});
|
||||
}, await context._injected(), selector, visibility, timeout);
|
||||
}, await context._injected(), selector, present, timeout);
|
||||
}
|
||||
|
||||
export const setFileInputFunction = async (element: HTMLInputElement, payloads: types.FilePayload[]) => {
|
||||
|
|
|
|||
|
|
@ -556,9 +556,13 @@ export class Frame {
|
|||
return handle;
|
||||
}
|
||||
|
||||
async waitForSelector(selector: string, options?: types.TimeoutOptions & { visibility?: types.Visibility }): Promise<dom.ElementHandle<Element> | null> {
|
||||
const { timeout = this._page._timeoutSettings.timeout(), visibility = 'any' } = (options || {});
|
||||
const handle = await this._waitForSelectorInUtilityContext(selector, visibility, timeout);
|
||||
async waitForSelector(selector: string, options?: types.TimeoutOptions): Promise<dom.ElementHandle<Element> | null> {
|
||||
if (options && (options as any).waitFor)
|
||||
throw new Error('Unsupported waitFor option, did you mean to click?');
|
||||
if (options && (options as any).visibility)
|
||||
throw new Error('Unsupported visibility option, did you mean to waitForSelectorMissing?');
|
||||
const { timeout = this._page._timeoutSettings.timeout() } = (options || {});
|
||||
const handle = await this._waitForSelectorInUtilityContext(selector, timeout);
|
||||
const mainContext = await this._mainContext();
|
||||
if (handle && handle._context !== mainContext) {
|
||||
const adopted = this._page._delegate.adoptElementHandle(handle, mainContext);
|
||||
|
|
@ -568,7 +572,15 @@ export class Frame {
|
|||
return handle;
|
||||
}
|
||||
|
||||
async $wait(selector: string, options?: types.TimeoutOptions & { visibility?: types.Visibility }): Promise<dom.ElementHandle<Element> | null> {
|
||||
async waitForSelectorMissing(selector: string, options?: types.TimeoutOptions): Promise<void> {
|
||||
if (options && (options as any).visibility)
|
||||
throw new Error('Unsupported visibility option, did you mean to waitForSelector?');
|
||||
const { timeout = this._page._timeoutSettings.timeout() } = (options || {});
|
||||
const task = dom.waitForSelectorTask(selector, false /* present */, timeout);
|
||||
await this._scheduleRerunnableTask(task, 'utility', timeout, `selector "${selector}" to be missing`);
|
||||
}
|
||||
|
||||
async $wait(selector: string, options?: types.TimeoutOptions): Promise<dom.ElementHandle<Element> | null> {
|
||||
return this.waitForSelector(selector, options);
|
||||
}
|
||||
|
||||
|
|
@ -842,7 +854,7 @@ export class Frame {
|
|||
await handle.dispose();
|
||||
}
|
||||
|
||||
async waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options: types.WaitForFunctionOptions & { visibility?: types.Visibility } = {}, ...args: any[]): Promise<js.JSHandle | null> {
|
||||
async waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options: types.WaitForFunctionOptions = {}, ...args: any[]): Promise<js.JSHandle | null> {
|
||||
if (helper.isString(selectorOrFunctionOrTimeout))
|
||||
return this.waitForSelector(selectorOrFunctionOrTimeout, options) as any;
|
||||
if (helper.isNumber(selectorOrFunctionOrTimeout))
|
||||
|
|
@ -858,9 +870,9 @@ export class Frame {
|
|||
throw new Error('waitFor option should be a boolean, got "' + (typeof waitFor) + '"');
|
||||
let handle: dom.ElementHandle<Element>;
|
||||
if (waitFor) {
|
||||
const maybeHandle = await this._waitForSelectorInUtilityContext(selector, 'any', timeout);
|
||||
const maybeHandle = await this._waitForSelectorInUtilityContext(selector, timeout);
|
||||
if (!maybeHandle)
|
||||
throw new Error('No node found for selector: ' + selectorToString(selector, 'any'));
|
||||
throw new Error(`No node found for selector: ${selector}`);
|
||||
handle = maybeHandle;
|
||||
} else {
|
||||
const context = await this._context('utility');
|
||||
|
|
@ -871,14 +883,9 @@ export class Frame {
|
|||
return handle;
|
||||
}
|
||||
|
||||
private async _waitForSelectorInUtilityContext(selector: string, waitFor: types.Visibility, timeout: number): Promise<dom.ElementHandle<Element> | null> {
|
||||
let visibility: types.Visibility = 'any';
|
||||
if (waitFor === 'visible' || waitFor === 'hidden' || waitFor === 'any')
|
||||
visibility = waitFor;
|
||||
else
|
||||
throw new Error(`Unsupported visibility option "${waitFor}"`);
|
||||
const task = dom.waitForSelectorTask(selector, visibility, timeout);
|
||||
const result = await this._scheduleRerunnableTask(task, 'utility', timeout, `selector "${selectorToString(selector, visibility)}"`);
|
||||
private async _waitForSelectorInUtilityContext(selector: string, timeout: number): Promise<dom.ElementHandle<Element> | null> {
|
||||
const task = dom.waitForSelectorTask(selector, true /* present */, timeout);
|
||||
const result = await this._scheduleRerunnableTask(task, 'utility', timeout, `selector "${selector}"`);
|
||||
if (!result.asElement()) {
|
||||
await result.dispose();
|
||||
return null;
|
||||
|
|
@ -1061,15 +1068,3 @@ function createTimeoutPromise(timeout: number): Disposable<Promise<TimeoutError>
|
|||
dispose
|
||||
};
|
||||
}
|
||||
|
||||
function selectorToString(selector: string, visibility: types.Visibility): string {
|
||||
let label;
|
||||
switch (visibility) {
|
||||
case 'visible': label = '[visible] '; break;
|
||||
case 'hidden': label = '[hidden] '; break;
|
||||
case 'any':
|
||||
case undefined:
|
||||
label = ''; break;
|
||||
}
|
||||
return `${label}${selector}`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,16 +135,6 @@ class Injected {
|
|||
return result;
|
||||
}
|
||||
|
||||
isVisible(element: Element): boolean {
|
||||
if (!element.ownerDocument || !element.ownerDocument.defaultView)
|
||||
return true;
|
||||
const style = element.ownerDocument.defaultView.getComputedStyle(element);
|
||||
if (!style || style.visibility === 'hidden')
|
||||
return false;
|
||||
const rect = element.getBoundingClientRect();
|
||||
return !!(rect.top || rect.bottom || rect.width || rect.height);
|
||||
}
|
||||
|
||||
private _pollMutation(selector: string | undefined, predicate: Predicate, timeout: number): Promise<any> {
|
||||
let timedOut = false;
|
||||
if (timeout)
|
||||
|
|
|
|||
10
src/page.ts
10
src/page.ts
|
|
@ -211,11 +211,15 @@ export class Page extends platform.EventEmitter {
|
|||
return this.mainFrame().$(selector);
|
||||
}
|
||||
|
||||
async waitForSelector(selector: string, options?: types.TimeoutOptions & { visibility?: types.Visibility }): Promise<dom.ElementHandle<Element> | null> {
|
||||
async waitForSelector(selector: string, options?: types.TimeoutOptions): Promise<dom.ElementHandle<Element> | null> {
|
||||
return this.mainFrame().waitForSelector(selector, options);
|
||||
}
|
||||
|
||||
async $wait(selector: string, options?: types.TimeoutOptions & { visibility?: types.Visibility }): Promise<dom.ElementHandle<Element> | null> {
|
||||
async waitForSelectorMissing(selector: string, options?: types.TimeoutOptions): Promise<void> {
|
||||
return this.mainFrame().waitForSelectorMissing(selector, options);
|
||||
}
|
||||
|
||||
async $wait(selector: string, options?: types.TimeoutOptions): Promise<dom.ElementHandle<Element> | null> {
|
||||
return this.mainFrame().$wait(selector, options);
|
||||
}
|
||||
|
||||
|
|
@ -525,7 +529,7 @@ export class Page extends platform.EventEmitter {
|
|||
return this.mainFrame().uncheck(selector, options);
|
||||
}
|
||||
|
||||
async waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options?: types.WaitForFunctionOptions & { visibility?: types.Visibility }, ...args: any[]): Promise<js.JSHandle | null> {
|
||||
async waitFor(selectorOrFunctionOrTimeout: (string | number | Function), options?: types.WaitForFunctionOptions, ...args: any[]): Promise<js.JSHandle | null> {
|
||||
return this.mainFrame().waitFor(selectorOrFunctionOrTimeout, options, ...args);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,6 @@ export type Quad = [ Point, Point, Point, Point ];
|
|||
export type TimeoutOptions = { timeout?: number };
|
||||
export type WaitForOptions = TimeoutOptions & { waitFor?: boolean };
|
||||
|
||||
export type Visibility = 'visible' | 'hidden' | 'any';
|
||||
|
||||
export type Polling = 'raf' | 'mutation' | number;
|
||||
export type WaitForFunctionOptions = TimeoutOptions & { polling?: Polling };
|
||||
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
|
|||
const error = await page.click('button', { waitFor: 'visible' }).catch(e => e);
|
||||
expect(error.message).toBe('waitFor option should be a boolean, got "string"');
|
||||
});
|
||||
it('should waitFor visible', async({page, server}) => {
|
||||
it('should waitFor display:none to be cleared', async({page, server}) => {
|
||||
let done = false;
|
||||
await page.goto(server.PREFIX + '/input/button.html');
|
||||
await page.$eval('button', b => b.style.display = 'none');
|
||||
|
|
|
|||
|
|
@ -200,17 +200,6 @@ module.exports.describe = function({testRunner, expect, selectors, FFOX, CHROMIU
|
|||
const element = await page.$('css=section >> css=div');
|
||||
expect(element).toBeTruthy();
|
||||
});
|
||||
it('should respect waitFor visibility', async({page, server}) => {
|
||||
await page.setContent('<section id="testAttribute">43543</section>');
|
||||
expect(await page.waitForSelector('css=section', { waitFor: 'visible'})).toBeTruthy();
|
||||
expect(await page.waitForSelector('css=section', { waitFor: 'any'})).toBeTruthy();
|
||||
expect(await page.waitForSelector('css=section')).toBeTruthy();
|
||||
|
||||
await page.setContent('<section id="testAttribute" style="display: none">43543</section>');
|
||||
expect(await page.waitForSelector('css=section', { waitFor: 'hidden'})).toBeTruthy();
|
||||
expect(await page.waitForSelector('css=section', { waitFor: 'any'})).toBeTruthy();
|
||||
expect(await page.waitForSelector('css=section')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Page.$$', function() {
|
||||
|
|
|
|||
|
|
@ -284,61 +284,18 @@ module.exports.describe = function({testRunner, expect, product, playwright, FFO
|
|||
await waitForSelector;
|
||||
expect(boxFound).toBe(true);
|
||||
});
|
||||
it('should wait for visible', async({page, server}) => {
|
||||
let divFound = false;
|
||||
const waitForSelector = page.waitForSelector('div').then(() => divFound = true);
|
||||
await page.setContent(`<div style='display: none; visibility: hidden;'>1</div>`);
|
||||
expect(divFound).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.removeProperty('display'));
|
||||
expect(divFound).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.removeProperty('visibility'));
|
||||
expect(await waitForSelector).toBe(true);
|
||||
expect(divFound).toBe(true);
|
||||
});
|
||||
it('should wait for visible recursively', async({page, server}) => {
|
||||
let divVisible = false;
|
||||
const waitForSelector = page.waitForSelector('div#inner', { visibility: 'visible' }).then(() => divVisible = true);
|
||||
await page.setContent(`<div style='display: none; visibility: hidden;'><div id="inner">hi</div></div>`);
|
||||
expect(divVisible).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.removeProperty('display'));
|
||||
expect(divVisible).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.removeProperty('visibility'));
|
||||
expect(await waitForSelector).toBe(true);
|
||||
expect(divVisible).toBe(true);
|
||||
});
|
||||
it('hidden should wait for visibility: hidden', async({page, server}) => {
|
||||
let divHidden = false;
|
||||
await page.setContent(`<div style='display: block;'></div>`);
|
||||
const waitForSelector = page.waitForSelector('div', { visibility: 'hidden' }).then(() => divHidden = true);
|
||||
await page.waitForSelector('div'); // do a round trip
|
||||
expect(divHidden).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.setProperty('visibility', 'hidden'));
|
||||
expect(await waitForSelector).toBe(true);
|
||||
expect(divHidden).toBe(true);
|
||||
});
|
||||
it('hidden should wait for display: none', async({page, server}) => {
|
||||
let divHidden = false;
|
||||
await page.setContent(`<div style='display: block;'></div>`);
|
||||
const waitForSelector = page.waitForSelector('div', { visibility: 'hidden' }).then(() => divHidden = true);
|
||||
await page.waitForSelector('div'); // do a round trip
|
||||
expect(divHidden).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').style.setProperty('display', 'none'));
|
||||
expect(await waitForSelector).toBe(true);
|
||||
expect(divHidden).toBe(true);
|
||||
});
|
||||
it('hidden should wait for removal', async({page, server}) => {
|
||||
it('waitForMissing should wait for removal', async({page, server}) => {
|
||||
await page.setContent(`<div></div>`);
|
||||
let divRemoved = false;
|
||||
const waitForSelector = page.waitForSelector('div', { visibility: 'hidden' }).then(() => divRemoved = true);
|
||||
const waitForSelector = page.waitForSelectorMissing('div').then(() => divRemoved = true);
|
||||
await page.waitForSelector('div'); // do a round trip
|
||||
expect(divRemoved).toBe(false);
|
||||
await page.evaluate(() => document.querySelector('div').remove());
|
||||
expect(await waitForSelector).toBe(true);
|
||||
await waitForSelector;
|
||||
expect(divRemoved).toBe(true);
|
||||
});
|
||||
it('should return null if waiting to hide non-existing element', async({page, server}) => {
|
||||
const handle = await page.waitForSelector('non-existing', { visibility: 'hidden' });
|
||||
expect(handle).toBe(null);
|
||||
it('should return immediately if waitForMissing non-existing element', async({page, server}) => {
|
||||
await page.waitForSelectorMissing('non-existing');
|
||||
});
|
||||
it('should respect timeout', async({page, server}) => {
|
||||
let error = null;
|
||||
|
|
@ -347,12 +304,12 @@ module.exports.describe = function({testRunner, expect, product, playwright, FFO
|
|||
expect(error.message).toContain('waiting for selector "div" failed: timeout');
|
||||
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 waitForMissing', async({page, server}) => {
|
||||
await page.setContent(`<div></div>`);
|
||||
let error = null;
|
||||
await page.waitForSelector('div', { visibility: 'hidden', timeout: 10 }).catch(e => error = e);
|
||||
await page.waitForSelectorMissing('div', { timeout: 10 }).catch(e => error = e);
|
||||
expect(error).toBeTruthy();
|
||||
expect(error.message).toContain('waiting for selector "[hidden] div" failed: timeout');
|
||||
expect(error.message).toContain('waiting for selector "div" to be missing failed: timeout');
|
||||
});
|
||||
it('should respond to node attribute mutation', async({page, server}) => {
|
||||
let divFound = false;
|
||||
|
|
@ -372,25 +329,20 @@ module.exports.describe = function({testRunner, expect, product, playwright, FFO
|
|||
await page.waitForSelector('.zombo', { timeout: 10 }).catch(e => error = e);
|
||||
expect(error.stack).toContain('waittask.spec.js');
|
||||
});
|
||||
it('should throw for unknown waitFor option', async({page, server}) => {
|
||||
it('should throw for waitFor option', async({page, server}) => {
|
||||
await page.setContent('<section>test</section>');
|
||||
const error = await page.waitForSelector('section', { waitFor: 'foo' }).catch(e => e);
|
||||
expect(error.message).toContain('Unsupported waitFor option, did you mean to click?');
|
||||
});
|
||||
it('should throw for visibility option', async({page, server}) => {
|
||||
await page.setContent('<section>test</section>');
|
||||
const error = await page.waitForSelector('section', { visibility: 'foo' }).catch(e => e);
|
||||
expect(error.message).toContain('Unsupported visibility option');
|
||||
expect(error.message).toContain('Unsupported visibility option, did you mean to waitForSelectorMissing?');
|
||||
});
|
||||
it('should throw for numeric waitFor option', async({page, server}) => {
|
||||
it('should throw for visibility option on waitForMissing', async({page, server}) => {
|
||||
await page.setContent('<section>test</section>');
|
||||
const error = await page.waitForSelector('section', { visibility: 123 }).catch(e => e);
|
||||
expect(error.message).toContain('Unsupported visibility option');
|
||||
});
|
||||
it('should throw for true waitFor option', async({page, server}) => {
|
||||
await page.setContent('<section>test</section>');
|
||||
const error = await page.waitForSelector('section', { visibility: true }).catch(e => e);
|
||||
expect(error.message).toContain('Unsupported visibility option');
|
||||
});
|
||||
it('should throw for false waitFor option', async({page, server}) => {
|
||||
await page.setContent('<section>test</section>');
|
||||
const error = await page.waitForSelector('section', { visibility: false }).catch(e => e);
|
||||
expect(error.message).toContain('Unsupported visibility option');
|
||||
const error = await page.waitForSelectorMissing('section', { visibility: 'foo' }).catch(e => e);
|
||||
expect(error.message).toContain('Unsupported visibility option, did you mean to waitForSelector?');
|
||||
});
|
||||
it('should support >> selector syntax', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
|
|
|
|||
Loading…
Reference in a new issue