@argos-ci/puppeteer 5.2.0 → 5.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  const argosScreenshot = async (...args) => {
2
- const { argosScreenshot } = await import("./index.js");
2
+ const { argosScreenshot } = await import("./index.mjs");
3
3
  return argosScreenshot(...args);
4
4
  };
5
5
 
@@ -0,0 +1,65 @@
1
+ import { StabilizationPluginOptions, ViewportOption } from "@argos-ci/browser";
2
+ import { ElementHandle, Page, ScreenshotOptions } from "puppeteer";
3
+
4
+ //#region src/index.d.ts
5
+ /**
6
+ * Accepts all Puppeteer screenshot options and adds Argos-specific options.
7
+ */
8
+ type ArgosScreenshotOptions = Omit<ScreenshotOptions, "encoding" | "type" | "omitBackground" | "path"> & {
9
+ /**
10
+ * ElementHandle or string selector of the element to take a screenshot of.
11
+ */
12
+ element?: string | ElementHandle;
13
+ /**
14
+ * Viewports to take screenshots of.
15
+ */
16
+ viewports?: ViewportOption[];
17
+ /**
18
+ * Custom CSS evaluated during the screenshot process.
19
+ */
20
+ argosCSS?: string;
21
+ /**
22
+ * Disable hover effects by moving the mouse to the top-left corner of the page.
23
+ * @default true
24
+ */
25
+ disableHover?: boolean;
26
+ /**
27
+ * Sensitivity threshold between 0 and 1.
28
+ * The higher the threshold, the less sensitive the diff will be.
29
+ * @default 0.5
30
+ */
31
+ threshold?: number;
32
+ /**
33
+ * Wait for the UI to stabilize before taking the screenshot.
34
+ * Set to `false` to disable stabilization.
35
+ * Pass an object to customize the stabilization.
36
+ * @default true
37
+ */
38
+ stabilize?: boolean | StabilizationPluginOptions;
39
+ /**
40
+ * Tag or array of tags to attach to the screenshot.
41
+ */
42
+ tag?: string | string[];
43
+ };
44
+ /**
45
+ * Stabilize the UI and takes a screenshot of the application under test.
46
+ *
47
+ * @example
48
+ * argosScreenshot(page, "my-screenshot")
49
+ * @see https://argos-ci.com/docs/puppeteer#api-overview
50
+ */
51
+ declare function argosScreenshot(
52
+ /**
53
+ * Puppeteer `page` object.
54
+ */
55
+ page: Page,
56
+ /**
57
+ * Name of the screenshot. Must be unique.
58
+ */
59
+ name: string,
60
+ /**
61
+ * Options for the screenshot.
62
+ */
63
+ options?: ArgosScreenshotOptions): Promise<void>;
64
+ //#endregion
65
+ export { ArgosScreenshotOptions, argosScreenshot };
package/dist/index.mjs ADDED
@@ -0,0 +1,187 @@
1
+ import { createRequire } from "node:module";
2
+ import { resolve } from "node:path";
3
+ import { mkdir } from "node:fs/promises";
4
+ import { getGlobalScript, resolveViewport } from "@argos-ci/browser";
5
+ import { getScreenshotName, readVersionFromPackage, validateThreshold, writeMetadata } from "@argos-ci/util";
6
+ //#region src/index.ts
7
+ const require = createRequire(import.meta.url);
8
+ /**
9
+ * Inject Argos script into the page.
10
+ */
11
+ async function injectArgos(page) {
12
+ if (await page.evaluate(() => typeof window.__ARGOS__ !== "undefined")) return;
13
+ await page.addScriptTag({ content: getGlobalScript() });
14
+ }
15
+ async function getPuppeteerVersion() {
16
+ return readVersionFromPackage(require.resolve("puppeteer/package.json"));
17
+ }
18
+ async function getArgosPuppeteerVersion() {
19
+ return readVersionFromPackage(require.resolve("@argos-ci/puppeteer/package.json"));
20
+ }
21
+ function getViewport(page) {
22
+ const viewport = page.viewport();
23
+ if (!viewport) throw new Error("Can't take screenshots without a viewport.");
24
+ return viewport;
25
+ }
26
+ async function getBrowserInfo(page) {
27
+ const [browserName, browserVersion] = (await page.browser().version()).split("/");
28
+ return {
29
+ browserName,
30
+ browserVersion
31
+ };
32
+ }
33
+ async function getScreenshotPath(name) {
34
+ if (name.endsWith(".png")) return name;
35
+ const screenshotFolder = resolve(process.cwd(), "screenshots/argos");
36
+ await mkdir(screenshotFolder, { recursive: true });
37
+ return resolve(screenshotFolder, name + ".png");
38
+ }
39
+ function checkIsFullPage(options) {
40
+ return options.fullPage !== void 0 ? options.fullPage : options.element === void 0;
41
+ }
42
+ /**
43
+ * Sets the viewport size and waits for the visual viewport to match the specified dimensions.
44
+ * @returns A promise that resolves when the viewport size has been successfully set and matched.
45
+ */
46
+ async function setViewportSize(page, viewportSize) {
47
+ await page.setViewport(viewportSize);
48
+ await page.waitForFunction(({ width, height }) => window.innerWidth === width && window.innerHeight === height, {}, {
49
+ width: viewportSize.width,
50
+ height: viewportSize.height
51
+ });
52
+ }
53
+ /**
54
+ * Get the stabilization context from the options.
55
+ */
56
+ function getStabilizationContext(options) {
57
+ const { argosCSS, viewports } = options;
58
+ return {
59
+ fullPage: checkIsFullPage(options),
60
+ argosCSS,
61
+ viewports,
62
+ options: options.stabilize
63
+ };
64
+ }
65
+ /**
66
+ * Run before taking all screenshots.
67
+ */
68
+ async function beforeAll(page, options) {
69
+ const { disableHover = true } = options;
70
+ const context = getStabilizationContext(options);
71
+ await page.evaluate((context) => window.__ARGOS__.beforeAll(context), context);
72
+ if (disableHover) await page.mouse.move(0, 0);
73
+ return async () => {
74
+ await page.evaluate(() => window.__ARGOS__.afterAll());
75
+ };
76
+ }
77
+ /**
78
+ * Run before taking each screenshot.
79
+ */
80
+ async function beforeEach(page, options) {
81
+ const context = getStabilizationContext(options);
82
+ await page.evaluate((context) => window.__ARGOS__.beforeEach(context), context);
83
+ return async () => {
84
+ await page.evaluate(() => window.__ARGOS__.afterEach());
85
+ };
86
+ }
87
+ /**
88
+ * Wait for the UI to be ready before taking the screenshot.
89
+ */
90
+ async function waitForReadiness(page, options) {
91
+ const context = getStabilizationContext(options);
92
+ try {
93
+ await page.waitForFunction((context) => window.__ARGOS__.waitFor(context), void 0, context);
94
+ } catch (error) {
95
+ const reasons = await page.evaluate((context) => window.__ARGOS__.getWaitFailureExplanations(context), context);
96
+ throw new Error(`
97
+ Failed to stabilize screenshot, found the following issues:
98
+ ${reasons.map((reason) => `- ${reason}`).join("\n")}
99
+ `.trim(), { cause: error });
100
+ }
101
+ }
102
+ /**
103
+ * Stabilize the UI and takes a screenshot of the application under test.
104
+ *
105
+ * @example
106
+ * argosScreenshot(page, "my-screenshot")
107
+ * @see https://argos-ci.com/docs/puppeteer#api-overview
108
+ */
109
+ async function argosScreenshot(page, name, options = {}) {
110
+ const { element, viewports, argosCSS: _argosCSS, ...puppeteerOptions } = options;
111
+ if (!page) throw new Error("A Puppeteer `page` object is required.");
112
+ if (!name) throw new Error("The `name` argument is required.");
113
+ const [originalViewport] = await Promise.all([getViewport(page), injectArgos(page)]);
114
+ const afterAll = await beforeAll(page, options);
115
+ const fullPage = checkIsFullPage(options);
116
+ async function collectMetadata() {
117
+ const [colorScheme, mediaType, puppeteerVersion, argosPuppeteerVersion, { browserName, browserVersion }] = await Promise.all([
118
+ page.evaluate(() => window.__ARGOS__.getColorScheme()),
119
+ page.evaluate(() => window.__ARGOS__.getMediaType()),
120
+ getPuppeteerVersion(),
121
+ getArgosPuppeteerVersion(),
122
+ getBrowserInfo(page)
123
+ ]);
124
+ const viewport = getViewport(page);
125
+ const metadata = {
126
+ url: page.url(),
127
+ viewport: {
128
+ width: viewport.width,
129
+ height: viewport.height
130
+ },
131
+ colorScheme,
132
+ mediaType,
133
+ test: null,
134
+ browser: browserName || browserVersion ? {
135
+ name: browserName || "unknown",
136
+ version: browserVersion || "unknown"
137
+ } : void 0,
138
+ automationLibrary: {
139
+ name: "puppeteer",
140
+ version: puppeteerVersion
141
+ },
142
+ sdk: {
143
+ name: "@argos-ci/puppeteer",
144
+ version: argosPuppeteerVersion
145
+ }
146
+ };
147
+ metadata.transient = {};
148
+ if (options?.tag) metadata.tags = Array.isArray(options.tag) ? options.tag : [options.tag];
149
+ if (options?.threshold !== void 0) {
150
+ validateThreshold(options.threshold);
151
+ metadata.transient.threshold = options.threshold;
152
+ }
153
+ return metadata;
154
+ }
155
+ async function stabilizeAndScreenshot(name) {
156
+ await waitForReadiness(page, options);
157
+ const afterEach = await beforeEach(page, options);
158
+ await waitForReadiness(page, options);
159
+ const [screenshotPath, metadata] = await Promise.all([getScreenshotPath(name), collectMetadata()]);
160
+ await writeMetadata(screenshotPath, metadata);
161
+ const screenshotOptions = {
162
+ path: screenshotPath,
163
+ type: "png",
164
+ fullPage,
165
+ ...puppeteerOptions
166
+ };
167
+ if (element === void 0) await page.screenshot(screenshotOptions);
168
+ else if (typeof element === "string") {
169
+ await page.waitForSelector(element);
170
+ const handle = await page.$(element);
171
+ if (!handle) throw new Error(`Unable to find element ${element}`);
172
+ await handle.screenshot(screenshotOptions);
173
+ } else await element.screenshot(screenshotOptions);
174
+ await afterEach();
175
+ }
176
+ if (viewports) {
177
+ for (const viewport of viewports) {
178
+ const viewportSize = resolveViewport(viewport);
179
+ await setViewportSize(page, viewportSize);
180
+ await stabilizeAndScreenshot(getScreenshotName(name, { viewportWidth: viewportSize.width }));
181
+ }
182
+ await setViewportSize(page, originalViewport);
183
+ } else await stabilizeAndScreenshot(name);
184
+ await afterAll();
185
+ }
186
+ //#endregion
187
+ export { argosScreenshot };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@argos-ci/puppeteer",
3
3
  "description": "Puppeteer SDK for visual testing with Argos.",
