feat(Frame): addStyleTag and addScriptTag now return ElementHandles.

This patch teaches `page.addStyleTag` and `page.addScriptTag` to return ElementHandles
to the added tags.

Fixes #1179.
This commit is contained in:
Xingan Wang 2017-11-03 00:05:38 -07:00 committed by Andrey Lushnikov
parent f08f33458f
commit e0f5b93923
3 changed files with 34 additions and 23 deletions

View File

@ -1442,7 +1442,7 @@ const html = await frame.$eval('.main-container', e => e.outerHTML);
- `url` <[string]> Url of a script to be added. - `url` <[string]> Url of a script to be added.
- `path` <[string]> Path to the JavaScript file to be injected into frame. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). - `path` <[string]> Path to the JavaScript file to be injected into frame. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd).
- `content` <[string]> Raw JavaScript content to be injected into frame. - `content` <[string]> Raw JavaScript content to be injected into frame.
- returns: <[Promise]> which resolves when the script's onload fires or when the script content was injected into frame. - returns: <[Promise]<[ElementHandle]>> which resolves to the added tag when the script's onload fires or when the script content was injected into frame.
Adds a `<script>` tag into the page with the desired url or content. Adds a `<script>` tag into the page with the desired url or content.
@ -1451,7 +1451,7 @@ Adds a `<script>` tag into the page with the desired url or content.
- `url` <[string]> Url of the `<link>` tag. - `url` <[string]> Url of the `<link>` tag.
- `path` <[string]> Path to the CSS file to be injected into frame. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). - `path` <[string]> Path to the CSS file to be injected into frame. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd).
- `content` <[string]> Raw CSS content to be injected into frame. - `content` <[string]> Raw CSS content to be injected into frame.
- returns: <[Promise]> which resolves when the stylesheet's onload fires or when the CSS content was injected into frame. - returns: <[Promise]<[ElementHandle]>> which resolves to the added tag when the stylesheet's onload fires or when the CSS content was injected into frame.
Adds a `<link rel="stylesheet">` tag into the page with the desired url or a `<style type="text/css">` tag with the content. Adds a `<link rel="stylesheet">` tag into the page with the desired url or a `<style type="text/css">` tag with the content.

View File

