chore: migrate addStyleTag (#8879)

* chore: remove unnecessary type signature

* chore: fix tests

* chore: migrate `addStyleTag`

* chore: fix tests

* chore: fix tests
This commit is contained in:
jrandolf 2022-09-01 17:52:08 +02:00 committed by GitHub
parent 8f11237a67
commit 6b4a99fcfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 179 additions and 128 deletions

View File

@ -4,26 +4,26 @@ sidebar_label: Frame.addStyleTag
# Frame.addStyleTag() method # Frame.addStyleTag() method
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.
**Signature:** **Signature:**
```typescript ```typescript
class Frame { class Frame {
addStyleTag( addStyleTag(
options: FrameAddStyleTagOptions options: Omit<FrameAddStyleTagOptions, 'url'>
): Promise<ElementHandle<HTMLStyleElement | HTMLLinkElement>>; ): Promise<ElementHandle<HTMLStyleElement>>;
} }
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ----------------------------------------------------------------- | --------------------------- | | --------- | ------------------------------------------------------------------------------------ | ----------- |
| options | [FrameAddStyleTagOptions](./puppeteer.frameaddstyletagoptions.md) | Options for the style link. | | options | Omit&lt;[FrameAddStyleTagOptions](./puppeteer.frameaddstyletagoptions.md), 'url'&gt; | |
**Returns:** **Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLStyleElement \| HTMLLinkElement&gt;&gt; Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLStyleElement&gt;&gt;
a promise that resolves to the added tag when the stylesheets's `onload` event fires or when the CSS content was injected into the frame. An [element handle](./puppeteer.elementhandle.md) to the loaded `<link>` or `<style>` element.

View File

@ -0,0 +1,25 @@
---
sidebar_label: Frame.addStyleTag_1
---
# Frame.addStyleTag() method
**Signature:**
```typescript
class Frame {
addStyleTag(
options: FrameAddStyleTagOptions
): Promise<ElementHandle<HTMLLinkElement>>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ----------------------------------------------------------------- | ----------- |
| options | [FrameAddStyleTagOptions](./puppeteer.frameaddstyletagoptions.md) | |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLLinkElement&gt;&gt;

View File

@ -69,7 +69,8 @@ console.log(text);
| [$eval(selector, pageFunction, args)](./puppeteer.frame._eval.md) | | <p>Runs the given function on the first element matching the given selector in the frame.</p><p>If the given function returns a promise, then this method will wait till the promise resolves.</p> | | [$eval(selector, pageFunction, args)](./puppeteer.frame._eval.md) | | <p>Runs the given function on the first element matching the given selector in the frame.</p><p>If the given function returns a promise, then this method will wait till the promise resolves.</p> |
| [$x(expression)](./puppeteer.frame._x.md) | | | | [$x(expression)](./puppeteer.frame._x.md) | | |
| [addScriptTag(options)](./puppeteer.frame.addscripttag.md) | | Adds a <code>&lt;script&gt;</code> tag into the page with the desired url or content. | | [addScriptTag(options)](./puppeteer.frame.addscripttag.md) | | Adds a <code>&lt;script&gt;</code> tag into the page with the desired url or content. |
| [addStyleTag(options)](./puppeteer.frame.addstyletag.md) | | Adds a <code>&lt;link rel=&quot;stylesheet&quot;&gt;</code> tag into the page with the desired url or a <code>&lt;style type=&quot;text/css&quot;&gt;</code> tag with the content. | | [addStyleTag(options)](./puppeteer.frame.addstyletag.md) | | Adds a <code>&lt;link rel=&quot;stylesheet&quot;&gt;</code> tag into the page with the desired URL or a <code>&lt;style type=&quot;text/css&quot;&gt;</code> tag with the content. |
| [addStyleTag(options)](./puppeteer.frame.addstyletag_1.md) | | |
| [childFrames()](./puppeteer.frame.childframes.md) | | | | [childFrames()](./puppeteer.frame.childframes.md) | | |
| [click(selector, options)](./puppeteer.frame.click.md) | | Clicks the first element found that matches <code>selector</code>. | | [click(selector, options)](./puppeteer.frame.click.md) | | Clicks the first element found that matches <code>selector</code>. |
| [content()](./puppeteer.frame.content.md) | | | | [content()](./puppeteer.frame.content.md) | | |

View File

@ -6,26 +6,26 @@ sidebar_label: Page.addStyleTag
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.
Shortcut for .
**Signature:** **Signature:**
```typescript ```typescript
class Page { class Page {
addStyleTag(options: { addStyleTag(
url?: string; options: Omit<FrameAddStyleTagOptions, 'url'>
path?: string; ): Promise<ElementHandle<HTMLStyleElement>>;
content?: string;
}): Promise<ElementHandle<Node>>;
} }
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | -------------------------------------------------- | ----------- | | --------- | ------------------------------------------------------------------------------------ | ----------- |
| options | { url?: string; path?: string; content?: string; } | | | options | Omit&lt;[FrameAddStyleTagOptions](./puppeteer.frameaddstyletagoptions.md), 'url'&gt; | |
**Returns:** **Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt;&gt; Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLStyleElement&gt;&gt;
Promise which resolves to the added tag when the stylesheet's onload fires or when the CSS content was injected into frame. An [element handle](./puppeteer.elementhandle.md) to the injected `<link>` or `<style>` element.

View File

@ -0,0 +1,25 @@
---
sidebar_label: Page.addStyleTag_1
---
# Page.addStyleTag() method
**Signature:**
```typescript
class Page {
addStyleTag(
options: FrameAddStyleTagOptions
): Promise<ElementHandle<HTMLLinkElement>>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ----------------------------------------------------------------- | ----------- |
| options | [FrameAddStyleTagOptions](./puppeteer.frameaddstyletagoptions.md) | |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLLinkElement&gt;&gt;

View File

@ -82,7 +82,8 @@ page.off('request', logRequest);
| [$eval(selector, pageFunction, args)](./puppeteer.page._eval.md) | | This method runs <code>document.querySelector</code> within the page and passes the result as the first argument to the <code>pageFunction</code>. | | [$eval(selector, pageFunction, args)](./puppeteer.page._eval.md) | | This method runs <code>document.querySelector</code> within the page and passes the result as the first argument to the <code>pageFunction</code>. |
| [$x(expression)](./puppeteer.page._x.md) | | The method evaluates the XPath expression relative to the page document as its context node. If there are no such elements, the method resolves to an empty array. | | [$x(expression)](./puppeteer.page._x.md) | | The method evaluates the XPath expression relative to the page document as its context node. If there are no such elements, the method resolves to an empty array. |
| [addScriptTag(options)](./puppeteer.page.addscripttag.md) | | Adds a <code>&lt;script&gt;</code> tag into the page with the desired URL or content. | | [addScriptTag(options)](./puppeteer.page.addscripttag.md) | | Adds a <code>&lt;script&gt;</code> tag into the page with the desired URL or content. |
| [addStyleTag(options)](./puppeteer.page.addstyletag.md) | | Adds a <code>&lt;link rel=&quot;stylesheet&quot;&gt;</code> tag into the page with the desired URL or a <code>&lt;style type=&quot;text/css&quot;&gt;</code> tag with the content. | | [addStyleTag(options)](./puppeteer.page.addstyletag.md) | | <p>Adds a <code>&lt;link rel=&quot;stylesheet&quot;&gt;</code> tag into the page with the desired URL or a <code>&lt;style type=&quot;text/css&quot;&gt;</code> tag with the content.</p><p>Shortcut for .</p> |
| [addStyleTag(options)](./puppeteer.page.addstyletag_1.md) | | |
| [authenticate(credentials)](./puppeteer.page.authenticate.md) | | Provide credentials for <code>HTTP authentication</code>. | | [authenticate(credentials)](./puppeteer.page.authenticate.md) | | Provide credentials for <code>HTTP authentication</code>. |
| [bringToFront()](./puppeteer.page.bringtofront.md) | | Brings page to front (activates tab). | | [bringToFront()](./puppeteer.page.bringtofront.md) | | Brings page to front (activates tab). |
| [browser()](./puppeteer.page.browser.md) | | Get the browser the page belongs to. | | [browser()](./puppeteer.page.browser.md) | | Get the browser the page belongs to. |

View File

@ -18,6 +18,7 @@ import {LifecycleWatcher, PuppeteerLifeCycleEvent} from './LifecycleWatcher.js';
import {Page} from './Page.js'; import {Page} from './Page.js';
import {getQueryHandlerAndSelector} from './QueryHandler.js'; import {getQueryHandlerAndSelector} from './QueryHandler.js';
import {EvaluateFunc, HandleFor, NodeFor} from './types.js'; import {EvaluateFunc, HandleFor, NodeFor} from './types.js';
import {importFS} from './util.js';
/** /**
* @public * @public
@ -751,7 +752,7 @@ export class Frame {
const {path} = options; const {path} = options;
if (+!!options.url + +!!path + +!!content !== 1) { if (+!!options.url + +!!path + +!!content !== 1) {
throw new Error( throw new Error(
'Exactly one of `url`, `path`, or `content` may be specified.' 'Exactly one of `url`, `path`, or `content` must be specified.'
); );
} }
@ -795,7 +796,11 @@ export class Frame {
script.addEventListener( script.addEventListener(
'error', 'error',
event => { event => {
rej(event.message ?? 'Could not load script'); let message = 'Could not load script';
if (event instanceof ErrorEvent) {
message = event.message ?? message;
}
rej(message);
}, },
{once: true} {once: true}
); );
@ -813,18 +818,87 @@ export class Frame {
} }
/** /**
* Adds a `<link rel="stylesheet">` tag into the page with the desired url or * Adds a `<link rel="stylesheet">` tag into the page with the desired URL or
* a `<style type="text/css">` tag with the content. * a `<style type="text/css">` tag with the content.
* *
* @param options - Options for the style link. * @returns An {@link ElementHandle | element handle} to the loaded `<link>`
* @returns a promise that resolves to the added tag when the stylesheets's * or `<style>` element.
* `onload` event fires or when the CSS content was injected into the
* frame.
*/ */
async addStyleTag(
options: Omit<FrameAddStyleTagOptions, 'url'>
): Promise<ElementHandle<HTMLStyleElement>>;
async addStyleTag(
options: FrameAddStyleTagOptions
): Promise<ElementHandle<HTMLLinkElement>>;
async addStyleTag( async addStyleTag(
options: FrameAddStyleTagOptions options: FrameAddStyleTagOptions
): Promise<ElementHandle<HTMLStyleElement | HTMLLinkElement>> { ): Promise<ElementHandle<HTMLStyleElement | HTMLLinkElement>> {
return this.worlds[MAIN_WORLD].addStyleTag(options); let {content = ''} = options;
const {path} = options;
if (+!!options.url + +!!path + +!!content !== 1) {
throw new Error(
'Exactly one of `url`, `path`, or `content` must be specified.'
);
}
if (path) {
let fs: typeof import('fs').promises;
try {
fs = (await importFS()).promises;
} catch (error) {
if (error instanceof TypeError) {
throw new Error(
'Can only pass a file path in a Node-like environment.'
);
}
throw error;
}
content = await fs.readFile(path, 'utf8');
content += '/*# sourceURL=' + path.replace(/\n/g, '') + '*/';
options.content = content;
}
return this.worlds[MAIN_WORLD].transferHandle(
await this.worlds[PUPPETEER_WORLD].evaluateHandle(
async ({url, content}) => {
if (!url) {
const style = document.createElement('style');
style.appendChild(document.createTextNode(content!));
const promise = new Promise((res, rej) => {
style.addEventListener('load', res, {once: true});
style.addEventListener(
'error',
event => {
rej(event.message ?? 'Could not load style');
},
{once: true}
);
});
document.head.appendChild(style);
await promise;
return style;
}
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
const promise = new Promise((res, rej) => {
link.addEventListener('load', res, {once: true});
link.addEventListener(
'error',
event => {
rej(event.message ?? 'Could not load style');
},
{once: true}
);
});
document.head.appendChild(link);
await promise;
return link;
},
options
)
);
} }
/** /**

View File

@ -32,7 +32,6 @@ import {EvaluateFunc, HandleFor, NodeFor} from './types.js';
import { import {
createJSHandle, createJSHandle,
debugError, debugError,
importFS,
isNumber, isNumber,
isString, isString,
makePredicateString, makePredicateString,
@ -334,92 +333,6 @@ export class IsolatedWorld {
} }
} }
/**
* Adds a style tag into the current context.
*
* @remarks
* You can pass a URL, filepath or string of contents. Note that when running Puppeteer
* in a browser environment you cannot pass a filepath and should use either
* `url` or `content`.
*/
async addStyleTag(options: {
url?: string;
path?: string;
content?: string;
}): Promise<ElementHandle<HTMLStyleElement | HTMLLinkElement>> {
const {url = null, path = null, content = null} = options;
if (url !== null) {
try {
const context = await this.executionContext();
return (await context.evaluateHandle(
addStyleUrl,
url
)) as ElementHandle<HTMLLinkElement>;
} catch (error) {
throw new Error(`Loading style from ${url} failed`);
}
}
if (path !== null) {
let fs: typeof import('fs').promises;
try {
fs = (await importFS()).promises;
} catch (error) {
if (error instanceof TypeError) {
throw new Error(
'Cannot pass a filepath to addStyleTag in the browser environment.'
);
}
throw error;
}
let contents = await fs.readFile(path, 'utf8');
contents += '/*# sourceURL=' + path.replace(/\n/g, '') + '*/';
const context = await this.executionContext();
return (await context.evaluateHandle(
addStyleContent,
contents
)) as ElementHandle<HTMLStyleElement>;
}
if (content !== null) {
const context = await this.executionContext();
return (await context.evaluateHandle(
addStyleContent,
content
)) as ElementHandle<HTMLStyleElement>;
}
throw new Error(
'Provide an object with a `url`, `path` or `content` property'
);
async function addStyleUrl(url: string): Promise<HTMLElement> {
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;
}
async function addStyleContent(content: string): Promise<HTMLElement> {
const style = document.createElement('style');
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;
}
}
async click( async click(
selector: string, selector: string,
options: {delay?: number; button?: MouseButton; clickCount?: number} options: {delay?: number; button?: MouseButton; clickCount?: number}

View File

@ -32,7 +32,11 @@ import {ElementHandle} from './ElementHandle.js';
import {EmulationManager} from './EmulationManager.js'; import {EmulationManager} from './EmulationManager.js';
import {EventEmitter, Handler} from './EventEmitter.js'; import {EventEmitter, Handler} from './EventEmitter.js';
import {FileChooser} from './FileChooser.js'; import {FileChooser} from './FileChooser.js';
import {Frame, FrameAddScriptTagOptions} from './Frame.js'; import {
Frame,
FrameAddScriptTagOptions,
FrameAddStyleTagOptions,
} from './Frame.js';
import {FrameManager, FrameManagerEmittedEvents} from './FrameManager.js'; import {FrameManager, FrameManagerEmittedEvents} from './FrameManager.js';
import {HTTPRequest} from './HTTPRequest.js'; import {HTTPRequest} from './HTTPRequest.js';
import {HTTPResponse} from './HTTPResponse.js'; import {HTTPResponse} from './HTTPResponse.js';
@ -1423,16 +1427,24 @@ export class Page extends EventEmitter {
} }
/** /**
* Adds a `<link rel="stylesheet">` tag into the page with the desired URL or a * Adds a `<link rel="stylesheet">` tag into the page with the desired URL or
* `<style type="text/css">` tag with the content. * a `<style type="text/css">` tag with the content.
* @returns Promise which resolves to the added tag when the stylesheet's *
* onload fires or when the CSS content was injected into frame. * Shortcut for
* {@link Frame.addStyleTag | page.mainFrame().addStyleTag(options)}.
*
* @returns An {@link ElementHandle | element handle} to the injected `<link>`
* or `<style>` element.
*/ */
async addStyleTag(options: { async addStyleTag(
url?: string; options: Omit<FrameAddStyleTagOptions, 'url'>
path?: string; ): Promise<ElementHandle<HTMLStyleElement>>;
content?: string; async addStyleTag(
}): Promise<ElementHandle<Node>> { options: FrameAddStyleTagOptions
): Promise<ElementHandle<HTMLLinkElement>>;
async addStyleTag(
options: FrameAddStyleTagOptions
): Promise<ElementHandle<HTMLStyleElement | HTMLLinkElement>> {
return this.mainFrame().addStyleTag(options); return this.mainFrame().addStyleTag(options);
} }

View File

@ -1631,7 +1631,7 @@ describe('Page', function () {
error = error_ as Error; error = error_ as Error;
} }
expect(error.message).toBe( expect(error.message).toBe(
'Exactly one of `url`, `path`, or `content` may be specified.' 'Exactly one of `url`, `path`, or `content` must be specified.'
); );
}); });
@ -1797,7 +1797,7 @@ describe('Page', function () {
error = error_ as Error; error = error_ as Error;
} }
expect(error.message).toBe( expect(error.message).toBe(
'Provide an object with a `url`, `path` or `content` property' 'Exactly one of `url`, `path`, or `content` must be specified.'
); );
}); });
@ -1824,7 +1824,7 @@ describe('Page', function () {
} catch (error_) { } catch (error_) {
error = error_ as Error; error = error_ as Error;
} }
expect(error.message).toBe('Loading style from /nonexistfile.js failed'); expect(error.message).toContain('Could not load style');
}); });
it('should work with a path', async () => { it('should work with a path', async () => {