4
- "version": "5.2.0",
4
+ "version": "5.2.2",
5
5
  "author": "Smooth Code",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -25,11 +25,11 @@
25
25
  "access": "public"
26
26
  },
27
27
  "type": "module",
28
- "types": "./dist/index.d.ts",
28
+ "types": "./dist/index.d.mts",
29
29
  "exports": {
30
30
  ".": {
31
- "types": "./dist/index.d.ts",
32
- "import": "./dist/index.js",
31
+ "types": "./dist/index.d.mts",
32
+ "import": "./dist/index.mjs",
33
33
  "require": "./dist/index.cjs",
34
34
  "default": "./dist/index.cjs"
35
35
  },
@@ -42,21 +42,21 @@
42
42
  "puppeteer": ">=1"
43
43
  },
44
44
  "dependencies": {
45
- "@argos-ci/browser": "5.1.2",
46
- "@argos-ci/util": "3.3.0"
45
+ "@argos-ci/browser": "5.1.3",
46
+ "@argos-ci/util": "3.4.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@argos-ci/cli": "4.1.2",
49
+ "@argos-ci/cli": "4.1.4",
50
50
  "@types/jest": "^30.0.0",
51
51
  "@types/node": "catalog:",
52
52
  "expect-puppeteer": "^11.0.0",
53
- "jest": "^30.2.0",
53
+ "jest": "^30.3.0",
54
54
  "jest-light-runner": "^0.7.11",
55
55
  "jest-puppeteer": "^11.0.0",
56
- "puppeteer": "^24.36.1"
56
+ "puppeteer": "^24.40.0"
57
57
  },
