Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: id option for addScriptTag #5477

Merged
merged 3 commits into from
Sep 14, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 5 additions & 3 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1390,7 +1390,8 @@ Shortcut for [page.mainFrame().$x(expression)](#framexexpression)
- `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).
- `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.

Adds a `<script>` tag into the page with the desired URL or content.
Expand Down Expand Up @@ -2328,7 +2329,7 @@ await page.setGeolocation({ latitude: 59.95, longitude: 30.31667 });

#### page.setOfflineMode(enabled)

- `enabled` <[boolean]> When `true`, enables offline mode for the page.
- `enabled` <[boolean]> When `true`, enables offline mode for the page.
- returns: <[Promise]>

> **NOTE** while this method sets the network connection to offline, it does not change the parameters used in [page.emulateNetworkConditions(networkConditions)](#pageemulatenetworkconditionsnetworkconditions).
Expand Down Expand Up @@ -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.
- `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.
- `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.

Adds a `<script>` tag into the page with the desired URL or content.
Expand Down
23 changes: 17 additions & 6 deletions experimental/puppeteer-firefox/lib/DOMWorld.js
Original file line number Diff line number Diff line change
Expand Up @@ -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>}
*/
async addScriptTag(options) {
const {
type = '',
id = ''
} = options;

if (typeof options.url === 'string') {
const url = options.url;
try {
return (await this.evaluateHandle(addScriptUrl, url, options.type)).asElement();
return (await this.evaluateHandle(addScriptUrl, url, id, type)).asElement();
} catch (error) {
throw new Error(`Loading script from ${url} failed`);
}
Expand All @@ -156,23 +161,26 @@ class DOMWorld {
if (typeof options.path === 'string') {
let contents = await readFileAsync(options.path, 'utf8');
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') {
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');

/**
* @param {string} url
* @param {string} id
* @param {string} type
* @return {!Promise<!HTMLElement>}
*/
async function addScriptUrl(url, type) {
async function addScriptUrl(url, id, type) {
const script = document.createElement('script');
script.src = url;
if (id)
script.id = id;
if (type)
script.type = type;
const promise = new Promise((res, rej) => {
Expand All @@ -186,13 +194,16 @@ class DOMWorld {

/**
* @param {string} content
* @param {string} id
* @param {string} type
* @return {!HTMLElement}
*/
function addScriptContent(content, type = 'text/javascript') {
function addScriptContent(content, id, type = 'text/javascript') {
const script = document.createElement('script');
script.type = type;
script.text = content;
if (id)
script.id = id;
let error = null;
script.onerror = e => error = e;
document.head.appendChild(script);
Expand Down
2 changes: 1 addition & 1 deletion experimental/puppeteer-firefox/lib/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -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>}
*/
async addScriptTag(options) {
Expand Down
19 changes: 15 additions & 4 deletions src/common/DOMWorld.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,14 +282,21 @@ export class DOMWorld {
url?: string;
path?: string;
content?: string;
id?: string;
type?: string;
}): Promise<ElementHandle> {
const { url = null, path = null, content = null, type = '' } = options;
const {
url = null,
path = null,
content = null,
id = '',
type = '',
} = options;
if (url !== null) {
try {
const context = await this.executionContext();
return (
await context.evaluateHandle(addScriptUrl, url, type)
await context.evaluateHandle(addScriptUrl, url, id, type)
).asElement();
} catch (error) {
throw new Error(`Loading script from ${url} failed`);
Expand All @@ -307,14 +314,14 @@ export class DOMWorld {
contents += '//# sourceURL=' + path.replace(/\n/g, '');
const context = await this.executionContext();
return (
await context.evaluateHandle(addScriptContent, contents, type)
await context.evaluateHandle(addScriptContent, contents, id, type)
).asElement();
}

if (content !== null) {
const context = await this.executionContext();
return (
await context.evaluateHandle(addScriptContent, content, type)
await context.evaluateHandle(addScriptContent, content, id, type)
).asElement();
}

Expand All @@ -324,10 +331,12 @@ export class DOMWorld {

async function addScriptUrl(
url: string,
id: string,
type: string
): Promise<HTMLElement> {
const script = document.createElement('script');
script.src = url;
if (id) script.id = id;
if (type) script.type = type;
const promise = new Promise((res, rej) => {
script.onload = res;
Expand All @@ -340,11 +349,13 @@ export class DOMWorld {

function addScriptContent(
content: string,
id: string,
type = 'text/javascript'
): HTMLElement {
const script = document.createElement('script');
script.type = type;
script.text = content;
if (id) script.id = id;
let error = null;
script.onerror = (e) => (error = e);
document.head.appendChild(script);
Expand Down
1 change: 1 addition & 0 deletions src/common/Page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,7 @@ export class Page extends EventEmitter {
path?: string;
content?: string;
type?: string;
id?: string;
}): Promise<ElementHandle> {
return this.mainFrame().addScriptTag(options);
}
Expand Down
9 changes: 9 additions & 0 deletions test/page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1406,6 +1406,15 @@ describe('Page', function () {
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
xit('should throw when added with content to the CSP page', async () => {
const { page, server } = getTestState();
Expand Down