feat: add id option to addScriptTag (#5477)

This commit is contained in:
Noam Lustiger 2021-09-14 17:02:05 -04:00 committed by GitHub
parent 1d0fc459c8
commit 300be5d167
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 13 deletions

View File

@ -1390,7 +1390,8 @@ Shortcut for [page.mainFrame().$x(expression)](#framexexpression)
- `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.
- `type` <[string]> Script type. Use 'module' in order to load a JavaScript ES6 module. See [script](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script) for more details. - `type` <[string]> Script type. Use 'module' in order to load a Javascript ES6 module. See [script](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script) for more details.
- `id` <[string]> id attribute to add to the script tag.
- returns: <[Promise]<[ElementHandle]>> which resolves to the added tag 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.
@ -3657,7 +3658,8 @@ The method evaluates the XPath expression relative to the frame document as its
- `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.
- `type` <[string]> Script type. Use 'module' in order to load a JavaScript ES6 module. See [script](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script) for more details. - `type` <[string]> Script type. Use 'module' in order to load a Javascript ES6 module. See [script](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script) for more details.
- `id` <[string]> id attribute to add to the script tag.
- returns: <[Promise]<[ElementHandle]>> which resolves to the added tag 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.

View File

@ -140,14 +140,19 @@ class DOMWorld {
} }
/** /**
* @param {!{content?: string, path?: string, type?: string, url?: string}} options * @param {!{content?: string, path?: string, type?: string, url?: string, id?: string}} options
* @return {!Promise<!ElementHandle>} * @return {!Promise<!ElementHandle>}
*/ */
async addScriptTag(options) { async addScriptTag(options) {
const {
type = '',
id = ''
} = options;
if (typeof options.url === 'string') { if (typeof options.url === 'string') {
const url = options.url; const url = options.url;
try { try {
return (await this.evaluateHandle(addScriptUrl, url, options.type)).asElement(); return (await this.evaluateHandle(addScriptUrl, url, id, type)).asElement();
} catch (error) { } catch (error) {
throw new Error(`Loading script from ${url} failed`); throw new Error(`Loading script from ${url} failed`);
} }
@ -156,23 +161,26 @@ class DOMWorld {
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 (await this.evaluateHandle(addScriptContent, contents, options.type)).asElement(); return (await this.evaluateHandle(addScriptContent, contents, id, type)).asElement();
} }
if (typeof options.content === 'string') { if (typeof options.content === 'string') {
return (await this.evaluateHandle(addScriptContent, options.content, options.type)).asElement(); return (await this.evaluateHandle(addScriptContent, options.content, id, type)).asElement();
} }
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
* @param {string} id
* @param {string} type * @param {string} type
* @return {!Promise<!HTMLElement>} * @return {!Promise<!HTMLElement>}
*/ */
async function addScriptUrl(url, type) { async function addScriptUrl(url, id, type) {
const script = document.createElement('script'); const script = document.createElement('script');
script.src = url; script.src = url;
if (id)
script.id = id;
if (type) if (type)
script.type = type; script.type = type;
const promise = new Promise((res, rej) => { const promise = new Promise((res, rej) => {
@ -186,13 +194,16 @@ class DOMWorld {
/** /**
* @param {string} content * @param {string} content
* @param {string} id
* @param {string} type * @param {string} type
* @return {!HTMLElement} * @return {!HTMLElement}
*/ */
function addScriptContent(content, type = 'text/javascript') { function addScriptContent(content, id, type = 'text/javascript') {
const script = document.createElement('script'); const script = document.createElement('script');
script.type = type; script.type = type;
script.text = content; script.text = content;
if (id)
script.id = id;
let error = null; let error = null;
script.onerror = e => error = e; script.onerror = e => error = e;
document.head.appendChild(script); document.head.appendChild(script);

View File

@ -560,7 +560,7 @@ class Page extends EventEmitter {
} }
/** /**
* @param {!{content?: string, path?: string, type?: string, url?: string}} options * @param {!{content?: string, path?: string, type?: string, url?: string, id?: string}} options
* @return {!Promise<!ElementHandle>} * @return {!Promise<!ElementHandle>}
*/ */
async addScriptTag(options) { async addScriptTag(options) {

View File

@ -282,14 +282,21 @@ export class DOMWorld {
url?: string; url?: string;
path?: string; path?: string;
content?: string; content?: string;
id?: string;
type?: string; type?: string;
}): Promise<ElementHandle> { }): Promise<ElementHandle> {
const { url = null, path = null, content = null, type = '' } = options; const {
url = null,
path = null,
content = null,
id = '',
type = '',
} = options;
if (url !== null) { if (url !== null) {
try { try {
const context = await this.executionContext(); const context = await this.executionContext();
return ( return (
await context.evaluateHandle(addScriptUrl, url, type) await context.evaluateHandle(addScriptUrl, url, id, type)
).asElement(); ).asElement();
} catch (error) { } catch (error) {
throw new Error(`Loading script from ${url} failed`); throw new Error(`Loading script from ${url} failed`);
@ -307,14 +314,14 @@ export class DOMWorld {
contents += '//# sourceURL=' + path.replace(/\n/g, ''); contents += '//# sourceURL=' + path.replace(/\n/g, '');
const context = await this.executionContext(); const context = await this.executionContext();
return ( return (
await context.evaluateHandle(addScriptContent, contents, type) await context.evaluateHandle(addScriptContent, contents, id, type)
).asElement(); ).asElement();
} }
if (content !== null) { if (content !== null) {
const context = await this.executionContext(); const context = await this.executionContext();
return ( return (
await context.evaluateHandle(addScriptContent, content, type) await context.evaluateHandle(addScriptContent, content, id, type)
).asElement(); ).asElement();
} }
@ -324,10 +331,12 @@ export class DOMWorld {
async function addScriptUrl( async function addScriptUrl(
url: string, url: string,
id: string,
type: string type: string
): Promise<HTMLElement> { ): Promise<HTMLElement> {
const script = document.createElement('script'); const script = document.createElement('script');
script.src = url; script.src = url;
if (id) script.id = id;
if (type) script.type = type; if (type) script.type = type;
const promise = new Promise((res, rej) => { const promise = new Promise((res, rej) => {
script.onload = res; script.onload = res;
@ -340,11 +349,13 @@ export class DOMWorld {
function addScriptContent( function addScriptContent(
content: string, content: string,
id: string,
type = 'text/javascript' type = 'text/javascript'
): HTMLElement { ): HTMLElement {
const script = document.createElement('script'); const script = document.createElement('script');
script.type = type; script.type = type;
script.text = content; script.text = content;
if (id) script.id = id;
let error = null; let error = null;
script.onerror = (e) => (error = e); script.onerror = (e) => (error = e);
document.head.appendChild(script); document.head.appendChild(script);

View File

@ -1280,6 +1280,7 @@ export class Page extends EventEmitter {
path?: string; path?: string;
content?: string; content?: string;
type?: string; type?: string;
id?: string;
}): Promise<ElementHandle> { }): Promise<ElementHandle> {
return this.mainFrame().addScriptTag(options); return this.mainFrame().addScriptTag(options);
} }

View File

@ -1406,6 +1406,15 @@ describe('Page', function () {
expect(await page.evaluate(() => globalThis.__injected)).toBe(35); expect(await page.evaluate(() => globalThis.__injected)).toBe(35);
}); });
it('should add id when provided', async () => {
const { page, server } = getTestState();
await page.goto(server.EMPTY_PAGE);
await page.addScriptTag({ content: 'window.__injected = 1;', id: 'one' });
await page.addScriptTag({ url: '/injectedfile.js', id: 'two' });
expect(await page.$('#one')).not.toBeNull();
expect(await page.$('#two')).not.toBeNull();
});
// @see https://github.com/puppeteer/puppeteer/issues/4840 // @see https://github.com/puppeteer/puppeteer/issues/4840
xit('should throw when added with content to the CSP page', async () => { xit('should throw when added with content to the CSP page', async () => {
const { page, server } = getTestState(); const { page, server } = getTestState();