@ -323,86 +323,92 @@ class Frame {
/** /**
* @param {Object} options * @param {Object} options
* @return {!Promise} * @return {!Promise<!ElementHandle>}
*/ */
async addScriptTag(options) { async addScriptTag(options) {
if (typeof options.url === 'string') if (typeof options.url === 'string')
return this.evaluate(addScriptUrl, options.url); return this._context.evaluateHandle(addScriptUrl, options.url);
if (typeof options.path === 'string') { if (typeof options.path === 'string') {
let contents = await readFileAsync(options.path, 'utf8'); let contents = await readFileAsync(options.path, 'utf8');
contents += '//# sourceURL=' + options.path.replace(/\n/g, ''); contents += '//# sourceURL=' + options.path.replace(/\n/g, '');
return this.evaluate(addScriptContent, contents); return this._context.evaluateHandle(addScriptContent, contents);
} }
if (typeof options.content === 'string') if (typeof options.content === 'string')
return this.evaluate(addScriptContent, options.content); return this._context.evaluateHandle(addScriptContent, options.content);
throw new Error('Provide an object with a `url`, `path` or `content` property'); throw new Error('Provide an object with a `url`, `path` or `content` property');
/** /**
* @param {string} url * @param {string} url
* @return {!Promise<!HTMLElement>}
*/ */
function addScriptUrl(url) { async function addScriptUrl(url) {
const script = document.createElement('script'); const script = document.createElement('script');
script.src = url; script.src = url;
const promise = new Promise(x => script.onload = x);
document.head.appendChild(script); document.head.appendChild(script);
return promise; await new Promise(x => script.onload = x);
return script;
} }
/** /**
* @param {string} content * @param {string} content
* @return {!HTMLElement}
*/ */
function addScriptContent(content) { function addScriptContent(content) {
const script = document.createElement('script'); const script = document.createElement('script');
script.type = 'text/javascript'; script.type = 'text/javascript';
script.text = content; script.text = content;
document.head.appendChild(script); document.head.appendChild(script);
return script;
} }
} }
/** /**
* @param {Object} options * @param {Object} options
* @return {!Promise} * @return {!Promise<!ElementHandle>}
*/ */
async addStyleTag(options) { async addStyleTag(options) {
if (typeof options.url === 'string') if (typeof options.url === 'string')
return this.evaluate(addStyleUrl, options.url); return await this._context.evaluateHandle(addStyleUrl, options.url);
if (typeof options.path === 'string') { if (typeof options.path === 'string') {
let contents = await readFileAsync(options.path, 'utf8'); let contents = await readFileAsync(options.path, 'utf8');
contents += '/*# sourceURL=' + options.path.replace(/\n/g, '') + '*/'; contents += '/*# sourceURL=' + options.path.replace(/\n/g, '') + '*/';
return this.evaluate(addStyleContent, contents); return await this._context.evaluateHandle(addStyleContent, contents);
} }
if (typeof options.content === 'string') if (typeof options.content === 'string')
return this.evaluate(addStyleContent, options.content); return await this._context.evaluateHandle(addStyleContent, options.content);
throw new Error('Provide an object with a `url`, `path` or `content` property'); throw new Error('Provide an object with a `url`, `path` or `content` property');
/** /**
* @param {string} url * @param {string} url
* @return {!Promise<!HTMLElement>}
*/ */
function addStyleUrl(url) { async function addStyleUrl(url) {
const link = document.createElement('link'); const link = document.createElement('link');
link.rel = 'stylesheet'; link.rel = 'stylesheet';
link.href = url; link.href = url;
const promise = new Promise(x => link.onload = x);
document.head.appendChild(link); document.head.appendChild(link);
return promise; await new Promise(x => link.onload = x);
return link;
} }
/** /**
* @param {string} content * @param {string} content
* @return {!HTMLElement}
*/ */
function addStyleContent(content) { function addStyleContent(content) {
const style = document.createElement('style'); const style = document.createElement('style');
style.type = 'text/css'; style.type = 'text/css';
style.appendChild(document.createTextNode(content)); style.appendChild(document.createTextNode(content));
document.head.appendChild(style); document.head.appendChild(style);
return style;
} }
} }

View File

@ -2375,13 +2375,15 @@ describe('Page', function() {
it('should work with a url', SX(async function() { it('should work with a url', SX(async function() {
await page.goto(EMPTY_PAGE); await page.goto(EMPTY_PAGE);
await page.addScriptTag({ url: '/injectedfile.js' }); const scriptHandle = await page.addScriptTag({ url: '/injectedfile.js' });
expect(scriptHandle.asElement()).not.toBeNull();
expect(await page.evaluate(() => __injected)).toBe(42); expect(await page.evaluate(() => __injected)).toBe(42);
})); }));
it('should work with a path', SX(async function() { it('should work with a path', SX(async function() {
await page.goto(EMPTY_PAGE); await page.goto(EMPTY_PAGE);
await page.addScriptTag({ path: path.join(__dirname, 'assets/injectedfile.js') }); const scriptHandle = await page.addScriptTag({ path: path.join(__dirname, 'assets/injectedfile.js') });
expect(scriptHandle.asElement()).not.toBeNull();
expect(await page.evaluate(() => __injected)).toBe(42); expect(await page.evaluate(() => __injected)).toBe(42);
})); }));
@ -2394,7 +2396,8 @@ describe('Page', function() {
it('should work with content', SX(async function() { it('should work with content', SX(async function() {
await page.goto(EMPTY_PAGE); await page.goto(EMPTY_PAGE);
await page.addScriptTag({ content: 'window.__injected = 35;' }); const scriptHandle = await page.addScriptTag({ content: 'window.__injected = 35;' });
expect(scriptHandle.asElement()).not.toBeNull();
expect(await page.evaluate(() => __injected)).toBe(35); expect(await page.evaluate(() => __injected)).toBe(35);
})); }));
}); });
@ -2412,13 +2415,15 @@ describe('Page', function() {
it('should work with a url', SX(async function() { it('should work with a url', SX(async function() {
await page.goto(EMPTY_PAGE); await page.goto(EMPTY_PAGE);
await page.addStyleTag({ url: '/injectedstyle.css' }); const styleHandle = await page.addStyleTag({ url: '/injectedstyle.css' });
expect(styleHandle.asElement()).not.toBeNull();
expect(await page.evaluate(`window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')`)).toBe('rgb(255, 0, 0)'); expect(await page.evaluate(`window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')`)).toBe('rgb(255, 0, 0)');
})); }));
it('should work with a path', SX(async function() { it('should work with a path', SX(async function() {
await page.goto(EMPTY_PAGE); await page.goto(EMPTY_PAGE);
await page.addStyleTag({ path: path.join(__dirname, 'assets/injectedstyle.css') }); const styleHandle = await page.addStyleTag({ path: path.join(__dirname, 'assets/injectedstyle.css') });
expect(styleHandle.asElement()).not.toBeNull();
expect(await page.evaluate(`window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')`)).toBe('rgb(255, 0, 0)'); expect(await page.evaluate(`window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')`)).toBe('rgb(255, 0, 0)');
})); }));
@ -2428,12 +2433,12 @@ describe('Page', function() {
const styleHandle = await page.$('style'); const styleHandle = await page.$('style');
const styleContent = await page.evaluate(style => style.innerHTML, styleHandle); const styleContent = await page.evaluate(style => style.innerHTML, styleHandle);
expect(styleContent).toContain(path.join('assets', 'injectedstyle.css')); expect(styleContent).toContain(path.join('assets', 'injectedstyle.css'));
styleHandle.dispose();
})); }));
it('should work with content', SX(async function() { it('should work with content', SX(async function() {
await page.goto(EMPTY_PAGE); await page.goto(EMPTY_PAGE);
await page.addStyleTag({ content: 'body { background-color: green; }' }); const styleHandle = await page.addStyleTag({ content: 'body { background-color: green; }' });
expect(styleHandle.asElement()).not.toBeNull();
expect(await page.evaluate(`window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')`)).toBe('rgb(0, 128, 0)'); expect(await page.evaluate(`window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')`)).toBe('rgb(0, 128, 0)');
})); }));
}); });