58
58
  "scripts": {
59
- "build": "tsup && cp ./src/index.cjs ./dist",
59
+ "build": "tsdown && cp ./src/index.cjs ./dist",
60
60
  "jest": "NODE_OPTIONS=--experimental-vm-modules jest",
61
61
  "test-e2e": "pnpm run jest --runInBand",
62
62
  "argos-upload": "pnpm exec argos upload screenshots --build-name \"argos-puppeteer-e2e-node-$NODE_VERSION-$OS\"",
@@ -66,5 +66,5 @@
66
66
  "check-format": "prettier --check --ignore-unknown --ignore-path=../../.gitignore --ignore-path=../../.prettierignore .",
67
67
  "lint": "eslint ."
68
68
  },
69
- "gitHead": "3e325792c50e801034c3248d94d7b1dc91bede71"
69
+ "gitHead": "82add1422f689642095d43a9e3bb0d2a008728af"
70
70
  }
package/dist/index.d.ts DELETED
@@ -1,64 +0,0 @@
1
- import { ScreenshotOptions, ElementHandle, Page } from 'puppeteer';
2
- import { ViewportOption, StabilizationPluginOptions } from '@argos-ci/browser';
3
-
4
- /**
5
- * Accepts all Puppeteer screenshot options and adds Argos-specific options.
6
- */
7
- type ArgosScreenshotOptions = Omit<ScreenshotOptions, "encoding" | "type" | "omitBackground" | "path"> & {
8
- /**
9
- * ElementHandle or string selector of the element to take a screenshot of.
10
- */
11
- element?: string | ElementHandle;
12
- /**
13
- * Viewports to take screenshots of.
14
- */
15
- viewports?: ViewportOption[];
16
- /**
17
- * Custom CSS evaluated during the screenshot process.
18
- */
19
- argosCSS?: string;
20
- /**
21
- * Disable hover effects by moving the mouse to the top-left corner of the page.
22
- * @default true
23
- */
24
- disableHover?: boolean;
25
- /**
26
- * Sensitivity threshold between 0 and 1.
27
- * The higher the threshold, the less sensitive the diff will be.
28
- * @default 0.5
29
- */
30
- threshold?: number;
31
- /**
32
- * Wait for the UI to stabilize before taking the screenshot.
33
- * Set to `false` to disable stabilization.
34
- * Pass an object to customize the stabilization.
35
- * @default true
36
- */
37
- stabilize?: boolean | StabilizationPluginOptions;
38
- /**
39
- * Tag or array of tags to attach to the screenshot.
40
- */
41
- tag?: string | string[];
42
- };
43
- /**
44
- * Stabilize the UI and takes a screenshot of the application under test.
45
- *
46
- * @example
47
- * argosScreenshot(page, "my-screenshot")
48
- * @see https://argos-ci.com/docs/puppeteer#api-overview
49
- */
50
- declare function argosScreenshot(
51
- /**
52
- * Puppeteer `page` object.
53
- */
54
- page: Page,
55
- /**
56
- * Name of the screenshot. Must be unique.
57
- */
58
- name: string,
59
- /**
60
- * Options for the screenshot.
61
- */
62
- options?: ArgosScreenshotOptions): Promise<void>;
63
-
64
- export { type ArgosScreenshotOptions, argosScreenshot };
package/dist/index.js DELETED
@@ -1,239 +0,0 @@
1
- // src/index.ts
2
- import { resolve } from "path";
3
- import { mkdir } from "fs/promises";
4
- import { createRequire } from "module";
5
- import {
6
- resolveViewport,
7
- getGlobalScript
8
- } from "@argos-ci/browser";
9
- import {
10
- getScreenshotName,
11
- readVersionFromPackage,
12
- validateThreshold,
13
- writeMetadata
14
- } from "@argos-ci/util";
15
- var require2 = createRequire(import.meta.url);
16
- async function injectArgos(page) {
17
- const injected = await page.evaluate(
18
- () => typeof window.__ARGOS__ !== "undefined"
19
- );
20
- if (injected) {
21
- return;
22
- }
23
- await page.addScriptTag({ content: getGlobalScript() });
24
- }
25
- async function getPuppeteerVersion() {
26
- const pkgPath = require2.resolve("puppeteer/package.json");
27
- return readVersionFromPackage(pkgPath);
28
- }
29
- async function getArgosPuppeteerVersion() {
30
- const pkgPath = require2.resolve("@argos-ci/puppeteer/package.json");
31
- return readVersionFromPackage(pkgPath);
32
- }
33
- function getViewport(page) {
34
- const viewport = page.viewport();
35
- if (!viewport) {
36
- throw new Error("Can't take screenshots without a viewport.");
37
- }
38
- return viewport;
39
- }
40
- async function getBrowserInfo(page) {
41
- const rawVersion = await page.browser().version();
42
- const [browserName, browserVersion] = rawVersion.split("/");
43
- return { browserName, browserVersion };
44
- }
45
- async function getScreenshotPath(name) {
46
- if (name.endsWith(".png")) {
47
- return name;
48
- }
49
- const screenshotFolder = resolve(process.cwd(), "screenshots/argos");
50
- await mkdir(screenshotFolder, { recursive: true });
51
- return resolve(screenshotFolder, name + ".png");
52
- }
53
- function checkIsFullPage(options) {
54
- return options.fullPage !== void 0 ? options.fullPage : options.element === void 0;
55
- }
56
- async function setViewportSize(page, viewportSize) {
57
- await page.setViewport(viewportSize);
58
- await page.waitForFunction(
59
- ({ width, height }) => window.innerWidth === width && window.innerHeight === height,
60
- {},
61
- { width: viewportSize.width, height: viewportSize.height }
62
- );
63
- }
64
- function getStabilizationContext(options) {
65
- const { argosCSS, viewports } = options;
66
- const fullPage = checkIsFullPage(options);
67
- return {
68
- fullPage,
69
- argosCSS,
70
- viewports,
71
- options: options.stabilize
72
- };
73
- }
74
- async function beforeAll(page, options) {
75
- const { disableHover = true } = options;
76
- const context = getStabilizationContext(options);
77
- await page.evaluate(
78
- (context2) => window.__ARGOS__.beforeAll(context2),
79
- context
80
- );
81
- if (disableHover) {
82
- await page.mouse.move(0, 0);
83
- }
84
- return async () => {
85
- await page.evaluate(
86
- () => window.__ARGOS__.afterAll()
87
- );
88
- };
89
- }
90
- async function beforeEach(page, options) {
91
- const context = getStabilizationContext(options);
92
- await page.evaluate(
93
- (context2) => window.__ARGOS__.beforeEach(context2),
94
- context
95
- );
96
- return async () => {
97
- await page.evaluate(
98
- () => window.__ARGOS__.afterEach()
99
- );
100
- };
101
- }
102
- async function waitForReadiness(page, options) {
103
- const context = getStabilizationContext(options);
104
- try {
105
- await page.waitForFunction(
106
- (context2) => window.__ARGOS__.waitFor(context2),
107
- void 0,
108
- context
109
- );
110
- } catch (error) {
111
- const reasons = await page.evaluate(
112
- (context2) => window.__ARGOS__.getWaitFailureExplanations(
113
- context2
114
- ),
115
- context
116
- );
117
- throw new Error(
118
- `
119
- Failed to stabilize screenshot, found the following issues:
120
- ${reasons.map((reason) => `- ${reason}`).join("\n")}
121
- `.trim(),
122
- { cause: error }
123
- );
124
- }
125
- }
126
- async function argosScreenshot(page, name, options = {}) {
127
- const {
128
- element,
129
- viewports,
130
- argosCSS: _argosCSS,
131
- ...puppeteerOptions
132
- } = options;
133
- if (!page) {
134
- throw new Error("A Puppeteer `page` object is required.");
135
- }
136
- if (!name) {
137
- throw new Error("The `name` argument is required.");
138
- }
139
- const [originalViewport] = await Promise.all([
140
- getViewport(page),
141
- // Inject Argos script into the page
142
- injectArgos(page)
143
- ]);
144
- const afterAll = await beforeAll(page, options);
145
- const fullPage = checkIsFullPage(options);
146
- async function collectMetadata() {
147
- const [
148
- colorScheme,
149
- mediaType,
150
- puppeteerVersion,
151
- argosPuppeteerVersion,
152
- { browserName, browserVersion }
153
- ] = await Promise.all([
154
- page.evaluate(
155
- () => window.__ARGOS__.getColorScheme()
156
- ),
157
- page.evaluate(
158
- () => window.__ARGOS__.getMediaType()
159
- ),
160
- getPuppeteerVersion(),
161
- getArgosPuppeteerVersion(),
162
- getBrowserInfo(page)
163
- ]);
164
- const viewport = getViewport(page);
165
- const metadata = {
166
- url: page.url(),
167
- viewport: { width: viewport.width, height: viewport.height },
168
- colorScheme,
169
- mediaType,
170
- test: null,
171
- browser: browserName || browserVersion ? {
172
- name: browserName || "unknown",
173
- version: browserVersion || "unknown"
174
- } : void 0,
175
- automationLibrary: {
176
- name: "puppeteer",
177
- version: puppeteerVersion
178
- },
179
- sdk: {
180
- name: "@argos-ci/puppeteer",
181
- version: argosPuppeteerVersion
182
- }
183
- };
184
- metadata.transient = {};
185
- if (options?.tag) {
186
- metadata.tags = Array.isArray(options.tag) ? options.tag : [options.tag];
187
- }
188
- if (options?.threshold !== void 0) {
189
- validateThreshold(options.threshold);
190
- metadata.transient.threshold = options.threshold;
191
- }
192
- return metadata;
193
- }
194
- async function stabilizeAndScreenshot(name2) {
195
- await waitForReadiness(page, options);
196
- const afterEach = await beforeEach(page, options);
197
- await waitForReadiness(page, options);
198
- const [screenshotPath, metadata] = await Promise.all([
199
- getScreenshotPath(name2),
200
- collectMetadata()
201
- ]);
202
- await writeMetadata(screenshotPath, metadata);
203
- const screenshotOptions = {
204
- path: screenshotPath,
205
- type: "png",
206
- fullPage,
207
- ...puppeteerOptions
208
- };
209
- if (element === void 0) {
210
- await page.screenshot(screenshotOptions);
211
- } else if (typeof element === "string") {
212
- await page.waitForSelector(element);
213
- const handle = await page.$(element);
214
- if (!handle) {
215
- throw new Error(`Unable to find element ${element}`);
216
- }
217
- await handle.screenshot(screenshotOptions);
218
- } else {
219
- await element.screenshot(screenshotOptions);
220
- }
221
- await afterEach();
222
- }
223
- if (viewports) {
224
- for (const viewport of viewports) {
225
- const viewportSize = resolveViewport(viewport);
226
- await setViewportSize(page, viewportSize);
227
- await stabilizeAndScreenshot(
228
- getScreenshotName(name, { viewportWidth: viewportSize.width })
229
- );
230
- }
231
- await setViewportSize(page, originalViewport);
232
- } else {
233
- await stabilizeAndScreenshot(name);
234
- }
235
- await afterAll();
236
- }
237
- export {
238
- argosScreenshot
239
- };