Skip to content

Commit 20110bc

Browse files
adasqfrinyvonnick
andauthored
✨ Add timeout option (#189)
* timeout support added * 💡 Remove lint comments from tests --------- Co-authored-by: Yvonnick Frin <frin.yvonnick@gmail.com>
1 parent 7486250 commit 20110bc

File tree

7 files changed

+64
-16
lines changed

7 files changed

+64
-16
lines changed

README.md

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,23 @@ import nodeHtmlToImage from 'node-html-to-image'
6868

6969
List of all available options:
7070

71-
| option | description | type | required |
72-
|-------------------------|-------------------------------------------------------------------------------------------------|----------------------------|-------------|
73-
| output | The ouput path for generated image | string | optional |
74-
| html | The html used to generate image content | string | required |
75-
| type | The type of the generated image | jpeg or png (default: png) | optional |
76-
| quality | The quality of the generated image (only applicable to jpg) | number (default: 80) | optional |
77-
| content | If provided html property is considered an handlebars template and use content value to fill it | object or Array | optional |
78-
| waitUntil | Define when to consider markup succeded. [Learn more](https://github.com/puppeteer/puppeteer/blob/8370ec88ae94fa59d9e9dc0c154e48527d48c9fe/docs/api.md#pagesetcontenthtml-options). | string or Array<string> (default: networkidle0) | optional |
79-
| puppeteer | The puppeteer property let you use a different puppeteer library (like puppeteer-core or puppeteer-extra). | object (default: puppeteer) | optional |
80-
| puppeteerArgs | The puppeteerArgs property let you pass down custom configuration to puppeteer. [Learn more](https://github.com/puppeteer/puppeteer/blob/8370ec88ae94fa59d9e9dc0c154e48527d48c9fe/docs/api.md#puppeteerlaunchoptions). | object | optional |
81-
| beforeScreenshot | An async function that will execute just before screenshot is taken. Gives access to puppeteer page element. | Function | optional |
82-
| transparent | The transparent property lets you generate images with transparent background (for png type). | boolean | optional |
83-
| encoding | The encoding property of the image. Options are `binary` (default) or `base64`. | string | optional |
84-
| selector | The selector property lets you target a specific element to perform the screenshot on. (default `body`) | string | optional |
85-
| handlebarsHelpers | The handlebarsHelpers property lets add custom logic to the templates using Handlebars sub-expressions. [Learn more](https://handlebarsjs.com/guide/builtin-helpers.html#sub-expressions). | object | optional |
71+
| option | description | type | required |
72+
|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|-------------|
73+
| output | The ouput path for generated image | string | optional |
74+
| html | The html used to generate image content | string | required |
75+
| type | The type of the generated image | jpeg or png (default: png) | optional |
76+
| quality | The quality of the generated image (only applicable to jpg) | number (default: 80) | optional |
77+
| content | If provided html property is considered an handlebars template and use content value to fill it | object or Array | optional |
78+
| waitUntil | Define when to consider markup succeded. [Learn more](https://github.com/puppeteer/puppeteer/blob/8370ec88ae94fa59d9e9dc0c154e48527d48c9fe/docs/api.md#pagesetcontenthtml-options). | string or Array<string> (default: networkidle0) | optional |
79+
| puppeteer | The puppeteer property let you use a different puppeteer library (like puppeteer-core or puppeteer-extra). | object (default: puppeteer) | optional |
80+
| puppeteerArgs | The puppeteerArgs property let you pass down custom configuration to puppeteer. [Learn more](https://github.com/puppeteer/puppeteer/blob/8370ec88ae94fa59d9e9dc0c154e48527d48c9fe/docs/api.md#puppeteerlaunchoptions). | object | optional |
81+
| beforeScreenshot | An async function that will execute just before screenshot is taken. Gives access to puppeteer page element. | Function | optional |
82+
| transparent | The transparent property lets you generate images with transparent background (for png type). | boolean | optional |
83+
| encoding | The encoding property of the image. Options are `binary` (default) or `base64`. | string | optional |
84+
| selector | The selector property lets you target a specific element to perform the screenshot on. (default `body`) | string | optional |
85+
| handlebarsHelpers | The handlebarsHelpers property lets add custom logic to the templates using Handlebars sub-expressions. [Learn more](https://handlebarsjs.com/guide/builtin-helpers.html#sub-expressions). | object | optional |
86+
| timeout | Timeout for a [puppeteer-cluster](https://github.com/thomasdondorf/puppeteer-cluster#clusterlaunchoptions) (in `ms`). Defaults to `30000` (30 seconds). | number | optional |
87+
8688

8789
### Setting output image resolution
8890

src/main.integration.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ describe("node-html-to-image", () => {
7777
);
7878
});
7979

80+
it("should throw timeout error", async () => {
81+
await expect(async () => {
82+
await nodeHtmlToImage({
83+
timeout: 500,
84+
html: "<html></html>"
85+
});
86+
}).rejects.toThrow();
87+
expect(mockConsoleErr).toHaveBeenCalledWith(
88+
new Error("Timeout hit: 500")
89+
);
90+
});
91+
8092
it("should generate an jpeg image", async () => {
8193
await nodeHtmlToImage({
8294
output: "./generated/image.jpg",

src/main.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ export async function nodeHtmlToImage(options: Options) {
1515
type,
1616
quality,
1717
puppeteerArgs = {},
18+
timeout = 30000,
1819
puppeteer = undefined,
1920
} = options;
2021

2122
const cluster: Cluster<ScreenshotParams> = await Cluster.launch({
2223
concurrency: Cluster.CONCURRENCY_CONTEXT,
2324
maxConcurrency: 2,
25+
timeout,
2426
puppeteerOptions: { ...puppeteerArgs, headless: true },
2527
puppeteer: puppeteer,
2628
});

src/main.unit.spec.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
77

88
describe("node-html-to-image | Unit", () => {
99
let mockExit;
10+
let launchMock;
1011
const buffer1 = Buffer.alloc(1);
1112
const buffer2 = Buffer.alloc(1);
1213
const html = "<html><body>{{message}}</body></html>";
1314

1415
beforeEach(() => {
15-
jest.spyOn(Cluster, "launch").mockImplementation(
16+
launchMock = jest.spyOn(Cluster, "launch").mockImplementation(
1617
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
1718
// @ts-ignore
1819
jest.fn(() => ({
@@ -50,6 +51,16 @@ describe("node-html-to-image | Unit", () => {
5051

5152
expect(result).toEqual([buffer1, buffer2]);
5253
});
54+
55+
it("should pass 'timeout' to 'puppeteer-cluster' via options", async () => {
56+
const CLUSTER_TIMEOUT = 60 * 1000;
57+
await nodeHtmlToImage({
58+
html,
59+
timeout: CLUSTER_TIMEOUT,
60+
});
61+
62+
expect(launchMock).toHaveBeenCalledWith(expect.objectContaining({ timeout: CLUSTER_TIMEOUT }))
63+
});
5364
});
5465

5566
jest.mock("puppeteer-cluster");

src/screenshot.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ describe("beforeScreenshot", () => {
1010
beforeEach(() => {
1111
page = {
1212
setContent: jest.fn(),
13+
setDefaultTimeout: jest.fn(),
1314
$: jest.fn(() => ({ screenshot: jest.fn(() => buffer) })),
1415
};
1516
});
@@ -50,6 +51,20 @@ describe("beforeScreenshot", () => {
5051
);
5152
});
5253

54+
it("should call 'setDefaultTimeout' with option's timeout", async () => {
55+
const TIMEOUT = 40 * 1000;
56+
57+
await makeScreenshot(page, {
58+
timeout: TIMEOUT,
59+
screenshot: new Screenshot({
60+
html: "<html><body>{{message}}</body></html>",
61+
content: { message: "Hello world!" },
62+
}),
63+
});
64+
65+
expect(page.setDefaultTimeout).toHaveBeenCalledWith(TIMEOUT);
66+
});
67+
5368
it("should not compile a screenshot if content is empty", async () => {
5469
await makeScreenshot(page, {
5570
screenshot: new Screenshot({
@@ -97,6 +112,7 @@ describe("handlebarsHelpers", () => {
97112
beforeEach(() => {
98113
page = {
99114
setContent: jest.fn(),
115+
setDefaultTimeout: jest.fn(),
100116
$: jest.fn(() => ({ screenshot: jest.fn(() => buffer) })),
101117
};
102118
if (

src/screenshot.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ export async function makeScreenshot(
99
screenshot,
1010
beforeScreenshot,
1111
waitUntil = "networkidle0",
12+
timeout,
1213
handlebarsHelpers,
1314
}: MakeScreenshotParams
1415
) {
16+
page.setDefaultTimeout(timeout);
1517
const hasHelpers = handlebarsHelpers && typeof handlebarsHelpers === "object";
1618
if (hasHelpers) {
1719
if (

src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@ export interface Options extends ScreenshotParams {
2323
puppeteer?: any,
2424
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
2525
beforeScreenshot?: (page: Page) => void;
26+
timeout?: number
2627
}
2728

2829
export interface MakeScreenshotParams {
2930
screenshot: Screenshot;
3031
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
3132
beforeScreenshot?: (page: Page) => void;
3233
handlebarsHelpers?: { [helpers: string]: (...args: any[]) => any };
34+
35+
timeout?: number
3336
}

0 commit comments

Comments
 (0)