From 519ce482028562bbbad32ff1d42ca5daa85dfb52 Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Tue, 15 Jan 2019 15:34:05 -0800 Subject: [PATCH 1/3] refactor: split out IsolatedWorld from Frame This patch splits out `IsolatedWorld` class from Frame. The `IsolatedWorld` abstraction is an execution context with a designated set of DOM wrappers. References #2671 --- lib/FrameManager.js | 543 +----------------- lib/IsolatedWorld.js | 719 ++++++++++++++++++++++++ utils/doclint/check_public_api/index.js | 1 + 3 files changed, 748 insertions(+), 515 deletions(-) create mode 100644 lib/IsolatedWorld.js diff --git a/lib/FrameManager.js b/lib/FrameManager.js index 99cd691e45a52..a82426a9e32c4 100644 --- a/lib/FrameManager.js +++ b/lib/FrameManager.js @@ -14,15 +14,12 @@ * limitations under the License. */ -const fs = require('fs'); const EventEmitter = require('events'); const {helper, assert} = require('./helper'); const {Events} = require('./Events'); const {ExecutionContext} = require('./ExecutionContext'); const {LifecycleWatcher} = require('./LifecycleWatcher'); -const {TimeoutError} = require('./Errors'); - -const readFileAsync = helper.promisify(fs.readFile); +const {IsolatedWorld} = require('./IsolatedWorld'); class FrameManager extends EventEmitter { /** @@ -339,19 +336,10 @@ class Frame { this._id = frameId; this._detached = false; - /** @type {?Promise} */ - this._documentPromise = null; - /** @type {!Promise} */ - this._contextPromise; - this._contextResolveCallback = null; - this._setDefaultContext(null); - - - /** @type {!Set} */ - this._waitTasks = new Set(); this._loaderId = ''; /** @type {!Set} */ this._lifecycleEvents = new Set(); + this._isolatedWorld = new IsolatedWorld(frameManager, this); /** @type {!Set} */ this._childFrames = new Set(); @@ -364,7 +352,7 @@ class Frame { */ _addExecutionContext(context) { if (context._isDefault) - this._setDefaultContext(context); + this._isolatedWorld._setDefaultContext(context); } /** @@ -372,24 +360,7 @@ class Frame { */ _removeExecutionContext(context) { if (context._isDefault) - this._setDefaultContext(null); - } - - /** - * @param {?ExecutionContext} context - */ - _setDefaultContext(context) { - if (context) { - this._contextResolveCallback.call(null, context); - this._contextResolveCallback = null; - for (const waitTask of this._waitTasks) - waitTask.rerun(); - } else { - this._documentPromise = null; - this._contextPromise = new Promise(fulfill => { - this._contextResolveCallback = fulfill; - }); - } + this._isolatedWorld._setDefaultContext(null); } /** @@ -413,9 +384,7 @@ class Frame { * @return {!Promise} */ executionContext() { - if (this._detached) - throw new Error(`Execution Context is not available in detached frame "${this.url()}" (are you trying to evaluate?)`); - return this._contextPromise; + return this._isolatedWorld.executionContext(); } /** @@ -424,8 +393,7 @@ class Frame { * @return {!Promise} */ async evaluateHandle(pageFunction, ...args) { - const context = await this.executionContext(); - return context.evaluateHandle(pageFunction, ...args); + return this._isolatedWorld.evaluateHandle(pageFunction, ...args); } /** @@ -434,8 +402,7 @@ class Frame { * @return {!Promise<*>} */ async evaluate(pageFunction, ...args) { - const context = await this.executionContext(); - return context.evaluate(pageFunction, ...args); + return this._isolatedWorld.evaluate(pageFunction, ...args); } /** @@ -443,22 +410,7 @@ class Frame { * @return {!Promise} */ async $(selector) { - const document = await this._document(); - const value = await document.$(selector); - return value; - } - - /** - * @return {!Promise} - */ - async _document() { - if (this._documentPromise) - return this._documentPromise; - this._documentPromise = this.executionContext().then(async context => { - const document = await context.evaluateHandle('document'); - return document.asElement(); - }); - return this._documentPromise; + return this._isolatedWorld.$(selector); } /** @@ -466,9 +418,7 @@ class Frame { * @return {!Promise>} */ async $x(expression) { - const document = await this._document(); - const value = await document.$x(expression); - return value; + return this._isolatedWorld.$x(expression); } /** @@ -478,8 +428,7 @@ class Frame { * @return {!Promise<(!Object|undefined)>} */ async $eval(selector, pageFunction, ...args) { - const document = await this._document(); - return document.$eval(selector, pageFunction, ...args); + return this._isolatedWorld.$eval(selector, pageFunction, ...args); } /** @@ -489,9 +438,7 @@ class Frame { * @return {!Promise<(!Object|undefined)>} */ async $$eval(selector, pageFunction, ...args) { - const document = await this._document(); - const value = await document.$$eval(selector, pageFunction, ...args); - return value; + return this._isolatedWorld.$$eval(selector, pageFunction, ...args); } /** @@ -499,23 +446,14 @@ class Frame { * @return {!Promise>} */ async $$(selector) { - const document = await this._document(); - const value = await document.$$(selector); - return value; + return this._isolatedWorld.$$(selector); } /** * @return {!Promise} */ async content() { - return await this.evaluate(() => { - let retVal = ''; - if (document.doctype) - retVal = new XMLSerializer().serializeToString(document.doctype); - if (document.documentElement) - retVal += document.documentElement.outerHTML; - return retVal; - }); + return this._isolatedWorld.content(); } /** @@ -523,25 +461,7 @@ class Frame { * @param {!{timeout?: number, waitUntil?: string|!Array}=} options */ async setContent(html, options = {}) { - const { - waitUntil = ['load'], - timeout = 30000, - } = options; - // We rely upon the fact that document.open() will reset frame lifecycle with "init" - // lifecycle event. @see https://crrev.com/608658 - await this.evaluate(html => { - document.open(); - document.write(html); - document.close(); - }, html); - const watcher = new LifecycleWatcher(this._frameManager, this, waitUntil, timeout); - const error = await Promise.race([ - watcher.timeoutOrTerminationPromise(), - watcher.lifecyclePromise(), - ]); - watcher.dispose(); - if (error) - throw error; + return this._isolatedWorld.setContent(html, options); } /** @@ -584,70 +504,7 @@ class Frame { * @return {!Promise} */ async addScriptTag(options) { - const { - url = null, - path = null, - content = null, - type = '' - } = options; - if (url !== null) { - try { - const context = await this.executionContext(); - return (await context.evaluateHandle(addScriptUrl, url, type)).asElement(); - } catch (error) { - throw new Error(`Loading script from ${url} failed`); - } - } - - if (path !== null) { - let contents = await readFileAsync(path, 'utf8'); - contents += '//# sourceURL=' + path.replace(/\n/g, ''); - const context = await this.executionContext(); - return (await context.evaluateHandle(addScriptContent, contents, type)).asElement(); - } - - if (content !== null) { - const context = await this.executionContext(); - return (await context.evaluateHandle(addScriptContent, content, type)).asElement(); - } - - throw new Error('Provide an object with a `url`, `path` or `content` property'); - - /** - * @param {string} url - * @param {string} type - * @return {!Promise} - */ - async function addScriptUrl(url, type) { - const script = document.createElement('script'); - script.src = url; - if (type) - script.type = type; - const promise = new Promise((res, rej) => { - script.onload = res; - script.onerror = rej; - }); - document.head.appendChild(script); - await promise; - return script; - } - - /** - * @param {string} content - * @param {string} type - * @return {!HTMLElement} - */ - function addScriptContent(content, type = 'text/javascript') { - const script = document.createElement('script'); - script.type = type; - script.text = content; - let error = null; - script.onerror = e => error = e; - document.head.appendChild(script); - if (error) - throw error; - return script; - } + return this._isolatedWorld.addScriptTag(options); } /** @@ -655,67 +512,7 @@ class Frame { * @return {!Promise} */ async addStyleTag(options) { - const { - url = null, - path = null, - content = null - } = options; - if (url !== null) { - try { - const context = await this.executionContext(); - return (await context.evaluateHandle(addStyleUrl, url)).asElement(); - } catch (error) { - throw new Error(`Loading style from ${url} failed`); - } - } - - if (path !== null) { - let contents = await readFileAsync(path, 'utf8'); - contents += '/*# sourceURL=' + path.replace(/\n/g, '') + '*/'; - const context = await this.executionContext(); - return (await context.evaluateHandle(addStyleContent, contents)).asElement(); - } - - if (content !== null) { - const context = await this.executionContext(); - return (await context.evaluateHandle(addStyleContent, content)).asElement(); - } - - throw new Error('Provide an object with a `url`, `path` or `content` property'); - - /** - * @param {string} url - * @return {!Promise} - */ - async function addStyleUrl(url) { - const link = document.createElement('link'); - link.rel = 'stylesheet'; - link.href = url; - const promise = new Promise((res, rej) => { - link.onload = res; - link.onerror = rej; - }); - document.head.appendChild(link); - await promise; - return link; - } - - /** - * @param {string} content - * @return {!Promise} - */ - async function addStyleContent(content) { - const style = document.createElement('style'); - style.type = 'text/css'; - style.appendChild(document.createTextNode(content)); - const promise = new Promise((res, rej) => { - style.onload = res; - style.onerror = rej; - }); - document.head.appendChild(style); - await promise; - return style; - } + return this._isolatedWorld.addStyleTag(options); } /** @@ -723,30 +520,21 @@ class Frame { * @param {!{delay?: number, button?: "left"|"right"|"middle", clickCount?: number}=} options */ async click(selector, options) { - const handle = await this.$(selector); - assert(handle, 'No node found for selector: ' + selector); - await handle.click(options); - await handle.dispose(); + return this._isolatedWorld.click(selector, options); } /** * @param {string} selector */ async focus(selector) { - const handle = await this.$(selector); - assert(handle, 'No node found for selector: ' + selector); - await handle.focus(); - await handle.dispose(); + return this._isolatedWorld.focus(selector); } /** * @param {string} selector */ async hover(selector) { - const handle = await this.$(selector); - assert(handle, 'No node found for selector: ' + selector); - await handle.hover(); - await handle.dispose(); + return this._isolatedWorld.hover(selector); } /** @@ -755,33 +543,14 @@ class Frame { * @return {!Promise>} */ select(selector, ...values){ - for (const value of values) - assert(helper.isString(value), 'Values must be strings. Found value "' + value + '" of type "' + (typeof value) + '"'); - return this.$eval(selector, (element, values) => { - if (element.nodeName.toLowerCase() !== 'select') - throw new Error('Element is not a element.'); + + const options = Array.from(element.options); + element.value = undefined; + for (const option of options) { + option.selected = values.includes(option.value); + if (option.selected && !element.multiple) + break; + } + element.dispatchEvent(new Event('input', { 'bubbles': true })); + element.dispatchEvent(new Event('change', { 'bubbles': true })); + return options.filter(option => option.selected).map(option => option.value); + }, values); + } + + /** + * @param {string} selector + */ + async tap(selector) { + const handle = await this.$(selector); + assert(handle, 'No node found for selector: ' + selector); + await handle.tap(); + await handle.dispose(); + } + + /** + * @param {string} selector + * @param {string} text + * @param {{delay: (number|undefined)}=} options + */ + async type(selector, text, options) { + const handle = await this.$(selector); + assert(handle, 'No node found for selector: ' + selector); + await handle.type(text, options); + await handle.dispose(); + } + + /** + * @param {(string|number|Function)} selectorOrFunctionOrTimeout + * @param {!Object=} options + * @param {!Array<*>} args + * @return {!Promise} + */ + waitFor(selectorOrFunctionOrTimeout, options = {}, ...args) { + const xPathPattern = '//'; + + if (helper.isString(selectorOrFunctionOrTimeout)) { + const string = /** @type {string} */ (selectorOrFunctionOrTimeout); + if (string.startsWith(xPathPattern)) + return this.waitForXPath(string, options); + return this.waitForSelector(string, options); + } + if (helper.isNumber(selectorOrFunctionOrTimeout)) + return new Promise(fulfill => setTimeout(fulfill, /** @type {number} */ (selectorOrFunctionOrTimeout))); + if (typeof selectorOrFunctionOrTimeout === 'function') + return this.waitForFunction(selectorOrFunctionOrTimeout, options, ...args); + return Promise.reject(new Error('Unsupported target type: ' + (typeof selectorOrFunctionOrTimeout))); + } + + /** + * @param {string} selector + * @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options + * @return {!Promise} + */ + waitForSelector(selector, options) { + return this._waitForSelectorOrXPath(selector, false, options); + } + + /** + * @param {string} xpath + * @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options + * @return {!Promise} + */ + waitForXPath(xpath, options) { + return this._waitForSelectorOrXPath(xpath, true, options); + } + + /** + * @param {Function|string} pageFunction + * @param {!{polling?: string|number, timeout?: number}=} options + * @return {!Promise} + */ + waitForFunction(pageFunction, options = {}, ...args) { + const { + polling = 'raf', + timeout = 30000 + } = options; + return new WaitTask(this, pageFunction, 'function', polling, timeout, ...args).promise; + } + + /** + * @return {!Promise} + */ + async title() { + return this.evaluate(() => document.title); + } + + /** + * @param {string} selectorOrXPath + * @param {boolean} isXPath + * @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options + * @return {!Promise} + */ + _waitForSelectorOrXPath(selectorOrXPath, isXPath, options = {}) { + const { + visible: waitForVisible = false, + hidden: waitForHidden = false, + timeout = 30000, + } = options; + const polling = waitForVisible || waitForHidden ? 'raf' : 'mutation'; + const title = `${isXPath ? 'XPath' : 'selector'} "${selectorOrXPath}"${waitForHidden ? ' to be hidden' : ''}`; + return new WaitTask(this, predicate, title, polling, timeout, selectorOrXPath, isXPath, waitForVisible, waitForHidden).promise; + + /** + * @param {string} selectorOrXPath + * @param {boolean} isXPath + * @param {boolean} waitForVisible + * @param {boolean} waitForHidden + * @return {?Node|boolean} + */ + function predicate(selectorOrXPath, isXPath, waitForVisible, waitForHidden) { + const node = isXPath + ? document.evaluate(selectorOrXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue + : document.querySelector(selectorOrXPath); + if (!node) + return waitForHidden; + if (!waitForVisible && !waitForHidden) + return node; + const element = /** @type {Element} */ (node.nodeType === Node.TEXT_NODE ? node.parentElement : node); + + const style = window.getComputedStyle(element); + const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox(); + const success = (waitForVisible === isVisible || waitForHidden === !isVisible); + return success ? node : null; + + /** + * @return {boolean} + */ + function hasVisibleBoundingBox() { + const rect = element.getBoundingClientRect(); + return !!(rect.top || rect.bottom || rect.width || rect.height); + } + } + } +} + +class WaitTask { + /** + * @param {!IsolatedWorld} isolatedWorld + * @param {Function|string} predicateBody + * @param {string|number} polling + * @param {number} timeout + * @param {!Array<*>} args + */ + constructor(isolatedWorld, predicateBody, title, polling, timeout, ...args) { + if (helper.isString(polling)) + assert(polling === 'raf' || polling === 'mutation', 'Unknown polling option: ' + polling); + else if (helper.isNumber(polling)) + assert(polling > 0, 'Cannot poll with non-positive interval: ' + polling); + else + throw new Error('Unknown polling options: ' + polling); + + this._isolatedWorld = isolatedWorld; + this._polling = polling; + this._timeout = timeout; + this._predicateBody = helper.isString(predicateBody) ? 'return (' + predicateBody + ')' : 'return (' + predicateBody + ')(...args)'; + this._args = args; + this._runCount = 0; + isolatedWorld._waitTasks.add(this); + this.promise = new Promise((resolve, reject) => { + this._resolve = resolve; + this._reject = reject; + }); + // Since page navigation requires us to re-install the pageScript, we should track + // timeout on our end. + if (timeout) { + const timeoutError = new TimeoutError(`waiting for ${title} failed: timeout ${timeout}ms exceeded`); + this._timeoutTimer = setTimeout(() => this.terminate(timeoutError), timeout); + } + this.rerun(); + } + + /** + * @param {!Error} error + */ + terminate(error) { + this._terminated = true; + this._reject(error); + this._cleanup(); + } + + async rerun() { + const runCount = ++this._runCount; + /** @type {?Puppeteer.JSHandle} */ + let success = null; + let error = null; + try { + success = await (await this._isolatedWorld.executionContext()).evaluateHandle(waitForPredicatePageFunction, this._predicateBody, this._polling, this._timeout, ...this._args); + } catch (e) { + error = e; + } + + if (this._terminated || runCount !== this._runCount) { + if (success) + await success.dispose(); + return; + } + + // Ignore timeouts in pageScript - we track timeouts ourselves. + // If the frame's execution context has already changed, `frame.evaluate` will + // throw an error - ignore this predicate run altogether. + if (!error && await this._isolatedWorld.evaluate(s => !s, success).catch(e => true)) { + await success.dispose(); + return; + } + + // When the page is navigated, the promise is rejected. + // We will try again in the new execution context. + if (error && error.message.includes('Execution context was destroyed')) + return; + + // We could have tried to evaluate in a context which was already + // destroyed. + if (error && error.message.includes('Cannot find context with specified id')) + return; + + if (error) + this._reject(error); + else + this._resolve(success); + + this._cleanup(); + } + + _cleanup() { + clearTimeout(this._timeoutTimer); + this._isolatedWorld._waitTasks.delete(this); + this._runningTask = null; + } +} + +/** + * @param {string} predicateBody + * @param {string} polling + * @param {number} timeout + * @return {!Promise<*>} + */ +async function waitForPredicatePageFunction(predicateBody, polling, timeout, ...args) { + const predicate = new Function('...args', predicateBody); + let timedOut = false; + if (timeout) + setTimeout(() => timedOut = true, timeout); + if (polling === 'raf') + return await pollRaf(); + if (polling === 'mutation') + return await pollMutation(); + if (typeof polling === 'number') + return await pollInterval(polling); + + /** + * @return {!Promise<*>} + */ + function pollMutation() { + const success = predicate.apply(null, args); + if (success) + return Promise.resolve(success); + + let fulfill; + const result = new Promise(x => fulfill = x); + const observer = new MutationObserver(mutations => { + if (timedOut) { + observer.disconnect(); + fulfill(); + } + const success = predicate.apply(null, args); + if (success) { + observer.disconnect(); + fulfill(success); + } + }); + observer.observe(document, { + childList: true, + subtree: true, + attributes: true + }); + return result; + } + + /** + * @return {!Promise<*>} + */ + function pollRaf() { + let fulfill; + const result = new Promise(x => fulfill = x); + onRaf(); + return result; + + function onRaf() { + if (timedOut) { + fulfill(); + return; + } + const success = predicate.apply(null, args); + if (success) + fulfill(success); + else + requestAnimationFrame(onRaf); + } + } + + /** + * @param {number} pollInterval + * @return {!Promise<*>} + */ + function pollInterval(pollInterval) { + let fulfill; + const result = new Promise(x => fulfill = x); + onTimeout(); + return result; + + function onTimeout() { + if (timedOut) { + fulfill(); + return; + } + const success = predicate.apply(null, args); + if (success) + fulfill(success); + else + setTimeout(onTimeout, pollInterval); + } + } +} + +module.exports = {IsolatedWorld}; diff --git a/utils/doclint/check_public_api/index.js b/utils/doclint/check_public_api/index.js index a80f6e9de31b7..f01f4ab300f9a 100644 --- a/utils/doclint/check_public_api/index.js +++ b/utils/doclint/check_public_api/index.js @@ -26,6 +26,7 @@ const EXCLUDE_CLASSES = new Set([ 'CustomError', 'EmulationManager', 'FrameManager', + 'IsolatedWorld', 'JSCoverage', 'Helper', 'Launcher', From 498b26ecc1acdde5abc25795e68fde1cccf5baf9 Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Tue, 15 Jan 2019 16:56:29 -0800 Subject: [PATCH 2/3] rename into DOMWorld --- lib/{IsolatedWorld.js => DOMWorld.js} | 8 ++-- lib/FrameManager.js | 56 +++++++++++++-------------- 2 files changed, 32 insertions(+), 32 deletions(-) rename lib/{IsolatedWorld.js => DOMWorld.js} (99%) diff --git a/lib/IsolatedWorld.js b/lib/DOMWorld.js similarity index 99% rename from lib/IsolatedWorld.js rename to lib/DOMWorld.js index e2545be31d0f9..a87927aefb72f 100644 --- a/lib/IsolatedWorld.js +++ b/lib/DOMWorld.js @@ -23,7 +23,7 @@ const readFileAsync = helper.promisify(fs.readFile); /** * @unrestricted */ -class IsolatedWorld { +class DOMWorld { /** * @param {!Puppeteer.FrameManager} frameManager * @param {!Puppeteer.Frame} frame @@ -37,7 +37,7 @@ class IsolatedWorld { /** @type {!Promise} */ this._contextPromise; this._contextResolveCallback = null; - this._setDefaultContext(null); + this._setContext(null); /** @type {!Set} */ this._waitTasks = new Set(); @@ -47,7 +47,7 @@ class IsolatedWorld { /** * @param {?Puppeteer.ExecutionContext} context */ - _setDefaultContext(context) { + _setContext(context) { if (context) { this._contextResolveCallback.call(null, context); this._contextResolveCallback = null; @@ -716,4 +716,4 @@ async function waitForPredicatePageFunction(predicateBody, polling, timeout, ... } } -module.exports = {IsolatedWorld}; +module.exports = {DOMWorld}; diff --git a/lib/FrameManager.js b/lib/FrameManager.js index a82426a9e32c4..b730bab47961e 100644 --- a/lib/FrameManager.js +++ b/lib/FrameManager.js @@ -19,7 +19,7 @@ const {helper, assert} = require('./helper'); const {Events} = require('./Events'); const {ExecutionContext} = require('./ExecutionContext'); const {LifecycleWatcher} = require('./LifecycleWatcher'); -const {IsolatedWorld} = require('./IsolatedWorld'); +const {DOMWorld} = require('./DOMWorld'); class FrameManager extends EventEmitter { /** @@ -339,7 +339,7 @@ class Frame { this._loaderId = ''; /** @type {!Set} */ this._lifecycleEvents = new Set(); - this._isolatedWorld = new IsolatedWorld(frameManager, this); + this._mainWorld = new DOMWorld(frameManager, this); /** @type {!Set} */ this._childFrames = new Set(); @@ -352,7 +352,7 @@ class Frame { */ _addExecutionContext(context) { if (context._isDefault) - this._isolatedWorld._setDefaultContext(context); + this._mainWorld._setContext(context); } /** @@ -360,7 +360,7 @@ class Frame { */ _removeExecutionContext(context) { if (context._isDefault) - this._isolatedWorld._setDefaultContext(null); + this._mainWorld._setContext(null); } /** @@ -384,7 +384,7 @@ class Frame { * @return {!Promise} */ executionContext() { - return this._isolatedWorld.executionContext(); + return this._mainWorld.executionContext(); } /** @@ -393,7 +393,7 @@ class Frame { * @return {!Promise} */ async evaluateHandle(pageFunction, ...args) { - return this._isolatedWorld.evaluateHandle(pageFunction, ...args); + return this._mainWorld.evaluateHandle(pageFunction, ...args); } /** @@ -402,7 +402,7 @@ class Frame { * @return {!Promise<*>} */ async evaluate(pageFunction, ...args) { - return this._isolatedWorld.evaluate(pageFunction, ...args); + return this._mainWorld.evaluate(pageFunction, ...args); } /** @@ -410,7 +410,7 @@ class Frame { * @return {!Promise} */ async $(selector) { - return this._isolatedWorld.$(selector); + return this._mainWorld.$(selector); } /** @@ -418,7 +418,7 @@ class Frame { * @return {!Promise>} */ async $x(expression) { - return this._isolatedWorld.$x(expression); + return this._mainWorld.$x(expression); } /** @@ -428,7 +428,7 @@ class Frame { * @return {!Promise<(!Object|undefined)>} */ async $eval(selector, pageFunction, ...args) { - return this._isolatedWorld.$eval(selector, pageFunction, ...args); + return this._mainWorld.$eval(selector, pageFunction, ...args); } /** @@ -438,7 +438,7 @@ class Frame { * @return {!Promise<(!Object|undefined)>} */ async $$eval(selector, pageFunction, ...args) { - return this._isolatedWorld.$$eval(selector, pageFunction, ...args); + return this._mainWorld.$$eval(selector, pageFunction, ...args); } /** @@ -446,14 +446,14 @@ class Frame { * @return {!Promise>} */ async $$(selector) { - return this._isolatedWorld.$$(selector); + return this._mainWorld.$$(selector); } /** * @return {!Promise} */ async content() { - return this._isolatedWorld.content(); + return this._mainWorld.content(); } /** @@ -461,7 +461,7 @@ class Frame { * @param {!{timeout?: number, waitUntil?: string|!Array}=} options */ async setContent(html, options = {}) { - return this._isolatedWorld.setContent(html, options); + return this._mainWorld.setContent(html, options); } /** @@ -504,7 +504,7 @@ class Frame { * @return {!Promise} */ async addScriptTag(options) { - return this._isolatedWorld.addScriptTag(options); + return this._mainWorld.addScriptTag(options); } /** @@ -512,7 +512,7 @@ class Frame { * @return {!Promise} */ async addStyleTag(options) { - return this._isolatedWorld.addStyleTag(options); + return this._mainWorld.addStyleTag(options); } /** @@ -520,21 +520,21 @@ class Frame { * @param {!{delay?: number, button?: "left"|"right"|"middle", clickCount?: number}=} options */ async click(selector, options) { - return this._isolatedWorld.click(selector, options); + return this._mainWorld.click(selector, options); } /** * @param {string} selector */ async focus(selector) { - return this._isolatedWorld.focus(selector); + return this._mainWorld.focus(selector); } /** * @param {string} selector */ async hover(selector) { - return this._isolatedWorld.hover(selector); + return this._mainWorld.hover(selector); } /** @@ -543,14 +543,14 @@ class Frame { * @return {!Promise>} */ select(selector, ...values){ - return this._isolatedWorld.select(selector, ...values); + return this._mainWorld.select(selector, ...values); } /** * @param {string} selector */ async tap(selector) { - return this._isolatedWorld.tap(selector); + return this._mainWorld.tap(selector); } /** @@ -559,7 +559,7 @@ class Frame { * @param {{delay: (number|undefined)}=} options */ async type(selector, text, options) { - return this._isolatedWorld.type(selector, text, options); + return this._mainWorld.type(selector, text, options); } /** @@ -569,7 +569,7 @@ class Frame { * @return {!Promise} */ waitFor(selectorOrFunctionOrTimeout, options = {}, ...args) { - return this._isolatedWorld.waitFor(selectorOrFunctionOrTimeout, options, ...args); + return this._mainWorld.waitFor(selectorOrFunctionOrTimeout, options, ...args); } /** @@ -578,7 +578,7 @@ class Frame { * @return {!Promise} */ waitForSelector(selector, options) { - return this._isolatedWorld.waitForSelector(selector, options); + return this._mainWorld.waitForSelector(selector, options); } /** @@ -587,7 +587,7 @@ class Frame { * @return {!Promise} */ waitForXPath(xpath, options) { - return this._isolatedWorld.waitForXPath(xpath, options); + return this._mainWorld.waitForXPath(xpath, options); } /** @@ -596,14 +596,14 @@ class Frame { * @return {!Promise} */ waitForFunction(pageFunction, options = {}, ...args) { - return this._isolatedWorld.waitForFunction(pageFunction, options, ...args); + return this._mainWorld.waitForFunction(pageFunction, options, ...args); } /** * @return {!Promise} */ async title() { - return this._isolatedWorld.title(); + return this._mainWorld.title(); } /** @@ -642,7 +642,7 @@ class Frame { _detach() { this._detached = true; - this._isolatedWorld._detach(); + this._mainWorld._detach(); if (this._parentFrame) this._parentFrame._childFrames.delete(this); this._parentFrame = null; From 66f194adcf897567c0ced895b500bf91a51950d6 Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Tue, 15 Jan 2019 17:01:22 -0800 Subject: [PATCH 3/3] drop isolatedWorld from everywhere --- lib/DOMWorld.js | 14 +++++++------- utils/doclint/check_public_api/index.js | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/DOMWorld.js b/lib/DOMWorld.js index a87927aefb72f..c466ceb6c62a4 100644 --- a/lib/DOMWorld.js +++ b/lib/DOMWorld.js @@ -530,13 +530,13 @@ class DOMWorld { class WaitTask { /** - * @param {!IsolatedWorld} isolatedWorld + * @param {!DOMWorld} domWorld * @param {Function|string} predicateBody * @param {string|number} polling * @param {number} timeout * @param {!Array<*>} args */ - constructor(isolatedWorld, predicateBody, title, polling, timeout, ...args) { + constructor(domWorld, predicateBody, title, polling, timeout, ...args) { if (helper.isString(polling)) assert(polling === 'raf' || polling === 'mutation', 'Unknown polling option: ' + polling); else if (helper.isNumber(polling)) @@ -544,13 +544,13 @@ class WaitTask { else throw new Error('Unknown polling options: ' + polling); - this._isolatedWorld = isolatedWorld; + this._domWorld = domWorld; this._polling = polling; this._timeout = timeout; this._predicateBody = helper.isString(predicateBody) ? 'return (' + predicateBody + ')' : 'return (' + predicateBody + ')(...args)'; this._args = args; this._runCount = 0; - isolatedWorld._waitTasks.add(this); + domWorld._waitTasks.add(this); this.promise = new Promise((resolve, reject) => { this._resolve = resolve; this._reject = reject; @@ -579,7 +579,7 @@ class WaitTask { let success = null; let error = null; try { - success = await (await this._isolatedWorld.executionContext()).evaluateHandle(waitForPredicatePageFunction, this._predicateBody, this._polling, this._timeout, ...this._args); + success = await (await this._domWorld.executionContext()).evaluateHandle(waitForPredicatePageFunction, this._predicateBody, this._polling, this._timeout, ...this._args); } catch (e) { error = e; } @@ -593,7 +593,7 @@ class WaitTask { // Ignore timeouts in pageScript - we track timeouts ourselves. // If the frame's execution context has already changed, `frame.evaluate` will // throw an error - ignore this predicate run altogether. - if (!error && await this._isolatedWorld.evaluate(s => !s, success).catch(e => true)) { + if (!error && await this._domWorld.evaluate(s => !s, success).catch(e => true)) { await success.dispose(); return; } @@ -618,7 +618,7 @@ class WaitTask { _cleanup() { clearTimeout(this._timeoutTimer); - this._isolatedWorld._waitTasks.delete(this); + this._domWorld._waitTasks.delete(this); this._runningTask = null; } } diff --git a/utils/doclint/check_public_api/index.js b/utils/doclint/check_public_api/index.js index f01f4ab300f9a..0deb9019d2384 100644 --- a/utils/doclint/check_public_api/index.js +++ b/utils/doclint/check_public_api/index.js @@ -24,9 +24,9 @@ const EXCLUDE_CLASSES = new Set([ 'CSSCoverage', 'Connection', 'CustomError', + 'DOMWorld', 'EmulationManager', 'FrameManager', - 'IsolatedWorld', 'JSCoverage', 'Helper', 'Launcher',