@prodix/cypress 0.1.0

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/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # @prodix/cypress
2
+
3
+ [Prodix](https://www.prodixsolutions.co) visual testing for Cypress — checks every snapshot across real device profiles and flags visual bugs automatically.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ npm install --save-dev @prodix/cypress
9
+ ```
10
+
11
+ Add your API key and project ID (from Settings → API Keys in the [Prodix dashboard](https://app.prodixsolutions.co)):
12
+
13
+ ```bash
14
+ PRODIX_API_KEY=pdx_your_api_key_here
15
+ PRODIX_PROJECT_ID=your_project_id
16
+ ```
17
+
18
+ Register the plugin in `cypress.config.ts`:
19
+
20
+ ```ts
21
+ import { defineConfig } from "cypress";
22
+ import { prodixPlugin } from "@prodix/cypress";
23
+
24
+ export default defineConfig({
25
+ e2e: {
26
+ setupNodeEvents(on, config) {
27
+ prodixPlugin(on, config);
28
+ },
29
+ },
30
+ });
31
+ ```
32
+
33
+ Load the command in `cypress/support/e2e.ts`:
34
+
35
+ ```ts
36
+ import "@prodix/cypress/support";
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ```ts
42
+ describe("Homepage", () => {
43
+ it("looks correct", () => {
44
+ cy.visit("/");
45
+ cy.prodixSnapshot("Homepage");
46
+ });
47
+ });
48
+ ```
49
+
50
+ Each snapshot is checked across every device profile in your Prodix project — desktop, tablet, mobile, and foldables. Results upload during `cypress run` and appear in your project's Runs tab.
@@ -0,0 +1,12 @@
1
+ import { type ProdixConfig } from "@prodix/sdk-core";
2
+ /**
3
+ * Register in cypress.config.ts:
4
+ *
5
+ * setupNodeEvents(on, config) {
6
+ * prodixPlugin(on, config);
7
+ * }
8
+ *
9
+ * Reads PRODIX_API_KEY and PRODIX_PROJECT_ID from the environment unless passed in.
10
+ */
11
+ export declare function prodixPlugin(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, options?: Partial<ProdixConfig>): void;
12
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,YAAY,EAAuB,MAAM,kBAAkB,CAAC;AAIxF;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,OAAO,CAAC,YAAY,EACxB,MAAM,EAAE,OAAO,CAAC,mBAAmB,EACnC,OAAO,GAAE,OAAO,CAAC,YAAY,CAAM,GAClC,IAAI,CAuCN"}
package/dist/plugin.js ADDED
@@ -0,0 +1,50 @@
1
+ /// <reference types="cypress" />
2
+ import { ProdixClient } from "@prodix/sdk-core";
3
+ const message = (err) => (err instanceof Error ? err.message : String(err));
4
+ /**
5
+ * Register in cypress.config.ts:
6
+ *
7
+ * setupNodeEvents(on, config) {
8
+ * prodixPlugin(on, config);
9
+ * }
10
+ *
11
+ * Reads PRODIX_API_KEY and PRODIX_PROJECT_ID from the environment unless passed in.
12
+ */
13
+ export function prodixPlugin(on, config, options = {}) {
14
+ const apiKey = options.apiKey ?? process.env["PRODIX_API_KEY"];
15
+ const projectId = options.projectId ?? process.env["PRODIX_PROJECT_ID"];
16
+ const disable = (reason) => {
17
+ console.warn(`[prodix] ${reason}, so snapshots are disabled.`);
18
+ on("task", { prodixSnapshot: () => null });
19
+ };
20
+ if (!apiKey || !projectId)
21
+ return disable("PRODIX_API_KEY or PRODIX_PROJECT_ID is not set");
22
+ // after:run only fires in `cypress run`, so an interactive session would leave runs unsubmitted.
23
+ if (!config.isTextTerminal)
24
+ return disable("Uploads only happen during `cypress run`");
25
+ const client = new ProdixClient({ ...options, apiKey, projectId });
26
+ on("task", {
27
+ async prodixSnapshot(screen) {
28
+ try {
29
+ await client.snapshot(screen);
30
+ }
31
+ catch (err) {
32
+ // A Prodix outage should never fail the customer's test suite.
33
+ console.warn(`[prodix] snapshot "${screen.name}" failed: ${message(err)}`);
34
+ }
35
+ return null;
36
+ },
37
+ });
38
+ on("after:run", async () => {
39
+ try {
40
+ const run = await client.completeRun();
41
+ if (run) {
42
+ console.log(`[prodix] Run submitted: https://app.prodixsolutions.co/projects/${client.projectId}/runs/${run.runId}`);
43
+ }
44
+ }
45
+ catch (err) {
46
+ console.warn(`[prodix] could not submit run: ${message(err)}`);
47
+ }
48
+ });
49
+ }
50
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,YAAY,EAA0C,MAAM,kBAAkB,CAAC;AAExF,MAAM,OAAO,GAAG,CAAC,GAAY,EAAE,EAAE,CAAC,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAErF;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAC1B,EAAwB,EACxB,MAAmC,EACnC,UAAiC,EAAE;IAEnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAExE,MAAM,OAAO,GAAG,CAAC,MAAc,EAAE,EAAE;QACjC,OAAO,CAAC,IAAI,CAAC,YAAY,MAAM,8BAA8B,CAAC,CAAC;QAC/D,EAAE,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC;IAEF,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS;QAAE,OAAO,OAAO,CAAC,gDAAgD,CAAC,CAAC;IAC5F,iGAAiG;IACjG,IAAI,CAAC,MAAM,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,0CAA0C,CAAC,CAAC;IAEvF,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAEnE,EAAE,CAAC,MAAM,EAAE;QACT,KAAK,CAAC,cAAc,CAAC,MAAsB;YACzC,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,+DAA+D;gBAC/D,OAAO,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,IAAI,aAAa,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC7E,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC,CAAC;IAEH,EAAE,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;QACzB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YACvC,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,CAAC,GAAG,CACT,mEAAmE,MAAM,CAAC,SAAS,SAAS,GAAG,CAAC,KAAK,EAAE,CACxG,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,kCAAkC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,10 @@
1
+ declare global {
2
+ namespace Cypress {
3
+ interface Chainable {
4
+ /** Captures the current page for Prodix AI visual testing across every device profile. */
5
+ prodixSnapshot(name: string): Chainable<void>;
6
+ }
7
+ }
8
+ }
9
+ export {};
10
+ //# sourceMappingURL=support.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"support.d.ts","sourceRoot":"","sources":["../src/support.ts"],"names":[],"mappings":"AAiBA,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,SAAS;YACjB,0FAA0F;YAC1F,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;SAC/C;KACF;CACF"}
@@ -0,0 +1,11 @@
1
+ /// <reference types="cypress" />
2
+ import { serializeDom } from "@prodix/sdk-core/serialize";
3
+ // Import once in cypress/support/e2e.ts: import "@prodix/cypress/support";
4
+ Cypress.Commands.add("prodixSnapshot", (name) => {
5
+ Cypress.log({ name: "prodixSnapshot", message: name });
6
+ cy.document({ log: false }).then((doc) => {
7
+ const win = doc.defaultView;
8
+ cy.task("prodixSnapshot", { name, html: serializeDom(doc), width: win?.innerWidth, height: win?.innerHeight }, { log: false });
9
+ });
10
+ });
11
+ //# sourceMappingURL=support.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"support.js","sourceRoot":"","sources":["../src/support.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,4EAA4E;AAE5E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,IAAY,EAAE,EAAE;IACtD,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QACvC,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,CAAC;QAC5B,EAAE,CAAC,IAAI,CACL,gBAAgB,EAChB,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,EACnF,EAAE,GAAG,EAAE,KAAK,EAAE,CACf,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@prodix/cypress",
3
+ "version": "0.1.0",
4
+ "description": "Prodix AI visual testing for Cypress",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/plugin.d.ts",
9
+ "import": "./dist/plugin.js"
10
+ },
11
+ "./support": {
12
+ "types": "./dist/support.d.ts",
13
+ "import": "./dist/support.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "dependencies": {
20
+ "@prodix/sdk-core": "0.1.0"
21
+ },
22
+ "peerDependencies": {
23
+ "cypress": ">=13"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^22.15.3",
27
+ "cypress": "^14.3.0",
28
+ "typescript": "^5.8.3"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc -p tsconfig.json",
35
+ "typecheck": "tsc -p tsconfig.json --noEmit"
36
+ }
37
+ }