Added frame.waitFor(selector) (#59)

This patch adds `frame.waitFor(selector)` method.

Fixes #42.
This commit is contained in:
Aleksey 2017-07-07 15:39:02 -07:00 committed by Andrey Lushnikov
parent a0eeb415f2
commit 090ecfa6b9
4 changed files with 104 additions and 0 deletions

View File

@ -36,6 +36,7 @@
* [page.url()](#pageurl)
* [page.userAgent()](#pageuseragent)
* [page.viewportSize()](#pageviewportsize)
* [page.waitFor(selector)](#pagewaitforselector)
- [class: Dialog](#class-dialog)
* [dialog.accept()](#dialogaccept)
* [dialog.dismiss()](#dialogdismiss)
@ -49,6 +50,7 @@
* [frame.parentFrame()](#frameparentframe)
* [frame.securityOrigin()](#framesecurityorigin)
* [frame.url()](#frameurl)
* [frame.waitFor(selector)](#framewaitforselector)
- [class: Request](#class-request)
* [request.response()](#requestresponse)
- [class: Response](#class-response)
@ -248,6 +250,9 @@ Pages could be closed by `page.close()` method.
- `width` <[number]> Page's width in pixels.
- `height` <[number]> Page's height in pixels.
#### page.waitFor(selector)
Shortcut for [page.mainFrame().waitFor(selector)](#framewaitforselector).
### class: Dialog
#### dialog.accept()
@ -268,6 +273,11 @@ Pages could be closed by `page.close()` method.
#### frame.parentFrame()
#### frame.securityOrigin()
#### frame.url()
#### frame.waitFor(selector)
- `selector` <[string]> CSS selector of awaited element,
- returns: <[Promise]> Promise which resolves when element specified by selector string is added to DOM.
### class: Request
#### request.response()

View File

@ -197,6 +197,39 @@ class FrameManager extends EventEmitter {
});
return response.result.value;
}
/**
* @param {string} selector
* @param {!Frame} frame
* @return {!Promise<undefined>}
*/
async _waitForInFrame(selector, frame) {
let code = selector => new Promise((fulfill, reject) => {
if (document.querySelector(selector)) {
fulfill();
return;
}
new MutationObserver((mutations, observer) => {
for (let mutation of mutations) {
for (let node of mutation.addedNodes) {
if (node.matches(selector)) {
observer.disconnect();
fulfill();
return;
}
}
}
}).observe(document.documentElement, {
childList: true,
subtree: true
});
});
await this._client.send('Runtime.evaluate', {
expression: helper.evaluationString(code, selector),
awaitPromise: true,
returnByValue: true,
});
}
}
/** @enum {string} */
@ -287,6 +320,14 @@ class Frame {
return this._detached;
}
/**
* @param {string} selector
* @return {!Promise<undefined>}
*/
async waitFor(selector) {
await this._frameManager._waitForInFrame(selector, this);
}
/**
* @param {?Object} framePayload
*/

View File

@ -561,6 +561,14 @@ class Page extends EventEmitter {
});
}
}
/**
* @param {string} selector
* @return {!Promise<undefined>}
*/
waitFor(selector) {
return this.mainFrame().waitFor(selector);
}
}
/** @enum {string} */

View File

@ -131,6 +131,51 @@ describe('Puppeteer', function() {
}));
});
describe('Frame.waitFor', function() {
let FrameUtils = require('./frame-utils');
let addElement = tag => document.body.appendChild(document.createElement(tag));
it('should immediately resolve promise if node exists', SX(async function() {
await page.navigate(EMPTY_PAGE);
let frame = page.mainFrame();
let added = false;
await frame.waitFor('*').then(() => added = true);
expect(added).toBe(true);
added = false;
await frame.evaluate(addElement, 'div');
await frame.waitFor('div').then(() => added = true);
expect(added).toBe(true);
}));
it('should resolve promise when node is added', SX(async function() {
await page.navigate(EMPTY_PAGE);
let frame = page.mainFrame();
let added = false;
frame.waitFor('div').then(() => added = true);
// run nop function..
await frame.evaluate(() => 42);
// .. to be sure that waitFor promise is not resolved yet.
expect(added).toBe(false);
await frame.evaluate(addElement, 'br');
expect(added).toBe(false);
await frame.evaluate(addElement, 'div');
expect(added).toBe(true);
}));
it('Page.waitFor is shortcut for main frame', SX(async function() {
await page.navigate(EMPTY_PAGE);
await FrameUtils.attachFrame(page, 'frame1', EMPTY_PAGE);
let otherFrame = page.frames()[1];
let added = false;
page.waitFor('div').then(() => added = true);
await otherFrame.evaluate(addElement, 'div');
expect(added).toBe(false);
await page.evaluate(addElement, 'div');
expect(added).toBe(true);
}));
});
it('Page Events: ConsoleMessage', SX(async function() {
let msgs = [];
page.on('consolemessage', msg => msgs.push(msg));