@argos-ci/cypress 6.2.12 → 6.3.1

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.
@@ -0,0 +1,53 @@
1
+ import { StabilizationPluginOptions, ViewportOption } from "@argos-ci/browser";
2
+
3
+ //#region src/support.d.ts
4
+ type ArgosScreenshotOptions = Partial<Cypress.Loggable & Cypress.Timeoutable & Cypress.ScreenshotOptions> & {
5
+ /**
6
+ * Viewports to take screenshots of.
7
+ */
8
+ viewports?: ViewportOption[];
9
+ /**
10
+ * Custom CSS evaluated during the screenshot process.
11
+ */
12
+ argosCSS?: string;
13
+ /**
14
+ * Sensitivity threshold between 0 and 1.
15
+ * The higher the threshold, the less sensitive the diff will be.
16
+ * @default 0.5
17
+ */
18
+ threshold?: number;
19
+ /**
20
+ * Wait for the UI to stabilize before taking the screenshot.
21
+ * Set to `false` to disable stabilization.
22
+ * Pass an object to customize the stabilization.
23
+ * @default true
24
+ */
25
+ stabilize?: boolean | StabilizationPluginOptions;
26
+ /**
27
+ * Tag or array of tags to attach to the screenshot.
28
+ */
29
+ tag?: string | string[];
30
+ };
31
+ declare global {
32
+ namespace Cypress {
33
+ interface Chainable {
34
+ /**
35
+ * Stabilize the UI and takes a screenshot of the application under test.
36
+ *
37
+ * @see https://argos-ci.com/docs/cypress#api-overview
38
+ * @example
39
+ * cy.argosScreenshot("my-screenshot")
40
+ * cy.get(".post").argosScreenshot()
41
+ */
42
+ argosScreenshot: (
43
+ /**
44
+ * Name of the screenshot. Must be unique.
45
+ */
46
+ name: string,
47
+ /**
48
+ * Options for the screenshot.
49
+ */
50
+ options?: ArgosScreenshotOptions) => Chainable<null>;
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,148 @@
1
+ import "cypress-wait-until";
2
+ import { getGlobalScript, resolveViewport } from "@argos-ci/browser";
3
+ import { getMetadataPath, getScreenshotName, validateThreshold } from "@argos-ci/util/browser";
4
+ //#region package.json
5
+ var version = "6.3.0";
6
+ //#endregion
7
+ //#region src/shared.ts
8
+ /**
9
+ * Prefix to identify Argos screenshots.
10
+ */
11
+ const NAME_PREFIX = "argos/";
12
+ //#endregion
13
+ //#region src/support.ts
14
+ function injectArgos() {
15
+ cy.window({ log: false }).then((window) => {
16
+ if (typeof window.__ARGOS__ !== "undefined") return;
17
+ window.eval(getGlobalScript());
18
+ });
19
+ }
20
+ /**
21
+ * Get the stabilization context from the options.
22
+ */
23
+ function getStabilizationContext(options) {
24
+ const { argosCSS, viewports } = options;
25
+ return {
26
+ fullPage: !options.capture || options.capture === "fullPage",
27
+ argosCSS,
28
+ viewports,
29
+ options: options.stabilize
30
+ };
31
+ }
32
+ /**
33
+ * Run before taking all screenshots.
34
+ */
35
+ function beforeAll(options) {
36
+ const context = getStabilizationContext(options);
37
+ cy.window({ log: false }).then((window) => window.__ARGOS__.beforeAll(context));
38
+ return () => {
39
+ cy.window({ log: false }).then((window) => window.__ARGOS__.afterAll());
40
+ };
41
+ }
42
+ /**
43
+ * Run before taking each screenshot.
44
+ */
45
+ function beforeEach(options) {
46
+ const context = getStabilizationContext(options);
47
+ cy.window({ log: false }).then((window) => window.__ARGOS__.beforeEach(context));
48
+ return () => {
49
+ cy.window({ log: false }).then((window) => window.__ARGOS__.afterEach());
50
+ };
51
+ }
52
+ function getRetries(value) {
53
+ if (typeof value !== "number" || !Number.isFinite(value)) return 0;
54
+ const retries = Math.floor(value);
55
+ return retries < 0 ? 0 : retries;
56
+ }
57
+ /**
58
+ * Wait for the UI to be ready before taking the screenshot.
59
+ */
60
+ function waitForReadiness(options) {
61
+ const context = getStabilizationContext(options);
62
+ cy.waitUntil(() => cy.window({ log: false }).then((window) => {
63
+ if (window.__ARGOS__.waitFor(context)) return true;
64
+ window.__ARGOS__.getWaitFailureExplanations(context).forEach((reason) => {
65
+ cy.log(`[argos] stability: ${reason}`);
66
+ });
67
+ return false;
68
+ }));
69
+ }
70
+ Cypress.Commands.add("argosScreenshot", { prevSubject: [
71
+ "optional",
72
+ "element",
73
+ "window",
74
+ "document"
75
+ ] }, (subject, name, options = {}) => {
76
+ const { viewports, argosCSS: _argosCSS, tag, ...cypressOptions } = options;
77
+ if (!name) throw new Error("The `name` argument is required.");
78
+ Cypress.log({
79
+ name: "argosScreenshot",
80
+ displayName: `Argos Screenshot`,
81
+ message: name
82
+ });
83
+ injectArgos();
84
+ const afterAll = beforeAll(options);
85
+ function stabilizeAndScreenshot(name) {
86
+ waitForReadiness(options);
87
+ const afterEach = beforeEach(options);
88
+ waitForReadiness(options);
89
+ const ref = {};
90
+ cy.wrap(subject).screenshot(`${NAME_PREFIX}${name}`, {
91
+ blackout: ["[data-visual-test=\"blackout\"]"].concat(options.blackout || []),
92
+ onAfterScreenshot: (_$el, props) => {
93
+ ref.props = props;
94
+ },
95
+ ...cypressOptions
96
+ });
97
+ cy.window({ log: false }).then((window) => {
98
+ const mediaType = window.__ARGOS__.getMediaType();
99
+ const colorScheme = window.__ARGOS__.getColorScheme();
100
+ const metadata = {
101
+ url: window.location.href,
102
+ viewport: {
103
+ width: window.innerWidth,
104
+ height: window.innerHeight
105
+ },
106
+ colorScheme,
107
+ mediaType,
108
+ test: {
109
+ title: Cypress.currentTest.title,
110
+ titlePath: Cypress.currentTest.titlePath,
111
+ retry: Cypress.currentRetry,
112
+ retries: getRetries(cy.state("runnable")._retries)
113
+ },
114
+ browser: {
115
+ name: Cypress.browser.name,
116
+ version: Cypress.browser.version
117
+ },
118
+ automationLibrary: {
119
+ name: "cypress",
120
+ version: Cypress.version
121
+ },
122
+ sdk: {
123
+ name: "@argos-ci/cypress",
124
+ version
125
+ }
126
+ };
127
+ metadata.transient = {};
128
+ if (tag) metadata.tags = Array.isArray(tag) ? tag : [tag];
129
+ if (options.threshold !== void 0) {
130
+ validateThreshold(options.threshold);
131
+ metadata.transient.threshold = options.threshold;
132
+ }
133
+ cy.writeFile(getMetadataPath(ref.props.path), JSON.stringify(metadata));
134
+ });
135
+ afterEach();
136
+ }
137
+ if (viewports) {
138
+ for (const viewport of viewports) {
139
+ const viewportSize = resolveViewport(viewport);
140
+ cy.viewport(viewportSize.width, viewportSize.height);
141
+ stabilizeAndScreenshot(getScreenshotName(name, { viewportWidth: viewportSize.width }));
142
+ }
143
+ cy.viewport(Cypress.config("viewportWidth"), Cypress.config("viewportHeight"));
144
+ } else stabilizeAndScreenshot(name);
145
+ afterAll();
146
+ });
147
+ //#endregion
148
+ export {};
package/dist/task.cjs CHANGED
@@ -1,135 +1,88 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/task.ts
31
- var task_exports = {};
32
- __export(task_exports, {
33
- argosAfterRun: () => argosAfterRun,
34
- argosAfterScreenshot: () => argosAfterScreenshot,
35
- registerArgosTask: () => registerArgosTask
36
- });
37
- module.exports = __toCommonJS(task_exports);
38
- var import_core = require("@argos-ci/core");
39
- var import_node_path = require("path");
40
-
41
- // src/shared.ts
42
- var NAME_PREFIX = "argos/";
43
-
44
- // src/task.ts
45
- var import_promises = require("fs/promises");
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _argos_ci_core = require("@argos-ci/core");
3
+ let node_path = require("node:path");
4
+ let node_fs_promises = require("node:fs/promises");
5
+ //#endregion
6
+ //#region src/task.ts
46
7
  function checkIsCypressFailedResult(results) {
47
- return "status" in results && results.status === "failed";
8
+ return "status" in results && results.status === "failed";
48
9
  }
49
- var screenshotsDirectoryPromise = void 0;
10
+ let screenshotsDirectoryPromise = void 0;
11
+ /**
12
+ * Get the path to the directory where screenshots will be stored.
13
+ */
50
14
  async function getScreenshotsDirectory() {
51
- const { createTemporaryDirectory } = await import("@argos-ci/util");
52
- if (!screenshotsDirectoryPromise) {
53
- screenshotsDirectoryPromise = createTemporaryDirectory();
54
- }
55
- return screenshotsDirectoryPromise;
15
+ const { createTemporaryDirectory } = await import("@argos-ci/util");
16
+ if (!screenshotsDirectoryPromise) screenshotsDirectoryPromise = createTemporaryDirectory();
17
+ return screenshotsDirectoryPromise;
56
18
  }
19
+ /**
20
+ * Create a directory if it does not exist.
21
+ */
57
22
  async function createDirectory(directory) {
58
- const { createDirectory: createDirectory2 } = await import("@argos-ci/util");
59
- await createDirectory2(directory);
23
+ const { createDirectory } = await import("@argos-ci/util");
24
+ await createDirectory(directory);
60
25
  }
61
26
  function getArgosConfigFromOptions(options) {
62
- return {
63
- uploadToArgos: options?.uploadToArgos ?? true
64
- };
27
+ return { uploadToArgos: options?.uploadToArgos ?? true };
65
28
  }
29
+ /**
30
+ * Cypress "after:screenshot" event handler.
31
+ * - Move screenshots to Argos directory
32
+ */
66
33
  async function argosAfterScreenshot(config, details, options) {
67
- const { uploadToArgos } = getArgosConfigFromOptions(options);
68
- if (!uploadToArgos) {
69
- return { path: details.path };
70
- }
71
- const argosScreenshotsDir = await getScreenshotsDirectory();
72
- if (details.name?.startsWith(NAME_PREFIX)) {
73
- const newPath2 = (0, import_node_path.join)(
74
- argosScreenshotsDir,
75
- details.name.slice(NAME_PREFIX.length) + (0, import_node_path.extname)(details.path)
76
- );
77
- await createDirectory((0, import_node_path.dirname)(newPath2));
78
- await (0, import_promises.copyFile)(details.path, newPath2);
79
- return { path: newPath2 };
80
- }
81
- const { screenshotsFolder } = config;
82
- if (!screenshotsFolder) {
83
- throw new Error(
84
- "Cypress screenshotsFolder is not defined. Please set it in your cypress.config.js"
85
- );
86
- }
87
- if (!details.path.startsWith(screenshotsFolder)) {
88
- throw new Error(
89
- `Cypress screenshot path ${details.path} does not start with the configured screenshotsFolder ${screenshotsFolder}. Please check your cypress.config.js.`
90
- );
91
- }
92
- const relativePath = details.path.slice(
93
- screenshotsFolder.length + (screenshotsFolder.endsWith("/") ? 0 : 1)
94
- );
95
- const newPath = (0, import_node_path.join)(argosScreenshotsDir, relativePath);
96
- await createDirectory((0, import_node_path.dirname)(newPath));
97
- await (0, import_promises.copyFile)(details.path, newPath);
98
- return { path: (0, import_node_path.join)(argosScreenshotsDir, relativePath) };
34
+ const { uploadToArgos } = getArgosConfigFromOptions(options);
35
+ if (!uploadToArgos) return { path: details.path };
36
+ const argosScreenshotsDir = await getScreenshotsDirectory();
37
+ if (details.name?.startsWith("argos/")) {
38
+ const newPath = (0, node_path.join)(argosScreenshotsDir, details.name.slice(6) + (0, node_path.extname)(details.path));
39
+ await createDirectory((0, node_path.dirname)(newPath));
40
+ await (0, node_fs_promises.copyFile)(details.path, newPath);
41
+ return { path: newPath };
42
+ }
43
+ const { screenshotsFolder } = config;
44
+ if (!screenshotsFolder) throw new Error("Cypress screenshotsFolder is not defined. Please set it in your cypress.config.js");
45
+ if (!details.path.startsWith(screenshotsFolder)) throw new Error(`Cypress screenshot path ${details.path} does not start with the configured screenshotsFolder ${screenshotsFolder}. Please check your cypress.config.js.`);
46
+ const relativePath = details.path.slice(screenshotsFolder.length + (screenshotsFolder.endsWith("/") ? 0 : 1));
47
+ const newPath = (0, node_path.join)(argosScreenshotsDir, relativePath);
48
+ await createDirectory((0, node_path.dirname)(newPath));
49
+ await (0, node_fs_promises.copyFile)(details.path, newPath);
50
+ return { path: (0, node_path.join)(argosScreenshotsDir, relativePath) };
99
51
  }
52
+ /**
53
+ * Cypress "after:run" event handler.
54
+ * - Upload screenshots to Argos
55
+ */
100
56
  async function argosAfterRun(_config, results, options) {
101
- const { uploadToArgos } = getArgosConfigFromOptions(options);
102
- if (!uploadToArgos) {
103
- return;
104
- }
105
- const argosScreenshotsDir = await getScreenshotsDirectory();
106
- const res = await (0, import_core.upload)({
107
- ...options,
108
- files: ["**/*.png"],
109
- root: argosScreenshotsDir,
110
- metadata: {
111
- testReport: checkIsCypressFailedResult(results) ? { status: "failed" } : {
112
- status: "passed",
113
- stats: {
114
- startTime: results.startedTestsAt,
115
- duration: results.totalDuration
116
- }
117
- }
118
- }
119
- });
120
- console.log(`\u2705 Argos build created: ${res.build.url}`);
57
+ const { uploadToArgos } = getArgosConfigFromOptions(options);
58
+ if (!uploadToArgos) return;
59
+ const argosScreenshotsDir = await getScreenshotsDirectory();
60
+ const res = await (0, _argos_ci_core.upload)({
61
+ ...options,
62
+ files: ["**/*.png"],
63
+ root: argosScreenshotsDir,
64
+ metadata: { testReport: checkIsCypressFailedResult(results) ? { status: "failed" } : {
65
+ status: "passed",
66
+ stats: {
67
+ startTime: results.startedTestsAt,
68
+ duration: results.totalDuration
69
+ }
70
+ } }
71
+ });
72
+ console.log(`✅ Argos build created: ${res.build.url}`);
121
73
  }
74
+ /**
75
+ * Register the Argos tasks for Cypress.
76
+ */
122
77
  function registerArgosTask(on, config, options) {
123
- on("after:screenshot", (details) => {
124
- return argosAfterScreenshot(config, details, options);
125
- });
126
- on("after:run", async (results) => {
127
- return argosAfterRun(config, results, options);
128
- });
78
+ on("after:screenshot", (details) => {
79
+ return argosAfterScreenshot(config, details, options);
80
+ });
81
+ on("after:run", async (results) => {
82
+ return argosAfterRun(config, results, options);
83
+ });
129
84
  }
130
- // Annotate the CommonJS export names for ESM import in node:
131
- 0 && (module.exports = {
132
- argosAfterRun,
133
- argosAfterScreenshot,
134
- registerArgosTask
135
- });
85
+ //#endregion
86
+ exports.argosAfterRun = argosAfterRun;
87
+ exports.argosAfterScreenshot = argosAfterScreenshot;
88
+ exports.registerArgosTask = registerArgosTask;
package/dist/task.d.cts CHANGED
@@ -1,18 +1,19 @@
1
- import { UploadParameters } from '@argos-ci/core';
1
+ import { UploadParameters } from "@argos-ci/core";
2
2
 
3
+ //#region src/task.d.ts
3
4
  type RegisterArgosTaskOptions = Omit<UploadParameters, "files" | "root" | "metadata"> & {
4
- /**
5
- * Upload the report to Argos.
6
- * @default true
7
- */
8
- uploadToArgos?: boolean;
5
+ /**
6
+ * Upload the report to Argos.
7
+ * @default true
8
+ */
9
+ uploadToArgos?: boolean;
9
10
  };
10
11
  /**
11
12
  * Cypress "after:screenshot" event handler.
12
13
  * - Move screenshots to Argos directory
13
14
  */
14
15
  declare function argosAfterScreenshot(config: Cypress.PluginConfigOptions, details: Cypress.ScreenshotDetails, options?: RegisterArgosTaskOptions): Promise<{
15
- path: string;
16
+ path: any;
16
17
  }>;
17
18
  /**
18
19
  * Cypress "after:run" event handler.
@@ -23,5 +24,5 @@ declare function argosAfterRun(_config: Cypress.PluginConfigOptions, results: Cy
23
24
  * Register the Argos tasks for Cypress.
24
25
  */
25
26
  declare function registerArgosTask(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, options?: RegisterArgosTaskOptions): void;
26
-
27
- export { type RegisterArgosTaskOptions, argosAfterRun, argosAfterScreenshot, registerArgosTask };
27
+ //#endregion
28
+ export { RegisterArgosTaskOptions, argosAfterRun, argosAfterScreenshot, registerArgosTask };
@@ -1,18 +1,19 @@
1
- import { UploadParameters } from '@argos-ci/core';
1
+ import { UploadParameters } from "@argos-ci/core";
2
2
 
3
+ //#region src/task.d.ts
3
4
  type RegisterArgosTaskOptions = Omit<UploadParameters, "files" | "root" | "metadata"> & {
4
- /**
5
- * Upload the report to Argos.
6
- * @default true
7
- */
8
- uploadToArgos?: boolean;
5
+ /**
6
+ * Upload the report to Argos.
7
+ * @default true
8
+ */
9
+ uploadToArgos?: boolean;
9
10
  };
10
11
  /**
11
12
  * Cypress "after:screenshot" event handler.
12
13
  * - Move screenshots to Argos directory
13
14
  */
14
15
  declare function argosAfterScreenshot(config: Cypress.PluginConfigOptions, details: Cypress.ScreenshotDetails, options?: RegisterArgosTaskOptions): Promise<{
15
- path: string;
16
+ path: any;
16
17
  }>;
17
18
  /**
18
19
  * Cypress "after:run" event handler.
@@ -23,5 +24,5 @@ declare function argosAfterRun(_config: Cypress.PluginConfigOptions, results: Cy
23
24
  * Register the Argos tasks for Cypress.
24
25
  */
25
26
  declare function registerArgosTask(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, options?: RegisterArgosTaskOptions): void;
26
-
27
- export { type RegisterArgosTaskOptions, argosAfterRun, argosAfterScreenshot, registerArgosTask };
27
+ //#endregion
28
+ export { RegisterArgosTaskOptions, argosAfterRun, argosAfterScreenshot, registerArgosTask };
package/dist/task.mjs ADDED
@@ -0,0 +1,85 @@
1
+ import { upload } from "@argos-ci/core";
2
+ import { dirname, extname, join } from "node:path";
3
+ import { copyFile } from "node:fs/promises";
4
+ //#endregion
5
+ //#region src/task.ts
6
+ function checkIsCypressFailedResult(results) {
7
+ return "status" in results && results.status === "failed";
8
+ }
9
+ let screenshotsDirectoryPromise = void 0;
10
+ /**
11
+ * Get the path to the directory where screenshots will be stored.
12
+ */
13
+ async function getScreenshotsDirectory() {
14
+ const { createTemporaryDirectory } = await import("@argos-ci/util");
15
+ if (!screenshotsDirectoryPromise) screenshotsDirectoryPromise = createTemporaryDirectory();
16
+ return screenshotsDirectoryPromise;
17
+ }
18
+ /**
19
+ * Create a directory if it does not exist.
20
+ */
21
+ async function createDirectory(directory) {
22
+ const { createDirectory } = await import("@argos-ci/util");
23
+ await createDirectory(directory);
24
+ }
25
+ function getArgosConfigFromOptions(options) {
26
+ return { uploadToArgos: options?.uploadToArgos ?? true };
27
+ }
28
+ /**
29
+ * Cypress "after:screenshot" event handler.
30
+ * - Move screenshots to Argos directory
31
+ */
32
+ async function argosAfterScreenshot(config, details, options) {
33
+ const { uploadToArgos } = getArgosConfigFromOptions(options);
34
+ if (!uploadToArgos) return { path: details.path };
35
+ const argosScreenshotsDir = await getScreenshotsDirectory();
36
+ if (details.name?.startsWith("argos/")) {
37
+ const newPath = join(argosScreenshotsDir, details.name.slice(6) + extname(details.path));
38
+ await createDirectory(dirname(newPath));
39
+ await copyFile(details.path, newPath);
40
+ return { path: newPath };
41
+ }
42
+ const { screenshotsFolder } = config;
43
+ if (!screenshotsFolder) throw new Error("Cypress screenshotsFolder is not defined. Please set it in your cypress.config.js");
44
+ if (!details.path.startsWith(screenshotsFolder)) throw new Error(`Cypress screenshot path ${details.path} does not start with the configured screenshotsFolder ${screenshotsFolder}. Please check your cypress.config.js.`);
45
+ const relativePath = details.path.slice(screenshotsFolder.length + (screenshotsFolder.endsWith("/") ? 0 : 1));
46
+ const newPath = join(argosScreenshotsDir, relativePath);
47
+ await createDirectory(dirname(newPath));
48
+ await copyFile(details.path, newPath);
49
+ return { path: join(argosScreenshotsDir, relativePath) };
50
+ }
51
+ /**
52
+ * Cypress "after:run" event handler.
53
+ * - Upload screenshots to Argos
54
+ */
55
+ async function argosAfterRun(_config, results, options) {
56
+ const { uploadToArgos } = getArgosConfigFromOptions(options);
57
+ if (!uploadToArgos) return;
58
+ const argosScreenshotsDir = await getScreenshotsDirectory();
59
+ const res = await upload({
60
+ ...options,
61
+ files: ["**/*.png"],
62
+ root: argosScreenshotsDir,
63
+ metadata: { testReport: checkIsCypressFailedResult(results) ? { status: "failed" } : {
64
+ status: "passed",
65
+ stats: {
66
+ startTime: results.startedTestsAt,
67
+ duration: results.totalDuration
68
+ }
69
+ } }
70
+ });
71
+ console.log(`✅ Argos build created: ${res.build.url}`);
72
+ }
73
+ /**
74
+ * Register the Argos tasks for Cypress.
75
+ */
76
+ function registerArgosTask(on, config, options) {
77
+ on("after:screenshot", (details) => {
78
+ return argosAfterScreenshot(config, details, options);
79
+ });
80
+ on("after:run", async (results) => {
81
+ return argosAfterRun(config, results, options);
82
+ });
83
+ }
84
+ //#endregion
85
+ export { argosAfterRun, argosAfterScreenshot, registerArgosTask };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@argos-ci/cypress",
3
3
  "description": "Cypress SDK for visual testing with Argos.",
4
- "version": "6.2.12",
4
+ "version": "6.3.1",
5
5
  "author": "Smooth Code",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -26,15 +26,14 @@
26
26
  "access": "public"
27
27
  },
28
28
  "type": "module",
29
- "types": "./dist/index.d.ts",
30
29
  "exports": {
31
30
  "./support": {
32
- "types": "./dist/support.d.ts",
33
- "import": "./dist/support.js",
34
- "default": "./dist/support.js"
31
+ "types": "./dist/support.d.mts",
32
+ "import": "./dist/support.mjs",
33
+ "default": "./dist/support.mjs"
35
34
  },
36
35
  "./task": {
37
- "types": "./dist/task.d.ts",
36
+ "types": "./dist/task.d.mts",
38
37
  "import": "./dist/task.js",
39
38
  "require": "./dist/task.cjs",
40
39
  "default": "./dist/task.cjs"
@@ -45,9 +44,9 @@
45
44
  "node": ">=20.0.0"
46
45
  },
47
46
  "dependencies": {
48
- "@argos-ci/browser": "5.1.2",
49
- "@argos-ci/core": "5.1.1",
50
- "@argos-ci/util": "3.2.0",
47
+ "@argos-ci/browser": "5.1.3",
48
+ "@argos-ci/core": "5.1.3",
49
+ "@argos-ci/util": "3.4.0",
51
50
  "cypress-wait-until": "^3.0.2"
52
51
  },
53
52
  "peerDependencies": {
@@ -55,11 +54,11 @@
55
54
  },
56
55
  "devDependencies": {
57
56
  "@types/node": "catalog:",
58
- "cypress": "^15.9.0",
59
- "eslint-plugin-cypress": "^5.2.1"
57
+ "cypress": "^15.13.0",
58
+ "eslint-plugin-cypress": "^6.2.1"
60
59
  },
61
60
  "scripts": {
62
- "build": "tsup",
61
+ "build": "tsdown",
63
62
  "test-e2e": "pnpm exec cypress run",
64
63
  "build-e2e": "cypress install",
65
64
  "e2e": "UPLOAD_TO_ARGOS=true pnpm run test-e2e",
@@ -67,5 +66,5 @@
67
66
  "check-format": "prettier --check --ignore-unknown --ignore-path=../../.gitignore --ignore-path=../../.prettierignore .",
68
67
  "lint": "eslint ."
69
68
  },
70
- "gitHead": "52b2c59dc89e972ea9951dc7a94bf8f7d7922e4a"
69
+ "gitHead": "b49d186d5eb6e1338982a4cd5c3cb29e6cb0b7af"
71
70
  }
package/dist/support.d.ts DELETED
@@ -1,48 +0,0 @@
1
- import { ViewportOption, StabilizationPluginOptions } from '@argos-ci/browser';
2
-
3
- type ArgosScreenshotOptions = Partial<Cypress.Loggable & Cypress.Timeoutable & Cypress.ScreenshotOptions> & {
4
- /**
5
- * Viewports to take screenshots of.
6
- */
7
- viewports?: ViewportOption[];
8
- /**
9
- * Custom CSS evaluated during the screenshot process.
10
- */
11
- argosCSS?: string;
12
- /**
13
- * Sensitivity threshold between 0 and 1.
14
- * The higher the threshold, the less sensitive the diff will be.
15
- * @default 0.5
16
- */
17
- threshold?: number;
18
- /**
19
- * Wait for the UI to stabilize before taking the screenshot.
20
- * Set to `false` to disable stabilization.
21
- * Pass an object to customize the stabilization.
22
- * @default true
23
- */
24
- stabilize?: boolean | StabilizationPluginOptions;
25
- };
26
- declare global {
27
- namespace Cypress {
28
- interface Chainable {
29
- /**
30
- * Stabilize the UI and takes a screenshot of the application under test.
31
- *
32
- * @see https://argos-ci.com/docs/cypress#api-overview
33
- * @example
34
- * cy.argosScreenshot("my-screenshot")
35
- * cy.get(".post").argosScreenshot()
36
- */
37
- argosScreenshot: (
38
- /**
39
- * Name of the screenshot. Must be unique.
40
- */
41
- name: string,
42
- /**
43
- * Options for the screenshot.
44
- */
45
- options?: ArgosScreenshotOptions) => Chainable<null>;
46
- }
47
- }
48
- }
package/dist/support.js DELETED
@@ -1,171 +0,0 @@
1
- // src/support.ts
2
- import "cypress-wait-until";
3
- import {
4
- resolveViewport
5
- } from "@argos-ci/browser";
6
- import { getGlobalScript } from "@argos-ci/browser";
7
- import {
8
- getMetadataPath,
9
- getScreenshotName,
10
- validateThreshold
11
- } from "@argos-ci/util/browser";
12
-
13
- // package.json
14
- var version = "6.2.11";
15
-
16
- // src/shared.ts
17
- var NAME_PREFIX = "argos/";
18
-
19
- // src/support.ts
20
- function injectArgos() {
21
- cy.window({ log: false }).then((window) => {
22
- if (typeof window.__ARGOS__ !== "undefined") {
23
- return;
24
- }
25
- window.eval(getGlobalScript());
26
- });
27
- }
28
- function getStabilizationContext(options) {
29
- const { argosCSS, viewports } = options;
30
- const fullPage = !options.capture || options.capture === "fullPage";
31
- return {
32
- fullPage,
33
- argosCSS,
34
- viewports,
35
- options: options.stabilize
36
- };
37
- }
38
- function beforeAll(options) {
39
- const context = getStabilizationContext(options);
40
- cy.window({ log: false }).then(
41
- (window) => window.__ARGOS__.beforeAll(context)
42
- );
43
- return () => {
44
- cy.window({ log: false }).then(
45
- (window) => window.__ARGOS__.afterAll()
46
- );
47
- };
48
- }
49
- function beforeEach(options) {
50
- const context = getStabilizationContext(options);
51
- cy.window({ log: false }).then(
52
- (window) => window.__ARGOS__.beforeEach(context)
53
- );
54
- return () => {
55
- cy.window({ log: false }).then(
56
- (window) => window.__ARGOS__.afterEach()
57
- );
58
- };
59
- }
60
- function getRetries(value) {
61
- if (typeof value !== "number" || !Number.isFinite(value)) {
62
- return 0;
63
- }
64
- const retries = Math.floor(value);
65
- return retries < 0 ? 0 : retries;
66
- }
67
- function waitForReadiness(options) {
68
- const context = getStabilizationContext(options);
69
- cy.waitUntil(
70
- () => cy.window({ log: false }).then((window) => {
71
- const isStable = window.__ARGOS__.waitFor(
72
- context
73
- );
74
- if (isStable) {
75
- return true;
76
- }
77
- const failureReasons = window.__ARGOS__.getWaitFailureExplanations(context);
78
- failureReasons.forEach((reason) => {
79
- cy.log(`[argos] stability: ${reason}`);
80
- });
81
- return false;
82
- })
83
- );
84
- }
85
- Cypress.Commands.add(
86
- "argosScreenshot",
87
- { prevSubject: ["optional", "element", "window", "document"] },
88
- (subject, name, options = {}) => {
89
- const { viewports, argosCSS: _argosCSS, ...cypressOptions } = options;
90
- if (!name) {
91
- throw new Error("The `name` argument is required.");
92
- }
93
- Cypress.log({
94
- name: "argosScreenshot",
95
- displayName: `Argos Screenshot`,
96
- message: name
97
- });
98
- injectArgos();
99
- const afterAll = beforeAll(options);
100
- function stabilizeAndScreenshot(name2) {
101
- waitForReadiness(options);
102
- const afterEach = beforeEach(options);
103
- waitForReadiness(options);
104
- const ref = {};
105
- cy.wrap(subject).screenshot(`${NAME_PREFIX}${name2}`, {
106
- blackout: ['[data-visual-test="blackout"]'].concat(
107
- options.blackout || []
108
- ),
109
- onAfterScreenshot: (_$el, props) => {
110
- ref.props = props;
111
- },
112
- ...cypressOptions
113
- });
114
- cy.window({ log: false }).then((window) => {
115
- const mediaType = window.__ARGOS__.getMediaType();
116
- const colorScheme = window.__ARGOS__.getColorScheme();
117
- const metadata = {
118
- url: window.location.href,
119
- viewport: {
120
- width: window.innerWidth,
121
- height: window.innerHeight
122
- },
123
- colorScheme,
124
- mediaType,
125
- test: {
126
- title: Cypress.currentTest.title,
127
- titlePath: Cypress.currentTest.titlePath,
128
- retry: Cypress.currentRetry,
129
- // @ts-expect-error - private property
130
- retries: getRetries(cy.state("runnable")._retries)
131
- },
132
- browser: {
133
- name: Cypress.browser.name,
134
- version: Cypress.browser.version
135
- },
136
- automationLibrary: {
137
- name: "cypress",
138
- version: Cypress.version
139
- },
140
- sdk: {
141
- name: "@argos-ci/cypress",
142
- version
143
- }
144
- };
145
- metadata.transient = {};
146
- if (options.threshold !== void 0) {
147
- validateThreshold(options.threshold);
148
- metadata.transient.threshold = options.threshold;
149
- }
150
- cy.writeFile(getMetadataPath(ref.props.path), JSON.stringify(metadata));
151
- });
152
- afterEach();
153
- }
154
- if (viewports) {
155
- for (const viewport of viewports) {
156
- const viewportSize = resolveViewport(viewport);
157
- cy.viewport(viewportSize.width, viewportSize.height);
158
- stabilizeAndScreenshot(
159
- getScreenshotName(name, { viewportWidth: viewportSize.width })
160
- );
161
- }
162
- cy.viewport(
163
- Cypress.config("viewportWidth"),
164
- Cypress.config("viewportHeight")
165
- );
166
- } else {
167
- stabilizeAndScreenshot(name);
168
- }
169
- afterAll();
170
- }
171
- );
package/dist/task.js DELETED
@@ -1,98 +0,0 @@
1
- // src/task.ts
2
- import { upload } from "@argos-ci/core";
3
- import { extname, join, dirname } from "path";
4
-
5
- // src/shared.ts
6
- var NAME_PREFIX = "argos/";
7
-
8
- // src/task.ts
9
- import { copyFile } from "fs/promises";
10
- function checkIsCypressFailedResult(results) {
11
- return "status" in results && results.status === "failed";
12
- }
13
- var screenshotsDirectoryPromise = void 0;
14
- async function getScreenshotsDirectory() {
15
- const { createTemporaryDirectory } = await import("@argos-ci/util");
16
- if (!screenshotsDirectoryPromise) {
17
- screenshotsDirectoryPromise = createTemporaryDirectory();
18
- }
19
- return screenshotsDirectoryPromise;
20
- }
21
- async function createDirectory(directory) {
22
- const { createDirectory: createDirectory2 } = await import("@argos-ci/util");
23
- await createDirectory2(directory);
24
- }
25
- function getArgosConfigFromOptions(options) {
26
- return {
27
- uploadToArgos: options?.uploadToArgos ?? true
28
- };
29
- }
30
- async function argosAfterScreenshot(config, details, options) {
31
- const { uploadToArgos } = getArgosConfigFromOptions(options);
32
- if (!uploadToArgos) {
33
- return { path: details.path };
34
- }
35
- const argosScreenshotsDir = await getScreenshotsDirectory();
36
- if (details.name?.startsWith(NAME_PREFIX)) {
37
- const newPath2 = join(
38
- argosScreenshotsDir,
39
- details.name.slice(NAME_PREFIX.length) + extname(details.path)
40
- );
41
- await createDirectory(dirname(newPath2));
42
- await copyFile(details.path, newPath2);
43
- return { path: newPath2 };
44
- }
45
- const { screenshotsFolder } = config;
46
- if (!screenshotsFolder) {
47
- throw new Error(
48
- "Cypress screenshotsFolder is not defined. Please set it in your cypress.config.js"
49
- );
50
- }
51
- if (!details.path.startsWith(screenshotsFolder)) {
52
- throw new Error(
53
- `Cypress screenshot path ${details.path} does not start with the configured screenshotsFolder ${screenshotsFolder}. Please check your cypress.config.js.`
54
- );
55
- }
56
- const relativePath = details.path.slice(
57
- screenshotsFolder.length + (screenshotsFolder.endsWith("/") ? 0 : 1)
58
- );
59
- const newPath = join(argosScreenshotsDir, relativePath);
60
- await createDirectory(dirname(newPath));
61
- await copyFile(details.path, newPath);
62
- return { path: join(argosScreenshotsDir, relativePath) };
63
- }
64
- async function argosAfterRun(_config, results, options) {
65
- const { uploadToArgos } = getArgosConfigFromOptions(options);
66
- if (!uploadToArgos) {
67
- return;
68
- }
69
- const argosScreenshotsDir = await getScreenshotsDirectory();
70
- const res = await upload({
71
- ...options,
72
- files: ["**/*.png"],
73
- root: argosScreenshotsDir,
74
- metadata: {
75
- testReport: checkIsCypressFailedResult(results) ? { status: "failed" } : {
76
- status: "passed",
77
- stats: {
78
- startTime: results.startedTestsAt,
79
- duration: results.totalDuration
80
- }
81
- }
82
- }
83
- });
84
- console.log(`\u2705 Argos build created: ${res.build.url}`);
85
- }
86
- function registerArgosTask(on, config, options) {
87
- on("after:screenshot", (details) => {
88
- return argosAfterScreenshot(config, details, options);
89
- });
90
- on("after:run", async (results) => {
91
- return argosAfterRun(config, results, options);
92
- });
93
- }
94
- export {
95
- argosAfterRun,
96
- argosAfterScreenshot,
97
- registerArgosTask
98
- };