From b61e5c05522a8b0dd9bd98082e84e9783de7444d Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 25 Jan 2024 17:30:16 +0100 Subject: [PATCH 01/19] chore: remove most code and work based on fixtures --- README.md | 6 +- cypress.config.js | 3 +- cypress/e2e/1.cy.js | 100 +++++++++++++++++---------- src/utils/functions/register.js | 2 +- src/utils/snapshots/compareValues.js | 30 ++++---- src/utils/snapshots/snapshot.js | 84 ++++++++++------------ 6 files changed, 120 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 1b33e11..6803bde 100644 --- a/README.md +++ b/README.md @@ -62,9 +62,9 @@ describe("my tests", () => { In the above case, you can find the stored snapshot in their own files, mentioned above them ```jsonc -// cypress/snapshots/my-tests-works-foo.json +// cypress/fixtures/snapshots/my-tests-works-foo.json { "foo": 42 } -// cypress/snapshots/my-tests-works-bar.json +// cypress/fixtures/snapshots/my-tests-works-bar.json { "bar": 101 } ``` @@ -82,7 +82,7 @@ You can control snapshot comparison and behavior through a few options. ```js cy.get(...).snapshot({ snapshotName: 'Snapshot Name', // Overwrite the generated Snapshot name - snapshotPath: 'cypress/not_snapshots', // Overwrite where the Snapshot should be stored + snapshotPath: 'cypress/fixtures/not_snapshots', // Overwrite where the Snapshot should be stored json: false // convert DOM elements into JSON }) // when storing in the snapshot file diff --git a/cypress.config.js b/cypress.config.js index 7c57e27..890cf53 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -3,7 +3,8 @@ const { functions } = require("./src/utils"); module.exports = defineConfig({ snapshot: { - snapshotPath: "cypress/snapshots/", + // snapshotPath: "cypress/snapshots/", + SNAPSHOT_UPDATE: true }, e2e: { setupNodeEvents(on, config) { diff --git a/cypress/e2e/1.cy.js b/cypress/e2e/1.cy.js index d1dc177..c7f0a09 100644 --- a/cypress/e2e/1.cy.js +++ b/cypress/e2e/1.cy.js @@ -3,45 +3,73 @@ describe("@datashard/snapshot", () => { context("simple types", () => { it("works with objects", () => { - cy.fixture("File2").snapshot({ - snapshotPath: "cypress/snapshots", - snapshotName: "Objects", - }); + cy.wrap({ + "foo": "bar", + "Fizzy Drink": "Pop" + }).snapshot( + // "Filename", { + // snapshotPath: "asdasd" + // } + ); + + // cypress/fixtures/@datashard-snapshot/simple-types/works-with-objects/asdjskadhasj.json }); - it("works with numbers", () => { - cy.wrap(42).snapshot({ - snapshotPath: "cypress/snapshots", - snapshotName: "Numbers", - }); - }); + // it("works with numbers", () => { + // cy.wrap(42).snapshot({ + // snapshotPath: "cypress/fixtures/snapshots", + // snapshotName: "Numbers", + // }); + // }); - it("works with strings", () => { - cy.wrap("foo-bar").snapshot({ - snapshotPath: "cypress/snapshots", - snapshotName: "Strings", - }); - }); + // it("works with strings", () => { + // cy.wrap("foo-bar").snapshot({ + // snapshotPath: "cypress/fixtures/snapshots", + // snapshotName: "Strings", + // }); + // }); - it( - "works with arrays", - { - env: { - SNAPSHOT_UPDATE: true, - }, - }, - () => { - cy.wrap([1, 2, 3, 4]).snapshot({ - snapshotPath: "cypress/snapshots", - snapshotName: "Arrays", - }); - } - ); - it('works with more "complicated" Objects', () => { - cy.fixture("Complex").snapshot({ - snapshotPath: 'cypress/snapshots', - snapshotName: "Complex" - }) - }) + // it( + // "works with arrays", + // { + // env: { + // SNAPSHOT_UPDATE: true, + // }, + // }, + // () => { + // cy.wrap([1, 2, 3, 4]).snapshot({ + // snapshotPath: "cypress/fixtures/snapshots", + // snapshotName: "Arrays", + // }); + // } + // ); + // it('works with more "complicated" Objects', () => { + // cy.fixture("Complex").snapshot({ + // snapshotPath: 'cypress/fixtures/snapshots', + // snapshotName: "Complex" + // }) + // }) + // it.only("works based on fixtures", () => { + // cy + // .wrap({ + // "jsonapi": { + // "version": "2.0" + // }, + // "included": [ + // { + // "type": "users", + // "id": "2", + // "attributes": { + // "name": "Test" + // } + // } + // ] + // }) + // .snapshot({ + // snapshotFixture: "generated", + // // snapshotPath: "cypress/fixtures/snapshots", + // // snapshotName: "generated", + // }); + // }); }); }); diff --git a/src/utils/functions/register.js b/src/utils/functions/register.js index 8ad3504..e1d8d0a 100644 --- a/src/utils/functions/register.js +++ b/src/utils/functions/register.js @@ -7,7 +7,7 @@ module.exports = () => { lazy(is.fn(global.after), "Missing global after function"); lazy(is.object(global.Cypress), "Missing Cypress object"); - Cypress.Commands.add("snapshot", { prevSubject: true }, snapshot); + Cypress.Commands.add("snapshot", { prevSubject: "optional" }, snapshot); return snapshot; }; diff --git a/src/utils/snapshots/compareValues.js b/src/utils/snapshots/compareValues.js index bd05fef..510ef71 100644 --- a/src/utils/snapshots/compareValues.js +++ b/src/utils/snapshots/compareValues.js @@ -1,5 +1,3 @@ -// const { expect: chaiExpect } = require("chai"); - const isNestedData = (expected, value) => { return ( expected && value && typeof expected == `object` && typeof value == `object` @@ -12,11 +10,11 @@ const checkDataState = (expected, value) => { if (expected === value) { result = `| ✅ "${value}",`; } else if (expected == undefined) { - result = `| ➖ "➖╺ ${expected}|${value}",`; + result = `| ➖ "➖╺ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; } else if (value == undefined) { - result = `| ➕ "➕┿ ${expected}|${value}",`; + result = `| ➕ "➕┿ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; } else { - result = `| ⭕ "⭕╳ ${expected}|${value}",`; + result = `| ⭕ "⭕╳ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; } return result; @@ -31,9 +29,11 @@ const checkDataState = (expected, value) => { function parseTextToJSON(text) { const lines = - text - .replace(/\| [✅➖➕⭕]/g, "").trim() - .replace(/(.*?),\s*(\}|])/g, "$1$2"); + // JSON.stringify( + text + .replace(/\| [✅➖➕⭕]/g, "").trim() + .replace(/(.*?),\s*(\}|])/g, "$1$2") + // ) return lines; // return JSON.stringify(lines, null, 2); } @@ -44,8 +44,10 @@ function containsDiffChars(str) { } const compare = (expected, value) => { + if(value === undefined){ + throw new Error("Please provide Data to compare against.") + } let compareResult = ""; - let compareSuccess = true; if (isNestedData(expected, value)) { if (Array.isArray(expected)) { @@ -62,7 +64,6 @@ const compare = (expected, value) => { dataX.forEach(function (item, index) { const resultset = compare(item, dataY[index]); - compareSuccess = resultset.success; compareResult += resultset.result; }); compareResult += `],`; @@ -79,17 +80,16 @@ const compare = (expected, value) => { Object.keys(dataX).forEach((key) => { const resultset = compare(dataX[key], dataY[key]); - - compareSuccess = resultset.success; compareResult += `"${key}": ${resultset.result}`; }); - compareResult += `}`; + compareResult += `},`; } } else { - compareSuccess = false; compareResult = checkDataState(expected, value); } - let result = parseTextToJSON(compareResult); + let result = parseTextToJSON(compareResult).replace(/(},)$/g, `}`); + console.log("compareResult",compareResult) + console.log("result", result.replace(/(},)$/g, `}`)) // let result = compareResult; try { diff --git a/src/utils/snapshots/snapshot.js b/src/utils/snapshots/snapshot.js index 8f9f3b6..925a1dd 100644 --- a/src/utils/snapshots/snapshot.js +++ b/src/utils/snapshots/snapshot.js @@ -11,34 +11,36 @@ const pickSerializer = (asJson, value) => { return identity; }; -const store_snapshot = (props = { value, name, path, raiser }) => { - const expectedPath = path.join( - props.path || - Cypress.config("snapshot").snapshotPath || - "cypress/snapshots", - `${props.name.join("_").replace(/ /gi, "-").replace(/\//gi, "-")}.json` - ); - cy.task("readFileMaybe", expectedPath).then((exist) => { - if (exist && !Cypress.env().SNAPSHOT_UPDATE) { - props.raiser({ value: props.value, expected: JSON.parse(exist) }); - } else { - cy.writeFile(expectedPath, JSON.stringify(props.value, null, 2)); - } - }); +const store_snapshot = (props = { value, name, raiser }) => { + if (!Cypress.env().SNAPSHOT_UPDATE) { + cy.fixture(props.name).then(content => props.raiser({ value: props.value, expected: content })) + } else { + cy.writeFile(`${props.name}.json`, JSON.stringify(props.value.null, 2)) + } + + + // cy.fixture(props.name) + // .then(exist => { + // cy.log('fixture 2') + // if (exist && !Cypress.env().SNAPSHOT_UPDATE) { + // cy.log(`fixture exists and doesn't update`) + // props.raiser({ value: props.value, expected: exist, type: "fixture" }); + // } else { + // cy.log(`fixture exists and updates`) + // cy.writeFile(expectedPath, JSON.stringify(props.value, null, 2)); + // } + // }) }; -const set_snapshot = ( - { snapshotName, snapshotPath, serialized, value } -) => { +const set_snapshot = ({ snapshotName, serialized, value }) => { let devToolsLog = { $el: serialized }; - if (Cypress.dom.isJquery(value)) { devToolsLog.$el = value; } const options = { name: "snapshot", - message: Cypress._.last(snapshotName), + message: snapshotName, consoleProps: () => devToolsLog, }; @@ -46,7 +48,6 @@ const set_snapshot = ( const raiser = ({ value, expected }) => { const result = compareValues({ expected, value }); - if (!Cypress.env().SNAPSHOT_UPDATE && !result.success) { devToolsLog = { ...devToolsLog, @@ -55,19 +56,11 @@ const set_snapshot = ( value, }; - // ╺ - // ┿ - // ╳ - throw new Error( - `Snapshot Difference found.\nPlease Update the Snapshot\n\n${JSON.stringify( - JSON.parse(result.result), - null, - 2 - ) - .replaceAll(" ", " ") - .replaceAll(/[╺┿╳]/g, "")}` - // `Snapshot Difference found.\nPlease Update the Snapshot\n\n${result.result}` + `Snapshot Difference found.\nPlease Update the Snapshot\n + + + ${JSON.stringify(result.result.replaceAll(/[╺┿╳]/g, ""), null, 2)}` ); } }; @@ -76,35 +69,28 @@ const set_snapshot = ( store_snapshot({ value, name: snapshotName, - path: snapshotPath, raiser, }); }; -const get_snapshot_name = (test, custom_name) => { - const names = test.titlePath; +const get_snapshot_name = (asFolder, stepName) => { + const names = Cypress.currentTest.titlePath; + const sep = ">>datashard.work<<" + if (stepName) names.push(stepName) - const index = custom_name; - names.push(String(index)); - - if (custom_name) return [custom_name]; - return names; + if (asFolder) return names.join(sep).replace(/ /gi, "-").replace(/\//gi, "-").replaceAll(sep, '/') + else return names.join('__').replaceAll(" ", "-").replaceAll("/", "-") }; -module.exports = (value, step, options) => { - if (typeof step === "object") options = step; +module.exports = (value, stepName, options = { json: true, asFolder: false }) => { if (typeof value !== "object" || Array.isArray(value)) value = { data: value }; - const serializer = pickSerializer(options.json, value); const serialized = serializer(value); - set_snapshot({ - snapshotName: get_snapshot_name( - Cypress.currentTest, - options.snapshotName || step - ), - snapshotPath: options.snapshotPath, + snapshotName: path.join( + options.snapshotPath || Cypress.config('snapshot').snapshotPath || 'snapshots', + `/${get_snapshot_name(options.asFolder, stepName)}`), serialized, value, }); From 5db74ebcb6352af3ad148cfe64a2ba939718ee54 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 29 Jan 2024 19:08:06 +0100 Subject: [PATCH 02/19] mass changes --- .vscode/settings.json | 2 + cypress.config.js | 7 +- cypress/e2e/1.cy.js | 141 +++++------ cypress/fixtures/File.json | 4 - cypress/fixtures/File2.json | 4 - .../works-based-on-fixtures.json | 14 ++ .../works-with-more-complicated-Objects.json} | 0 .../simple-types/works-based-on-fixtures.json | 14 ++ .../simple-types/works-with-arrays.json} | 0 .../works-with-more-complicated-Objects.json} | 9 +- .../simple-types/works-with-numbers.json} | 0 .../simple-types/works-with-objects.json} | 0 .../simple-types/works-with-strings.json} | 0 cypress/snapshots/Fixture-File.json | 1 - cypress/snapshots/Random-Fixture-File.json | 4 - cypress/support/commands.js | 2 +- src/index.js | 5 +- src/{utils/functions => }/register.js | 26 +- src/{utils/snapshots => }/snapshot.js | 209 ++++++++-------- src/utils/{snapshots => }/compareValues.js | 230 +++++++++--------- src/utils/functions/addTasks.js | 5 - src/utils/index.js | 28 --- src/utils/tasks/readFileMaybe.js | 9 - 23 files changed, 356 insertions(+), 358 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 cypress/fixtures/File.json delete mode 100644 cypress/fixtures/File2.json create mode 100644 cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-based-on-fixtures.json rename cypress/fixtures/{Complex.json => snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json} (100%) create mode 100644 cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-based-on-fixtures.json rename cypress/{snapshots/Arrays.json => fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json} (100%) rename cypress/{snapshots/Complex.json => fixtures/snapshots/datashard-snapshot/simple-types/works-with-more-complicated-Objects.json} (58%) rename cypress/{snapshots/Numbers.json => fixtures/snapshots/datashard-snapshot/simple-types/works-with-numbers.json} (100%) rename cypress/{snapshots/Objects.json => fixtures/snapshots/datashard-snapshot/simple-types/works-with-objects.json} (100%) rename cypress/{snapshots/Strings.json => fixtures/snapshots/datashard-snapshot/simple-types/works-with-strings.json} (100%) delete mode 100644 cypress/snapshots/Fixture-File.json delete mode 100644 cypress/snapshots/Random-Fixture-File.json rename src/{utils/functions => }/register.js (85%) rename src/{utils/snapshots => }/snapshot.js (55%) rename src/utils/{snapshots => }/compareValues.js (96%) delete mode 100644 src/utils/functions/addTasks.js delete mode 100644 src/utils/index.js delete mode 100644 src/utils/tasks/readFileMaybe.js diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/cypress.config.js b/cypress.config.js index 890cf53..94f9cd0 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -1,14 +1,15 @@ const { defineConfig } = require("cypress"); -const { functions } = require("./src/utils"); module.exports = defineConfig({ snapshot: { // snapshotPath: "cypress/snapshots/", - SNAPSHOT_UPDATE: true + // SNAPSHOT_UPDATE: true, + useFolders: true, }, + e2e: { setupNodeEvents(on, config) { - functions.tasks(on, config); + // implement node event listeners here }, }, }); diff --git a/cypress/e2e/1.cy.js b/cypress/e2e/1.cy.js index c7f0a09..65e8b3c 100644 --- a/cypress/e2e/1.cy.js +++ b/cypress/e2e/1.cy.js @@ -1,75 +1,78 @@ /* eslint-env mocha */ /* global cy */ -describe("@datashard/snapshot", () => { - context("simple types", () => { - it("works with objects", () => { - cy.wrap({ - "foo": "bar", - "Fizzy Drink": "Pop" - }).snapshot( - // "Filename", { - // snapshotPath: "asdasd" - // } +describe("datashard/snapshot", () => { + context("simple types" + // , { env: { SNAPSHOT_UPDATE: true } } + , () => { + it("works with objects", () => { + cy.wrap({ + "foo": "bar", + "Fizzy Drink": "Pop" + }).snapshot(); + }); + + it("works with numbers", () => { + cy.wrap(42).snapshot({ + snapshotPath: "cypress/fixtures/snapshots", + snapshotName: "Numbers", + }); + }); + + it("works with strings", () => { + cy.wrap("foo-bar").snapshot({ + snapshotPath: "cypress/fixtures/snapshots", + snapshotName: "Strings", + }); + }); + + it( + "works with arrays", + { + env: { + SNAPSHOT_UPDATE: true, + }, + }, + () => { + cy.wrap([1, 2, 3, 4]).snapshot({ + snapshotPath: "cypress/fixtures/snapshots", + snapshotName: "Arrays", + }); + } ); - // cypress/fixtures/@datashard-snapshot/simple-types/works-with-objects/asdjskadhasj.json }); - - // it("works with numbers", () => { - // cy.wrap(42).snapshot({ - // snapshotPath: "cypress/fixtures/snapshots", - // snapshotName: "Numbers", - // }); - // }); - - // it("works with strings", () => { - // cy.wrap("foo-bar").snapshot({ - // snapshotPath: "cypress/fixtures/snapshots", - // snapshotName: "Strings", - // }); - // }); - - // it( - // "works with arrays", - // { - // env: { - // SNAPSHOT_UPDATE: true, - // }, - // }, - // () => { - // cy.wrap([1, 2, 3, 4]).snapshot({ - // snapshotPath: "cypress/fixtures/snapshots", - // snapshotName: "Arrays", - // }); - // } - // ); - // it('works with more "complicated" Objects', () => { - // cy.fixture("Complex").snapshot({ - // snapshotPath: 'cypress/fixtures/snapshots', - // snapshotName: "Complex" - // }) - // }) - // it.only("works based on fixtures", () => { - // cy - // .wrap({ - // "jsonapi": { - // "version": "2.0" - // }, - // "included": [ - // { - // "type": "users", - // "id": "2", - // "attributes": { - // "name": "Test" - // } - // } - // ] - // }) - // .snapshot({ - // snapshotFixture: "generated", - // // snapshotPath: "cypress/fixtures/snapshots", - // // snapshotName: "generated", - // }); - // }); - }); + context("complex types" + // , { env: { SNAPSHOT_UPDATE: true } } + , () => { + it('works with more "complicated" Objects', () => { + cy.wrap({ + "status": 200, + "response": { + "array": [0, 1, 2, "Three"], + "object": { + "with": "more details" + } + } + } + ).snapshot() + }) + it("works based on fixtures", () => { + cy + .wrap({ + "jsonapi": { + "version": "2.0" + }, + "included": [ + { + "type": "users", + "id": "2", + "attributes": { + "name": "Test" + } + } + ] + }) + .snapshot(); + }); + }) }); diff --git a/cypress/fixtures/File.json b/cypress/fixtures/File.json deleted file mode 100644 index fe41954..0000000 --- a/cypress/fixtures/File.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "foo": "bar", - "Fizzy Drink": "Soda" -} diff --git a/cypress/fixtures/File2.json b/cypress/fixtures/File2.json deleted file mode 100644 index effe26b..0000000 --- a/cypress/fixtures/File2.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "foo": "bar", - "Fizzy Drink": "Pop" -} diff --git a/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-based-on-fixtures.json b/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-based-on-fixtures.json new file mode 100644 index 0000000..ac6239a --- /dev/null +++ b/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-based-on-fixtures.json @@ -0,0 +1,14 @@ +{ + "jsonapi": { + "version": "2.0" + }, + "included": [ + { + "type": "users", + "id": "2", + "attributes": { + "name": "Test" + } + } + ] +} \ No newline at end of file diff --git a/cypress/fixtures/Complex.json b/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json similarity index 100% rename from cypress/fixtures/Complex.json rename to cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json diff --git a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-based-on-fixtures.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-based-on-fixtures.json new file mode 100644 index 0000000..ac6239a --- /dev/null +++ b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-based-on-fixtures.json @@ -0,0 +1,14 @@ +{ + "jsonapi": { + "version": "2.0" + }, + "included": [ + { + "type": "users", + "id": "2", + "attributes": { + "name": "Test" + } + } + ] +} \ No newline at end of file diff --git a/cypress/snapshots/Arrays.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json similarity index 100% rename from cypress/snapshots/Arrays.json rename to cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json diff --git a/cypress/snapshots/Complex.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-more-complicated-Objects.json similarity index 58% rename from cypress/snapshots/Complex.json rename to cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-more-complicated-Objects.json index 25a8f3b..1de1100 100644 --- a/cypress/snapshots/Complex.json +++ b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-more-complicated-Objects.json @@ -1,9 +1,14 @@ { "status": 200, "response": { - "array": [0, 1, 2, "Three"], + "array": [ + 0, + 1, + 2, + "Three" + ], "object": { "with": "more details" } } -} +} \ No newline at end of file diff --git a/cypress/snapshots/Numbers.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-numbers.json similarity index 100% rename from cypress/snapshots/Numbers.json rename to cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-numbers.json diff --git a/cypress/snapshots/Objects.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-objects.json similarity index 100% rename from cypress/snapshots/Objects.json rename to cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-objects.json diff --git a/cypress/snapshots/Strings.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-strings.json similarity index 100% rename from cypress/snapshots/Strings.json rename to cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-strings.json diff --git a/cypress/snapshots/Fixture-File.json b/cypress/snapshots/Fixture-File.json deleted file mode 100644 index 86ac8e3..0000000 --- a/cypress/snapshots/Fixture-File.json +++ /dev/null @@ -1 +0,0 @@ -{"foo":"bar","Fizzy Drink":"Soda"} \ No newline at end of file diff --git a/cypress/snapshots/Random-Fixture-File.json b/cypress/snapshots/Random-Fixture-File.json deleted file mode 100644 index cf78053..0000000 --- a/cypress/snapshots/Random-Fixture-File.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "foo": "bar", - "Fizzy Drink": "Soda" -} \ No newline at end of file diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 56daf1d..4bea380 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -1,2 +1,2 @@ // register .snapshot() command -require('../..').register() +require('../../src/index').register() diff --git a/src/index.js b/src/index.js index c1cc876..763a201 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,6 @@ // global cy, Cypress -const { functions } = require("./utils/index"); +const register = require("./register"); module.exports = { - register: functions.register, - tasks: functions.tasks, + register }; diff --git a/src/utils/functions/register.js b/src/register.js similarity index 85% rename from src/utils/functions/register.js rename to src/register.js index e1d8d0a..e1b1fa0 100644 --- a/src/utils/functions/register.js +++ b/src/register.js @@ -1,13 +1,13 @@ -const lazy = require("lazy-ass"); -const is = require("check-more-types"); -const snapshot = require("../snapshots/snapshot"); - -module.exports = () => { - lazy(is.fn(global.before), "Missing global before function"); - lazy(is.fn(global.after), "Missing global after function"); - lazy(is.object(global.Cypress), "Missing Cypress object"); - - Cypress.Commands.add("snapshot", { prevSubject: "optional" }, snapshot); - - return snapshot; -}; +const lazy = require("lazy-ass"); +const is = require("check-more-types"); +const snapshot = require("./snapshot"); + +module.exports = () => { + lazy(is.fn(global.before), "Missing global before function"); + lazy(is.fn(global.after), "Missing global after function"); + lazy(is.object(global.Cypress), "Missing Cypress object"); + + Cypress.Commands.add("snapshot", { prevSubject: "optional" }, snapshot); + + return snapshot; +}; diff --git a/src/utils/snapshots/snapshot.js b/src/snapshot.js similarity index 55% rename from src/utils/snapshots/snapshot.js rename to src/snapshot.js index 925a1dd..6679381 100644 --- a/src/utils/snapshots/snapshot.js +++ b/src/snapshot.js @@ -1,97 +1,112 @@ -const serializeDomElement = require("../serializers/serializeDomElement"); -const serializeToHTML = require("../serializers/serializeToHTML"); -const compareValues = require("./compareValues"); -const path = require("path"); -const identity = (x) => x; - -const pickSerializer = (asJson, value) => { - if (Cypress.dom.isJquery(value)) { - return asJson ? serializeDomElement : serializeToHTML; - } - return identity; -}; - -const store_snapshot = (props = { value, name, raiser }) => { - if (!Cypress.env().SNAPSHOT_UPDATE) { - cy.fixture(props.name).then(content => props.raiser({ value: props.value, expected: content })) - } else { - cy.writeFile(`${props.name}.json`, JSON.stringify(props.value.null, 2)) - } - - - // cy.fixture(props.name) - // .then(exist => { - // cy.log('fixture 2') - // if (exist && !Cypress.env().SNAPSHOT_UPDATE) { - // cy.log(`fixture exists and doesn't update`) - // props.raiser({ value: props.value, expected: exist, type: "fixture" }); - // } else { - // cy.log(`fixture exists and updates`) - // cy.writeFile(expectedPath, JSON.stringify(props.value, null, 2)); - // } - // }) -}; - -const set_snapshot = ({ snapshotName, serialized, value }) => { - let devToolsLog = { $el: serialized }; - if (Cypress.dom.isJquery(value)) { - devToolsLog.$el = value; - } - - const options = { - name: "snapshot", - message: snapshotName, - consoleProps: () => devToolsLog, - }; - - if (value) options.$el = value; - - const raiser = ({ value, expected }) => { - const result = compareValues({ expected, value }); - if (!Cypress.env().SNAPSHOT_UPDATE && !result.success) { - devToolsLog = { - ...devToolsLog, - message: result, - expected, - value, - }; - - throw new Error( - `Snapshot Difference found.\nPlease Update the Snapshot\n - - - ${JSON.stringify(result.result.replaceAll(/[╺┿╳]/g, ""), null, 2)}` - ); - } - }; - Cypress.log(options); - - store_snapshot({ - value, - name: snapshotName, - raiser, - }); -}; - -const get_snapshot_name = (asFolder, stepName) => { - const names = Cypress.currentTest.titlePath; - const sep = ">>datashard.work<<" - if (stepName) names.push(stepName) - - if (asFolder) return names.join(sep).replace(/ /gi, "-").replace(/\//gi, "-").replaceAll(sep, '/') - else return names.join('__').replaceAll(" ", "-").replaceAll("/", "-") -}; - -module.exports = (value, stepName, options = { json: true, asFolder: false }) => { - if (typeof value !== "object" || Array.isArray(value)) - value = { data: value }; - const serializer = pickSerializer(options.json, value); - const serialized = serializer(value); - set_snapshot({ - snapshotName: path.join( - options.snapshotPath || Cypress.config('snapshot').snapshotPath || 'snapshots', - `/${get_snapshot_name(options.asFolder, stepName)}`), - serialized, - value, - }); -}; +const serializeDomElement = require("./utils/serializers/serializeDomElement"); +const serializeToHTML = require("./utils/serializers/serializeToHTML"); +const compareValues = require("./utils/compareValues"); +const path = require("path"); +const identity = (x) => x; + +const pickSerializer = (asJson, value) => { + if (Cypress.dom.isJquery(value)) { + return asJson ? serializeDomElement : serializeToHTML; + } + return identity; +}; + +const store_snapshot = (props = { value, name, raiser }) => { + if (Cypress.env().SNAPSHOT_UPDATE || Cypress.config('snapshot').SNAPSHOT_UPDATE) { + cy.log(props.name) + console.log(props.name) + cy.writeFile(`${props.name}.json`, JSON.stringify(props.value, null, 2)) + } else { + // TODO: Figure out how to replace the fixture folder name if people move it + const fixtureName = props.name.replace("cypress/fixtures", "") + cy.fixture(fixtureName).then(content => props.raiser({ value: props.value, expected: content })) + } +}; + +const set_snapshot = ({ snapshotName, serialized, value }) => { + let devToolsLog = { $el: serialized }; + if (Cypress.dom.isJquery(value)) { + devToolsLog.$el = value; + } + + const options = { + name: "snapshot", + message: snapshotName, + consoleProps: () => devToolsLog, + }; + + if (value) options.$el = value; + + const raiser = ({ value, expected }) => { + const result = compareValues({ expected, value }); + if (!Cypress.env().SNAPSHOT_UPDATE && !result.success) { + devToolsLog = { + ...devToolsLog, + message: result, + expected, + value, + }; + + throw new Error( + `Snapshot Difference found.\nPlease Update the Snapshot\n + + + ${JSON.stringify(result.result.replaceAll(/[╺┿╳]/g, ""), null, 2)}` + ); + } + }; + Cypress.log(options); + + store_snapshot({ + value, + name: snapshotName, + raiser, + }); +}; + +function replaceCharacters(str, asFolder, sep) { + if (asFolder) { + if (!sep) throw new Error("Separator not Passed.") + return str + .replace(/ /gi, '-') + .replace(/\//gi, "-") + .replaceAll('"', '') + .replaceAll(sep, '/') + } else { + return str + .replaceAll(' ', '-') + .replaceAll('/', '-') + .replaceAll('"', '') + } +} + +const get_snapshot_name = (asFolder, stepName) => { + const names = Cypress.currentTest.titlePath; + const sep = ">>datashard.work<<" + + + if (stepName && typeof stepName !== 'object') { + names.push(stepName) + } + + + if (asFolder) return replaceCharacters(names.join(sep), true, sep) + else return replaceCharacters(names.join('__'), false) +}; + +module.exports = (value, stepName, options = { json: true }) => { + if (typeof stepName === 'object') options = { ...options, ...stepName } + if (typeof value !== "object" || Array.isArray(value)) + value = { data: value }; + const serializer = pickSerializer(options.json, value); + const serialized = serializer(value); + options.asFolder = Cypress.config('snapshot').useFolders || false + + set_snapshot({ + snapshotName: path.join( + options.snapshotPath || Cypress.config('snapshot').snapshotPath || 'cypress/fixtures/snapshots', + `/${get_snapshot_name(options.asFolder, stepName)}`), + serialized, + value, + }); +}; diff --git a/src/utils/snapshots/compareValues.js b/src/utils/compareValues.js similarity index 96% rename from src/utils/snapshots/compareValues.js rename to src/utils/compareValues.js index 510ef71..e9b0cf5 100644 --- a/src/utils/snapshots/compareValues.js +++ b/src/utils/compareValues.js @@ -1,115 +1,115 @@ -const isNestedData = (expected, value) => { - return ( - expected && value && typeof expected == `object` && typeof value == `object` - ); -}; - -const checkDataState = (expected, value) => { - let result; - - if (expected === value) { - result = `| ✅ "${value}",`; - } else if (expected == undefined) { - result = `| ➖ "➖╺ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; - } else if (value == undefined) { - result = `| ➕ "➕┿ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; - } else { - result = `| ⭕ "⭕╳ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; - } - - return result; -}; - - -/** - * - * @param {string} text - * @returns {string} - */ - -function parseTextToJSON(text) { - const lines = - // JSON.stringify( - text - .replace(/\| [✅➖➕⭕]/g, "").trim() - .replace(/(.*?),\s*(\}|])/g, "$1$2") - // ) - return lines; - // return JSON.stringify(lines, null, 2); -} - -function containsDiffChars(str) { - const emojis = ["╺", "┿", "╳"]; - return emojis.some(emoji => str.includes(emoji)); -} - -const compare = (expected, value) => { - if(value === undefined){ - throw new Error("Please provide Data to compare against.") - } - let compareResult = ""; - - if (isNestedData(expected, value)) { - if (Array.isArray(expected)) { - compareResult += `[`; - let dataX, dataY; - - if (expected.length >= value.length) { - dataX = expected; - dataY = value; - } else { - dataX = value; - dataY = expected; - } - - dataX.forEach(function (item, index) { - const resultset = compare(item, dataY[index]); - compareResult += resultset.result; - }); - compareResult += `],`; - } else { - let dataX, dataY; - compareResult += `{`; - if (Object.keys(expected).length >= Object.keys(value).length) { - dataX = expected; - dataY = value; - } else { - dataX = value; - dataY = expected; - } - - Object.keys(dataX).forEach((key) => { - const resultset = compare(dataX[key], dataY[key]); - compareResult += `"${key}": ${resultset.result}`; - }); - compareResult += `},`; - } - } else { - compareResult = checkDataState(expected, value); - } - let result = parseTextToJSON(compareResult).replace(/(},)$/g, `}`); - console.log("compareResult",compareResult) - console.log("result", result.replace(/(},)$/g, `}`)) - // let result = compareResult; - - try { - return { - success: !containsDiffChars(result), - result, - }; - } catch (error) { - return { success: false, result }; - } -}; - -/** - * - * @param {{ - * expected: { [k:string]: any}, - * value: {[k:string]:any} - * }} values - */ - -module.exports = function compareValues(values) { - return compare(values.expected, values.value); -}; +const isNestedData = (expected, value) => { + return ( + expected && value && typeof expected == `object` && typeof value == `object` + ); +}; + +const checkDataState = (expected, value) => { + let result; + + if (expected === value) { + result = `| ✅ "${value}",`; + } else if (expected == undefined) { + result = `| ➖ "➖╺ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; + } else if (value == undefined) { + result = `| ➕ "➕┿ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; + } else { + result = `| ⭕ "⭕╳ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; + } + + return result; +}; + + +/** + * + * @param {string} text + * @returns {string} + */ + +function parseTextToJSON(text) { + const lines = + // JSON.stringify( + text + .replace(/\| [✅➖➕⭕]/g, "").trim() + .replace(/(.*?),\s*(\}|])/g, "$1$2") + // ) + return lines; + // return JSON.stringify(lines, null, 2); +} + +function containsDiffChars(str) { + const emojis = ["╺", "┿", "╳"]; + return emojis.some(emoji => str.includes(emoji)); +} + +const compare = (expected, value) => { + if(value === undefined){ + throw new Error("Please provide Data to compare against.") + } + let compareResult = ""; + + if (isNestedData(expected, value)) { + if (Array.isArray(expected)) { + compareResult += `[`; + let dataX, dataY; + + if (expected.length >= value.length) { + dataX = expected; + dataY = value; + } else { + dataX = value; + dataY = expected; + } + + dataX.forEach(function (item, index) { + const resultset = compare(item, dataY[index]); + compareResult += resultset.result; + }); + compareResult += `],`; + } else { + let dataX, dataY; + compareResult += `{`; + if (Object.keys(expected).length >= Object.keys(value).length) { + dataX = expected; + dataY = value; + } else { + dataX = value; + dataY = expected; + } + + Object.keys(dataX).forEach((key) => { + const resultset = compare(dataX[key], dataY[key]); + compareResult += `"${key}": ${resultset.result}`; + }); + compareResult += `},`; + } + } else { + compareResult = checkDataState(expected, value); + } + let result = parseTextToJSON(compareResult).replace(/(},)$/g, `}`); + console.log("compareResult",compareResult) + console.log("result", result.replace(/(},)$/g, `}`)) + // let result = compareResult; + + try { + return { + success: !containsDiffChars(result), + result, + }; + } catch (error) { + return { success: false, result }; + } +}; + +/** + * + * @param {{ + * expected: { [k:string]: any}, + * value: {[k:string]:any} + * }} values + */ + +module.exports = function compareValues(values) { + return compare(values.expected, values.value); +}; diff --git a/src/utils/functions/addTasks.js b/src/utils/functions/addTasks.js deleted file mode 100644 index 4d01f92..0000000 --- a/src/utils/functions/addTasks.js +++ /dev/null @@ -1,5 +0,0 @@ -const readFileMaybe = require("../tasks/readFileMaybe"); - -module.exports = (on, config) => { - on("task", { readFileMaybe }); -}; diff --git a/src/utils/index.js b/src/utils/index.js deleted file mode 100644 index ae0b254..0000000 --- a/src/utils/index.js +++ /dev/null @@ -1,28 +0,0 @@ -const serializeToHTML = require("./serializers/serializeToHTML"); -const serializeDomElement = require("./serializers/serializeDomElement"); -const compareValues = require("./snapshots/compareValues"); -const readFileMaybe = require("./tasks/readFileMaybe"); -const identity = (x) => x; -const publicProps = (name) => !name.startsWith("__"); -const countSnapshots = (snapshots) => - Object.keys(snapshots).filter(publicProps).length; - -module.exports = { - serializers: { - serializeDomElement, - serializeToHTML, - identity, - countSnapshots, - }, - snapshots: { - compareValues, - }, - - functions: { - register: require("./functions/register"), - tasks: require("./functions/addTasks"), - }, - tasks: { - readFileMaybe, - }, -}; diff --git a/src/utils/tasks/readFileMaybe.js b/src/utils/tasks/readFileMaybe.js deleted file mode 100644 index 192c432..0000000 --- a/src/utils/tasks/readFileMaybe.js +++ /dev/null @@ -1,9 +0,0 @@ -const fs = require("fs"); - -module.exports = (filename) => { - if (fs.existsSync(filename)) { - return fs.readFileSync(filename, "utf8"); - } - - return false; -}; From 9a41366c82275b923d6914a6c0a318d983bb75e9 Mon Sep 17 00:00:00 2001 From: Joshua Date: Wed, 31 Jan 2024 09:22:07 +0100 Subject: [PATCH 03/19] rename Env Variables --- cypress/e2e/1.cy.js | 4 ++-- src/snapshot.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cypress/e2e/1.cy.js b/cypress/e2e/1.cy.js index 65e8b3c..a86374e 100644 --- a/cypress/e2e/1.cy.js +++ b/cypress/e2e/1.cy.js @@ -2,7 +2,7 @@ /* global cy */ describe("datashard/snapshot", () => { context("simple types" - // , { env: { SNAPSHOT_UPDATE: true } } + // , { env: { updateSnapshots: true } } , () => { it("works with objects", () => { cy.wrap({ @@ -29,7 +29,7 @@ describe("datashard/snapshot", () => { "works with arrays", { env: { - SNAPSHOT_UPDATE: true, + updateSnapshots: true, }, }, () => { diff --git a/src/snapshot.js b/src/snapshot.js index 6679381..e9f1997 100644 --- a/src/snapshot.js +++ b/src/snapshot.js @@ -12,7 +12,7 @@ const pickSerializer = (asJson, value) => { }; const store_snapshot = (props = { value, name, raiser }) => { - if (Cypress.env().SNAPSHOT_UPDATE || Cypress.config('snapshot').SNAPSHOT_UPDATE) { + if (Cypress.env().updateSnapshots || Cypress.config('snapshot').updateSnapshots) { cy.log(props.name) console.log(props.name) cy.writeFile(`${props.name}.json`, JSON.stringify(props.value, null, 2)) @@ -39,7 +39,7 @@ const set_snapshot = ({ snapshotName, serialized, value }) => { const raiser = ({ value, expected }) => { const result = compareValues({ expected, value }); - if (!Cypress.env().SNAPSHOT_UPDATE && !result.success) { + if ((!Cypress.env().updateSnapshots || !Cypress.config('snapshot').updateSnapshots) && !result.success) { devToolsLog = { ...devToolsLog, message: result, From 7c6f997bc06ac5ac16b5be61023dd2068ba38f51 Mon Sep 17 00:00:00 2001 From: Joshua Date: Wed, 31 Jan 2024 09:22:25 +0100 Subject: [PATCH 04/19] redo config --- cypress.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress.config.js b/cypress.config.js index 94f9cd0..9acf04d 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -1,9 +1,9 @@ const { defineConfig } = require("cypress"); module.exports = defineConfig({ + snapshot: { - // snapshotPath: "cypress/snapshots/", - // SNAPSHOT_UPDATE: true, + updateSnapshots: true, useFolders: true, }, From cb39e029c3ec691160f8743438bfb23b4658c586 Mon Sep 17 00:00:00 2001 From: Joshua Date: Wed, 31 Jan 2024 19:49:52 +0100 Subject: [PATCH 05/19] redo a surprising amount of things --- .github/assets/config.png | Bin 56521 -> 78132 bytes LICENSE | 22 +++ README.md | 171 ++++-------------- cypress.config.js | 4 +- cypress/e2e/1.cy.js | 10 +- cypress/e2e/2.cy.js | 10 +- .../Random-Context/Random-It/Arrays.json | 7 + .../Random-Context/Random-It/Numbers.json | 3 + .../Random-Context/Random-It/Strings.json | 3 + .../works-with-more-complicated-Objects.json | 9 +- .../simple-types/works-based-on-fixtures.json | 14 -- .../works-with-more-complicated-Objects.json | 14 -- package.json | 2 +- src/snapshot.js | 20 +- src/utils/compareValues.js | 55 ++---- 15 files changed, 115 insertions(+), 229 deletions(-) create mode 100644 LICENSE create mode 100644 cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Arrays.json create mode 100644 cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Numbers.json create mode 100644 cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Strings.json delete mode 100644 cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-based-on-fixtures.json delete mode 100644 cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-more-complicated-Objects.json diff --git a/.github/assets/config.png b/.github/assets/config.png index ede80f539a074b254d5baf6fbf871b25c147c419..ae39b13429697232d87a6cd67a8156a3a7461616 100644 GIT binary patch literal 78132 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 Nc_T2Vg{RJ4{~uj6LRkO+ literal 56521 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

{Yv#zEsK2PCd|za&R9Y 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 Adds value / object / DOM element snapshot testing support to Cypress test runner +> Adds support for Value, Object, and Dom Element Snapshot Testing to Cypress -

-Changes between @datashard/snapshot and @cypress/snapshot -
-They're mostly the same, as this is a fork of the Latter, though it's not a drop-in replacement. - -Unlike `@cypress/snapshot`, this saves snapshots in their own files with a sensible default and strives to have ongoing Support for future Cypress Versions - -
- - +## Breaking Changes +> [!WARNING] +The `readFileMaybe` task was required in previous Versions, this has been changed so this Module now uses the `cy.fixture` Command to get the contents of existing files. This means that this module will only be able to write new tests if `updateSnapshots` (previously `SNAPSHOT_UPDATE`) is set to true through Environment Variables or through the Cypress config. +\ +This also means, that previous tests will likely be broken, *please make sure that your tests pass before updating to the latest version of this module* ## Install - -Requires [Node](https://nodejs.org/en/) version 10 or above. +Requires Node 16 or above ```sh -npm install --save-dev @datashard/snapshot +npm i --save-dev @datashard/snapshot ``` ## Import - -After installing, you need to add this snippet within your Cypress Support File (default: `cypress/support/e2e.{js,ts}`) +After Installing, you'll need to add the following import into your Commands/Support File +> by default this will be `cypress/support/e2e.js` ```js -require("@datashard/snapshot").register(); +require('@datashard/snapshot').regsiter() ``` -This registers a new command to create new snapshot or compare value to old snapshot +This will register a new Command `.snapshot()`, to create new Snapshots and once created, to compare their Values. -and add the following to your `cypress.config.{js,ts}` +## Config +You can pass `updateSnapshots` and `useFolders` as options in the `cypress.config.js` file -```js - e2e: { - setupNodeEvents(on, config) { - require("@datashard/snapshot").tasks(on, config) - }, -``` + -> **Note** \ -> \ -> `@datashard/snapshot` **requires** the `readFileMaybe` plugin to be included, which can be easily done using the code above +Alternatively, you can also add `snapshotUpdate` as an Environment Variable to update your snapshots. -# Usage +Simply pass `--env updateSnapshots=true` when running Cypress. -Currently, if you want to take more than one snapshot, you need to pass a Step Name to prevent overwrites / test failures +> If you don't use the default fixture folder, you will also need to add `snapshotPath` to this module's config with the same path you use for `fixtureFolder`. +## Usage + +If properly added, usage of this plugin is rather simple, simply add `.snapshot()` to cypress functions that return valid JSON. + +### Example ```js describe("my tests", () => { it("works", () => { @@ -59,113 +52,27 @@ describe("my tests", () => { }); ``` -In the above case, you can find the stored snapshot in their own files, mentioned above them +Depending on your settings, this module will then save your snapshots as +```ts +// useFolders: false +cypress/fixtures/snapshots/my-tests__works__foo.json +cypress/fixtures/snapshots/my-tests__works__bar.json + +// useFolders: true +cypress/fixtures/snapshots/my-tests/works/foo.json +cypress/fixtures/snapshots/my-tests/works/bar.json -```jsonc -// cypress/fixtures/snapshots/my-tests-works-foo.json -{ "foo": 42 } -// cypress/fixtures/snapshots/my-tests-works-bar.json -{ "bar": 101 } ``` -If you change the site values, the saved snapshot will no longer match, throwing an error +Snapshots will generally be saved using this convention, provided by Cypress: -(picture taken from `cypress/snapshots/Arrays.json`) -![Snapshot mismatch](.github/assets/updated-mismatch.png) - -Click on the `SNAPSHOT` step in the Command Log to see expected and current value printed in the DevTools. - -### Options - -You can control snapshot comparison and behavior through a few options. - -```js -cy.get(...).snapshot({ - snapshotName: 'Snapshot Name', // Overwrite the generated Snapshot name - snapshotPath: 'cypress/fixtures/not_snapshots', // Overwrite where the Snapshot should be stored - json: false // convert DOM elements into JSON -}) // when storing in the snapshot file - -// will save as -// cypress/not_snapshots/Snapshot-Name.json +``` +{fixtureFolder}/---.json +{fixtureFolder}////.json ``` -You can also pass a "Step Name" to the Function +If a step wasn't named, it will instead use the ``for the file name, though this means that you will not be able to have more than 1 Snapshot in your It Block, as it would overwrite the previously created Snapshot files. -```js -cy.get(...).snapshot("Intercepted API Request") -// will save as -// cypress/snapshots/---Intercepted-API-Request.json -// to prevent duplications -``` -or both - -```js -cy.get(...).snapshot("Intercepted API Request", { - snapshotPath: "cypress/snapshots/api", - snapshotName: "first_intercept" -}) - -// will save as -// cypress/snapshots/api/first_intercept.json -``` - -### Configuration - -This module provides some configuration options: - -#### snapshot.snapshotPath - -Sets the default Path for saving Snapshots (default: `cypress/snapshots`) - -![Config Screenshot](./.github/assets/config.png) - -#### `ENV` CYPRESS_UPDATE_SNAPSHOTS - -Lets you pass a Env Variable to update failing Tests with the new Data - -# - -### Small print - -Authors: - -- Joshua <[data@shard.wtf](mailto:data@shard.wtf)> -- Gleb Bahmutov <gleb@cypress.io> - -
-License: MIT - do anything with the code, but don't blame us if it does not work. - -Support: If you find any problems with this module [open an issue](https://github.com/datashard/snapshot/issues) on Github - -## MIT License - -Copyright (c) 2017-2022 Cypress.io <hello@cypress.io> & Joshua <data@shard.wtf> - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -[npm-icon]: https://nodei.co/npm/@datashard/snapshot.svg?downloads=true -[npm-url]: https://npmjs.org/package/@datashard/snapshot -[semantic-url]: https://github.com/semantic-release/semantic-release -[renovate-badge]: https://img.shields.io/badge/renovate-app-blue.svg -[renovate-app]: https://renovateapp.com/ +Of course, if a value changed, it will no longer match the snapshot and throw an Error. +![](./.github/assets/Error.png) \ No newline at end of file diff --git a/cypress.config.js b/cypress.config.js index 9acf04d..b774daf 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -3,7 +3,7 @@ const { defineConfig } = require("cypress"); module.exports = defineConfig({ snapshot: { - updateSnapshots: true, + // updateSnapshots: true, useFolders: true, }, @@ -12,4 +12,4 @@ module.exports = defineConfig({ // implement node event listeners here }, }, -}); +}); \ No newline at end of file diff --git a/cypress/e2e/1.cy.js b/cypress/e2e/1.cy.js index a86374e..11a4807 100644 --- a/cypress/e2e/1.cy.js +++ b/cypress/e2e/1.cy.js @@ -48,13 +48,13 @@ describe("datashard/snapshot", () => { cy.wrap({ "status": 200, "response": { - "array": [0, 1, 2, "Three"], + "array": [0, 1, 2, "4"], "object": { - "with": "more details" + // "with": "more details" } - } - } - ).snapshot() + }, + "thisisnew": "wtf" + }).snapshot() }) it("works based on fixtures", () => { cy diff --git a/cypress/e2e/2.cy.js b/cypress/e2e/2.cy.js index 9d4abde..ebd6fd7 100644 --- a/cypress/e2e/2.cy.js +++ b/cypress/e2e/2.cy.js @@ -3,25 +3,21 @@ describe("Random Describe", () => { context("Random Context", () => { it("Random It", () => { - cy.fixture("File").snapshot("Fixture File", { - snapshotName: "Random Fixture File" - }); - // cy.fixture("File2").snapshot("Fixture File", + cy.wrap(42).snapshot("Numbers"); + cy.wrap("foo-bar").snapshot("Strings"); + cy.wrap([1, 2, 3]).snapshot("Arrays"); }); // it("works with numbers", () => { // console.log(cy.wrap(42)) - // cy.wrap(42).snapshot(); // }); // it("works with strings", () => { // console.log(cy.wrap("foo-bar")) - // cy.wrap("foo-bar").snapshot(); // }); // it("works with arrays", () => { // console.log(cy.wrap([1, 2, 3])) - // cy.wrap([1, 2, 3]).snapshot(); // }); }); }); diff --git a/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Arrays.json b/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Arrays.json new file mode 100644 index 0000000..83589cc --- /dev/null +++ b/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Arrays.json @@ -0,0 +1,7 @@ +{ + "data": [ + 1, + 2, + 3 + ] +} \ No newline at end of file diff --git a/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Numbers.json b/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Numbers.json new file mode 100644 index 0000000..7941fc3 --- /dev/null +++ b/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Numbers.json @@ -0,0 +1,3 @@ +{ + "data": 42 +} \ No newline at end of file diff --git a/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Strings.json b/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Strings.json new file mode 100644 index 0000000..c36f355 --- /dev/null +++ b/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Strings.json @@ -0,0 +1,3 @@ +{ + "data": "foo-bar" +} \ No newline at end of file diff --git a/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json b/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json index 1de1100..4c1e9ca 100644 --- a/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json +++ b/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json @@ -5,10 +5,9 @@ 0, 1, 2, - "Three" + "4" ], - "object": { - "with": "more details" - } - } + "object": {} + }, + "thisisnew": "wtf" } \ No newline at end of file diff --git a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-based-on-fixtures.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-based-on-fixtures.json deleted file mode 100644 index ac6239a..0000000 --- a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-based-on-fixtures.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "jsonapi": { - "version": "2.0" - }, - "included": [ - { - "type": "users", - "id": "2", - "attributes": { - "name": "Test" - } - } - ] -} \ No newline at end of file diff --git a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-more-complicated-Objects.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-more-complicated-Objects.json deleted file mode 100644 index 1de1100..0000000 --- a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-more-complicated-Objects.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "status": 200, - "response": { - "array": [ - 0, - 1, - 2, - "Three" - ], - "object": { - "with": "more details" - } - } -} \ No newline at end of file diff --git a/package.json b/package.json index 0be2c4e..87282a2 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "unused-deps": "dependency-check --unused --no-dev . --entry src/index.js", "semantic-release": "semantic-release", "cypress:open": "cypress open", - "cypress:update": "cypress run --env SNAPSHOT_UPDATE=true", + "cypress:update": "cypress run --env updateSnapshots=true", "cypress:run": "cypress run" }, "devDependencies": { diff --git a/src/snapshot.js b/src/snapshot.js index e9f1997..8ffb7dd 100644 --- a/src/snapshot.js +++ b/src/snapshot.js @@ -11,10 +11,16 @@ const pickSerializer = (asJson, value) => { return identity; }; +/** + * + * @param {string} text + * @returns {string} + */ + +const parseTextToJSON = (text) => text.replace(/\| [✅➖➕⭕]/g, "").trim().replace(/(.*?),\s*(\}|])/g, "$1$2").replace(/},(?!")$/g, "}"); + const store_snapshot = (props = { value, name, raiser }) => { if (Cypress.env().updateSnapshots || Cypress.config('snapshot').updateSnapshots) { - cy.log(props.name) - console.log(props.name) cy.writeFile(`${props.name}.json`, JSON.stringify(props.value, null, 2)) } else { // TODO: Figure out how to replace the fixture folder name if people move it @@ -39,6 +45,7 @@ const set_snapshot = ({ snapshotName, serialized, value }) => { const raiser = ({ value, expected }) => { const result = compareValues({ expected, value }); + // console.log("Final Result", result.result) if ((!Cypress.env().updateSnapshots || !Cypress.config('snapshot').updateSnapshots) && !result.success) { devToolsLog = { ...devToolsLog, @@ -49,10 +56,13 @@ const set_snapshot = ({ snapshotName, serialized, value }) => { throw new Error( `Snapshot Difference found.\nPlease Update the Snapshot\n - - ${JSON.stringify(result.result.replaceAll(/[╺┿╳]/g, ""), null, 2)}` - ); + ${JSON.stringify( + JSON.parse(parseTextToJSON(result.result).replaceAll(/[╺┿╳]/g, "")), null, 2) + .replaceAll(" ", " ") + } + + `); } }; Cypress.log(options); diff --git a/src/utils/compareValues.js b/src/utils/compareValues.js index e9b0cf5..ce803cb 100644 --- a/src/utils/compareValues.js +++ b/src/utils/compareValues.js @@ -1,52 +1,20 @@ -const isNestedData = (expected, value) => { - return ( - expected && value && typeof expected == `object` && typeof value == `object` - ); -}; + +const containsDiffChars = str => ["╺", "┿", "╳"].some(emoji => str.includes(emoji)); +const isNestedData = (expected, value) => expected && value && typeof expected == 'object' && typeof value == 'object'; + const checkDataState = (expected, value) => { let result; - if (expected === value) { result = `| ✅ "${value}",`; - } else if (expected == undefined) { - result = `| ➖ "➖╺ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; - } else if (value == undefined) { - result = `| ➕ "➕┿ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; } else { - result = `| ⭕ "⭕╳ ${JSON.stringify(expected)?.replaceAll('"', "'")}|${value?.replaceAll('"', "'")}",`; + result = `| ⭕ "⭕╳ ${JSON.stringify(expected)?.replaceAll('"', "'")} | ${value?.replaceAll('"', "'")}",`; } return result; }; - -/** - * - * @param {string} text - * @returns {string} - */ - -function parseTextToJSON(text) { - const lines = - // JSON.stringify( - text - .replace(/\| [✅➖➕⭕]/g, "").trim() - .replace(/(.*?),\s*(\}|])/g, "$1$2") - // ) - return lines; - // return JSON.stringify(lines, null, 2); -} - -function containsDiffChars(str) { - const emojis = ["╺", "┿", "╳"]; - return emojis.some(emoji => str.includes(emoji)); -} - const compare = (expected, value) => { - if(value === undefined){ - throw new Error("Please provide Data to compare against.") - } let compareResult = ""; if (isNestedData(expected, value)) { @@ -62,6 +30,9 @@ const compare = (expected, value) => { dataY = expected; } + console.log('datax', dataX) + console.log('dataY', dataY) + dataX.forEach(function (item, index) { const resultset = compare(item, dataY[index]); compareResult += resultset.result; @@ -87,18 +58,14 @@ const compare = (expected, value) => { } else { compareResult = checkDataState(expected, value); } - let result = parseTextToJSON(compareResult).replace(/(},)$/g, `}`); - console.log("compareResult",compareResult) - console.log("result", result.replace(/(},)$/g, `}`)) - // let result = compareResult; try { return { - success: !containsDiffChars(result), - result, + success: !containsDiffChars(compareResult), + result: compareResult, }; } catch (error) { - return { success: false, result }; + return { success: false, result: compareResult }; } }; From 960e699075012c733070dff2f38ce30e5b0bdb38 Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 1 Feb 2024 11:58:42 +0100 Subject: [PATCH 06/19] bump cypress and redo logging --- package-lock.json | 730 ++++------------------------------------------ package.json | 2 +- src/snapshot.js | 35 +-- 3 files changed, 73 insertions(+), 694 deletions(-) diff --git a/package-lock.json b/package-lock.json index b95ae2c..e41eb02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,25 +1,21 @@ { "name": "@datashard/snapshot", - "version": "2.2.2", + "version": "2.3.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@datashard/snapshot", - "version": "2.2.2", + "version": "2.3.2", "license": "MIT", "dependencies": { "@wildpeaks/snapshot-dom": "1.6.0", - "chai": "4.3.10", "check-more-types": "2.24.0", "js-beautify": "1.13.13", - "jsondiffpatch": "0.5.0", - "lazy-ass": "1.6.0", - "snap-shot-compare": "3.0.0", - "snap-shot-store": "1.2.3" + "lazy-ass": "1.6.0" }, "devDependencies": { - "cypress": "10.6.0", + "cypress": "12.13.0", "debug": "3.2.7", "dependency-check": "2.10.1" }, @@ -232,22 +228,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -286,14 +266,6 @@ "node": ">=0.8" } }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "engines": { - "node": "*" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -469,68 +441,6 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, - "node_modules/chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chalk/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chalk/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, "node_modules/check-more-types": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", @@ -701,6 +611,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -711,7 +622,8 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/colorette": { "version": "2.0.19", @@ -766,9 +678,9 @@ "dev": true }, "node_modules/cypress": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.6.0.tgz", - "integrity": "sha512-6sOpHjostp8gcLO34p6r/Ci342lBs8S5z9/eb3ZCQ22w2cIhMWGUoGKkosabPBfKcvRS9BE4UxybBtlIs8gTQA==", + "version": "12.13.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.13.0.tgz", + "integrity": "sha512-QJlSmdPk+53Zhy69woJMySZQJoWfEWun3X5OOenGsXjRPVfByVTHorxNehbzhZrEzH9RDUDqVcck0ahtlS+N/Q==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -786,12 +698,12 @@ "check-more-types": "^2.24.0", "cli-cursor": "^3.1.0", "cli-table3": "~0.6.1", - "commander": "^5.1.0", + "commander": "^6.2.1", "common-tags": "^1.8.0", "dayjs": "^1.10.4", - "debug": "^4.3.2", + "debug": "^4.3.4", "enquirer": "^2.3.6", - "eventemitter2": "^6.4.3", + "eventemitter2": "6.4.7", "execa": "4.1.0", "executable": "^4.1.1", "extract-zip": "2.0.1", @@ -804,7 +716,7 @@ "listr2": "^3.8.3", "lodash": "^4.17.21", "log-symbols": "^4.0.0", - "minimist": "^1.2.6", + "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", "proxy-from-env": "1.0.0", @@ -819,7 +731,7 @@ "cypress": "bin/cypress" }, "engines": { - "node": ">=12.0.0" + "node": "^14.0.0 || ^16.0.0 || >=18.0.0" } }, "node_modules/cypress/node_modules/ansi-styles": { @@ -866,9 +778,9 @@ } }, "node_modules/cypress/node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true, "engines": { "node": ">= 6" @@ -919,12 +831,6 @@ "node": ">=10" } }, - "node_modules/cypress/node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, "node_modules/cypress/node_modules/semver": { "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", @@ -988,17 +894,6 @@ "ms": "^2.1.1" } }, - "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", @@ -1042,12 +937,6 @@ "ms": "2.0.0" } }, - "node_modules/dependency-check/node_modules/minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "node_modules/dependency-check/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1064,48 +953,6 @@ "defined": "^1.0.0" } }, - "node_modules/diff-match-patch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" - }, - "node_modules/disparity": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/disparity/-/disparity-3.0.0.tgz", - "integrity": "sha512-n94Rzbv2ambRaFzrnBf34IEiyOdIci7maRpMkoQWB6xFYGA7Nbs0Z5YQzMfTeyQeelv23nayqOcssBoc6rKrgw==", - "dependencies": { - "ansi-styles": "^4.1.0", - "diff": "^4.0.1" - }, - "bin": { - "disparity": "bin/disparity" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/disparity/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/disparity/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1164,6 +1011,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, "engines": { "node": ">=0.8.0" } @@ -1353,11 +1201,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/folktale": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/folktale/-/folktale-2.3.2.tgz", - "integrity": "sha512-+8GbtQBwEqutP0v3uajDDoN64K2ehmHd0cjlghhxh0WpcfPzAIjPA03e1VvHlxL02FVGR0A6lwXsNQKn3H1RNQ==" - }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -1401,14 +1244,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "engines": { - "node": "*" - } - }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -1509,29 +1344,11 @@ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "engines": { "node": ">=8" } @@ -1739,58 +1556,6 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, - "node_modules/jsondiffpatch": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.5.0.tgz", - "integrity": "sha512-Quz3MvAwHxVYNXsOByL7xI5EB2WYOeFswqaHIA3qOK3isRWTxiplBEocmmru6XmxDB2L7jDNYtYA4FyimoAFEw==", - "dependencies": { - "chalk": "^3.0.0", - "diff-match-patch": "^1.0.0" - }, - "bin": { - "jsondiffpatch": "bin/jsondiffpatch" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/jsondiffpatch/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jsondiffpatch/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jsondiffpatch/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -2046,14 +1811,6 @@ "node": ">=8" } }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dependencies": { - "get-func-name": "^2.0.1" - } - }, "node_modules/lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -2101,10 +1858,20 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/natives": { "version": "1.1.6", @@ -2160,14 +1927,6 @@ "node": ">=8" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2244,14 +2003,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "engines": { - "node": "*" - } - }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -2326,11 +2077,6 @@ "node": ">=0.6" } }, - "node_modules/ramda": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz", - "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==" - }, "node_modules/read-package-json": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-1.3.3.tgz", @@ -2507,65 +2253,6 @@ "node": ">=8" } }, - "node_modules/snap-shot-compare": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/snap-shot-compare/-/snap-shot-compare-3.0.0.tgz", - "integrity": "sha512-bdwNOAGuKwPU+qsn0ASxTv+QfkXU+3VmkcDOkt965tes+JQQc8d6SfoLiEiRVhCey4v+ip2IjNUSbZm5nnkI9g==", - "dependencies": { - "check-more-types": "2.24.0", - "debug": "4.1.1", - "disparity": "3.0.0", - "folktale": "2.3.2", - "lazy-ass": "1.6.0", - "strip-ansi": "5.2.0", - "variable-diff": "1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/snap-shot-compare/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/snap-shot-store": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/snap-shot-store/-/snap-shot-store-1.2.3.tgz", - "integrity": "sha512-KLSUkdXvSfoPGPSo5Qk97jYEpME96WECOuIOpW91OGYt/fX2g2xOvXA35EJziI32PlDbRfi36JxzUcSsh59Ykw==", - "dependencies": { - "check-more-types": "2.24.0", - "debug": "3.1.0", - "folktale": "2.0.1", - "lazy-ass": "1.6.0", - "ramda": "0.25.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/snap-shot-store/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snap-shot-store/node_modules/folktale": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/folktale/-/folktale-2.0.1.tgz", - "integrity": "sha512-3kDSWVkSlErHIt/dC73vu+5zRqbW1mlnL46s2QfYN7Ps0JcS9MVtuLCrDQOBa7sanA+d9Fd8F+bn0VcyNe68Jw==" - }, - "node_modules/snap-shot-store/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "node_modules/sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", @@ -2591,17 +2278,6 @@ "node": ">=0.10.0" } }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -2611,14 +2287,6 @@ "node": ">=6" } }, - "node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", @@ -2667,14 +2335,6 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "engines": { - "node": ">=4" - } - }, "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -2702,15 +2362,6 @@ "node": ">=8" } }, - "node_modules/variable-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/variable-diff/-/variable-diff-1.1.0.tgz", - "integrity": "sha1-0r1cZtt2wTh52W5qMG7cmJ35eNo=", - "dependencies": { - "chalk": "^1.1.1", - "object-assign": "^4.0.1" - } - }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -2916,16 +2567,6 @@ } } }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, "arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -2947,11 +2588,6 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" - }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -3085,55 +2721,6 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, - "chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - } - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "requires": { - "get-func-name": "^2.0.2" - } - }, "check-more-types": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", @@ -3264,6 +2851,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { "color-name": "~1.1.4" } @@ -3271,7 +2859,8 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "colorette": { "version": "2.0.19", @@ -3320,9 +2909,9 @@ "dev": true }, "cypress": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.6.0.tgz", - "integrity": "sha512-6sOpHjostp8gcLO34p6r/Ci342lBs8S5z9/eb3ZCQ22w2cIhMWGUoGKkosabPBfKcvRS9BE4UxybBtlIs8gTQA==", + "version": "12.13.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.13.0.tgz", + "integrity": "sha512-QJlSmdPk+53Zhy69woJMySZQJoWfEWun3X5OOenGsXjRPVfByVTHorxNehbzhZrEzH9RDUDqVcck0ahtlS+N/Q==", "dev": true, "requires": { "@cypress/request": "^2.88.10", @@ -3339,12 +2928,12 @@ "check-more-types": "^2.24.0", "cli-cursor": "^3.1.0", "cli-table3": "~0.6.1", - "commander": "^5.1.0", + "commander": "^6.2.1", "common-tags": "^1.8.0", "dayjs": "^1.10.4", - "debug": "^4.3.2", + "debug": "^4.3.4", "enquirer": "^2.3.6", - "eventemitter2": "^6.4.3", + "eventemitter2": "6.4.7", "execa": "4.1.0", "executable": "^4.1.1", "extract-zip": "2.0.1", @@ -3357,7 +2946,7 @@ "listr2": "^3.8.3", "lodash": "^4.17.21", "log-symbols": "^4.0.0", - "minimist": "^1.2.6", + "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", "proxy-from-env": "1.0.0", @@ -3400,9 +2989,9 @@ } }, "commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true }, "debug": { @@ -3433,12 +3022,6 @@ "yallist": "^4.0.0" } }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, "semver": { "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", @@ -3489,14 +3072,6 @@ "ms": "^2.1.1" } }, - "deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "requires": { - "type-detect": "^4.0.0" - } - }, "defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", @@ -3534,12 +3109,6 @@ "ms": "2.0.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -3558,35 +3127,6 @@ "defined": "^1.0.0" } }, - "diff-match-patch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" - }, - "disparity": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/disparity/-/disparity-3.0.0.tgz", - "integrity": "sha512-n94Rzbv2ambRaFzrnBf34IEiyOdIci7maRpMkoQWB6xFYGA7Nbs0Z5YQzMfTeyQeelv23nayqOcssBoc6rKrgw==", - "requires": { - "ansi-styles": "^4.1.0", - "diff": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" - } - } - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -3637,7 +3177,8 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "eventemitter2": { "version": "6.4.7", @@ -3775,11 +3316,6 @@ "escape-string-regexp": "^1.0.5" } }, - "folktale": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/folktale/-/folktale-2.3.2.tgz", - "integrity": "sha512-+8GbtQBwEqutP0v3uajDDoN64K2ehmHd0cjlghhxh0WpcfPzAIjPA03e1VvHlxL02FVGR0A6lwXsNQKn3H1RNQ==" - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -3814,11 +3350,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==" - }, "get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -3902,25 +3433,11 @@ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, "ieee754": { "version": "1.2.1", @@ -4066,42 +3583,6 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, - "jsondiffpatch": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.5.0.tgz", - "integrity": "sha512-Quz3MvAwHxVYNXsOByL7xI5EB2WYOeFswqaHIA3qOK3isRWTxiplBEocmmru6XmxDB2L7jDNYtYA4FyimoAFEw==", - "requires": { - "chalk": "^3.0.0", - "diff-match-patch": "^1.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -4288,14 +3769,6 @@ } } }, - "loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "requires": { - "get-func-name": "^2.0.1" - } - }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -4334,10 +3807,17 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "natives": { "version": "1.1.6", @@ -4382,11 +3862,6 @@ "path-key": "^3.0.0" } }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4444,11 +3919,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" - }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -4511,11 +3981,6 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, - "ramda": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz", - "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==" - }, "read-package-json": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-1.3.3.tgz", @@ -4661,62 +4126,6 @@ } } }, - "snap-shot-compare": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/snap-shot-compare/-/snap-shot-compare-3.0.0.tgz", - "integrity": "sha512-bdwNOAGuKwPU+qsn0ASxTv+QfkXU+3VmkcDOkt965tes+JQQc8d6SfoLiEiRVhCey4v+ip2IjNUSbZm5nnkI9g==", - "requires": { - "check-more-types": "2.24.0", - "debug": "4.1.1", - "disparity": "3.0.0", - "folktale": "2.3.2", - "lazy-ass": "1.6.0", - "strip-ansi": "5.2.0", - "variable-diff": "1.1.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "snap-shot-store": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/snap-shot-store/-/snap-shot-store-1.2.3.tgz", - "integrity": "sha512-KLSUkdXvSfoPGPSo5Qk97jYEpME96WECOuIOpW91OGYt/fX2g2xOvXA35EJziI32PlDbRfi36JxzUcSsh59Ykw==", - "requires": { - "check-more-types": "2.24.0", - "debug": "3.1.0", - "folktale": "2.0.1", - "lazy-ass": "1.6.0", - "ramda": "0.25.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "folktale": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/folktale/-/folktale-2.0.1.tgz", - "integrity": "sha512-3kDSWVkSlErHIt/dC73vu+5zRqbW1mlnL46s2QfYN7Ps0JcS9MVtuLCrDQOBa7sanA+d9Fd8F+bn0VcyNe68Jw==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", @@ -4734,25 +4143,12 @@ "tweetnacl": "~0.14.0" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - }, "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, "throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", @@ -4795,11 +4191,6 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" - }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -4818,15 +4209,6 @@ "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true }, - "variable-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/variable-diff/-/variable-diff-1.1.0.tgz", - "integrity": "sha1-0r1cZtt2wTh52W5qMG7cmJ35eNo=", - "requires": { - "chalk": "^1.1.1", - "object-assign": "^4.0.1" - } - }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", diff --git a/package.json b/package.json index 87282a2..e66eac3 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "cypress:run": "cypress run" }, "devDependencies": { - "cypress": "10.6.0", + "cypress": "12.13.0", "debug": "3.2.7", "dependency-check": "2.10.1" }, diff --git a/src/snapshot.js b/src/snapshot.js index 8ffb7dd..135d47b 100644 --- a/src/snapshot.js +++ b/src/snapshot.js @@ -17,7 +17,7 @@ const pickSerializer = (asJson, value) => { * @returns {string} */ -const parseTextToJSON = (text) => text.replace(/\| [✅➖➕⭕]/g, "").trim().replace(/(.*?),\s*(\}|])/g, "$1$2").replace(/},(?!")$/g, "}"); +const parseTextToJSON = (text) => text.replace(/\| [✅➖➕⭕]/g, "").trim().replace(/(.*?),\s*(\}|])/g, "$1$2").replace(/},(?!")$/g, "}").replaceAll(/[╺┿╳]/g, "") const store_snapshot = (props = { value, name, raiser }) => { if (Cypress.env().updateSnapshots || Cypress.config('snapshot').updateSnapshots) { @@ -35,36 +35,33 @@ const set_snapshot = ({ snapshotName, serialized, value }) => { devToolsLog.$el = value; } - const options = { - name: "snapshot", - message: snapshotName, - consoleProps: () => devToolsLog, - }; - if (value) options.$el = value; const raiser = ({ value, expected }) => { const result = compareValues({ expected, value }); // console.log("Final Result", result.result) if ((!Cypress.env().updateSnapshots || !Cypress.config('snapshot').updateSnapshots) && !result.success) { - devToolsLog = { - ...devToolsLog, - message: result, - expected, - value, + devToolsLog = () => { + return { expected, value } }; - throw new Error( - `Snapshot Difference found.\nPlease Update the Snapshot\n + const error = (inError) => ` + Snapshot Difference found.\nPlease Update the Snapshot ${inError ? `\n${JSON.stringify(JSON.parse(parseTextToJSON(result.result)), null, 3).replaceAll(' ', " ")}` : ""}` - ${JSON.stringify( - JSON.parse(parseTextToJSON(result.result).replaceAll(/[╺┿╳]/g, "")), null, 2) - .replaceAll(" ", " ") - } + Cypress.log({ message: error(true) }) - `); + throw new Error(error()); } }; + + let options = { + name: "snapshot", + message: snapshotName, + consoleProps: () => { return devToolsLog }, + }; + + if (value) options.$el = value; + Cypress.log(options); store_snapshot({ From 5f861d49494f388c51ee9354d8ff2adddb99a4c7 Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 1 Feb 2024 14:44:27 +0100 Subject: [PATCH 07/19] add prettier logging --- cypress/support/commands.js | 109 ++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 4bea380..21cb158 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -1,2 +1,111 @@ // register .snapshot() command + +const baseStyles = [ + { + name: 'info', + color: '#cbd5e1', + }, + { + name: 'success', + color: '#10b981', + }, + { + name: 'warning', + color: '#fbbf24', + }, + { + name: 'error', + color: '#dc2626', + }, +] + +/** + * Helper function to convert hex colors to rgb + * @param {string} hex - hex color + * @returns {string} + * + * @example + * // returns "255 255 255" + * hex2rgb("#ffffff") + */ +function hex2rgb(hex) { + const r = parseInt(hex.slice(1, 3), 16) + const g = parseInt(hex.slice(3, 5), 16) + const b = parseInt(hex.slice(5, 7), 16) + + return `${r} ${g} ${b}` +} + +baseStyles.forEach((style) => { + createCustomLog(style.name, style.color) +}) + +/** + * Create a custom log + * @param {string} name - Name of the custom log + * @param {string} baseColor - Base color of the custom log in hex format + * + * @example + * // Create a custom log with name "misc" and base color "#9333ea" + * createCustomLog("misc", "#9333ea") + */ +export function createCustomLog(name, baseColor) { + if (!name || !baseColor) { + throw new Error('Missing parameters') + } + + const logStyle = document.createElement('style') + + logStyle.textContent = ` + .command.command-name-log-${name} span.command-method { + margin-right: 0.5rem; + min-width: 10px; + border-radius: 0.125rem; + border-width: 1px; + padding-left: 0.375rem; + padding-right: 0.375rem; + padding-top: 0.125rem; + padding-bottom: 0.125rem; + text-transform: uppercase; + + border-color: rgb(${hex2rgb(baseColor)} / 1); + background-color: rgb(${hex2rgb(baseColor)} / 0.2); + color: rgb(${hex2rgb(baseColor)} / 1) !important; + } + + .command.command-name-log-${name} span.command-message{ + color: rgb(${hex2rgb(baseColor)} / 1); + font-weight: normal; + } + + .command.command-name-log-${name} span.command-message strong, + .command.command-name-log-${name} span.command-message em { + color: rgb(${hex2rgb(baseColor)} / 1); + } + ` + + Cypress.$(window.top.document.head).append(logStyle) +} + +/** + * Print a message with a formatted style + * @param {Object} log - The message to be printed. + * @param {string} log.title - The title of the message. + * @param {string} log.message - The content of the message. + * @param {('info' | 'warning' | 'error' | 'success')} log.type - The type of the message. + * + * @example + * // Print a message with a formatted style e.g. success + * cy.print({ title: 'foo', message: 'bar', type: 'success' }) + */ +function cyPrint({ title, message, type }) { + Cypress.log({ + name: `log-${type}`, + displayName: `${title}`, + message, + }) +} + +Cypress.Commands.add('SNAPSHOT_prettyprint', cyPrint) + require('../../src/index').register() From b1ce5f2fdf3f5586df19cd2a9c36591c84131f8a Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 1 Feb 2024 14:45:03 +0100 Subject: [PATCH 08/19] cleanup --- cypress/e2e/1.cy.js | 2 +- src/snapshot.js | 22 +++++++++++++--------- src/utils/compareValues.js | 3 --- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/cypress/e2e/1.cy.js b/cypress/e2e/1.cy.js index 11a4807..4e3cb70 100644 --- a/cypress/e2e/1.cy.js +++ b/cypress/e2e/1.cy.js @@ -50,7 +50,7 @@ describe("datashard/snapshot", () => { "response": { "array": [0, 1, 2, "4"], "object": { - // "with": "more details" + "with": "more details" } }, "thisisnew": "wtf" diff --git a/src/snapshot.js b/src/snapshot.js index 135d47b..1dc6c74 100644 --- a/src/snapshot.js +++ b/src/snapshot.js @@ -21,6 +21,7 @@ const parseTextToJSON = (text) => text.replace(/\| [✅➖➕⭕]/g, "").trim(). const store_snapshot = (props = { value, name, raiser }) => { if (Cypress.env().updateSnapshots || Cypress.config('snapshot').updateSnapshots) { + cy.SNAPSHOT_prettyprint({ title: "INFO", type: "info", message: "Saving Snapshot" }) cy.writeFile(`${props.name}.json`, JSON.stringify(props.value, null, 2)) } else { // TODO: Figure out how to replace the fixture folder name if people move it @@ -35,11 +36,16 @@ const set_snapshot = ({ snapshotName, serialized, value }) => { devToolsLog.$el = value; } + let options = { + name: "snapshot", + message: snapshotName, + consoleProps: () => { return devToolsLog }, + }; + if (value) options.$el = value; const raiser = ({ value, expected }) => { const result = compareValues({ expected, value }); - // console.log("Final Result", result.result) if ((!Cypress.env().updateSnapshots || !Cypress.config('snapshot').updateSnapshots) && !result.success) { devToolsLog = () => { return { expected, value } @@ -51,18 +57,16 @@ const set_snapshot = ({ snapshotName, serialized, value }) => { Cypress.log({ message: error(true) }) throw new Error(error()); + } else { + cy.SNAPSHOT_prettyprint({ + title: "SUCCESS", + message: snapshotName, + type: "success" + }) } }; - let options = { - name: "snapshot", - message: snapshotName, - consoleProps: () => { return devToolsLog }, - }; - if (value) options.$el = value; - - Cypress.log(options); store_snapshot({ value, diff --git a/src/utils/compareValues.js b/src/utils/compareValues.js index ce803cb..1c7c885 100644 --- a/src/utils/compareValues.js +++ b/src/utils/compareValues.js @@ -30,9 +30,6 @@ const compare = (expected, value) => { dataY = expected; } - console.log('datax', dataX) - console.log('dataY', dataY) - dataX.forEach(function (item, index) { const resultset = compare(item, dataY[index]); compareResult += resultset.result; From f51bcae462f641a63012b241154f6c5b2c8dde4b Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 1 Feb 2024 14:45:18 +0100 Subject: [PATCH 09/19] rebuild snapshot --- .../complex-types/works-with-more-complicated-Objects.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json b/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json index 4c1e9ca..0b48984 100644 --- a/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json +++ b/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json @@ -7,7 +7,9 @@ 2, "4" ], - "object": {} + "object": { + "with": "more details" + } }, "thisisnew": "wtf" } \ No newline at end of file From 4b96c410562940fcf436336cbe6973c91538830e Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 5 Feb 2024 16:17:41 +0100 Subject: [PATCH 10/19] move prettyprint log into register.js --- cypress/support/commands.js | 107 ----------------------------------- src/register.js | 109 +++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 108 deletions(-) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 21cb158..887788f 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -1,111 +1,4 @@ // register .snapshot() command -const baseStyles = [ - { - name: 'info', - color: '#cbd5e1', - }, - { - name: 'success', - color: '#10b981', - }, - { - name: 'warning', - color: '#fbbf24', - }, - { - name: 'error', - color: '#dc2626', - }, -] - -/** - * Helper function to convert hex colors to rgb - * @param {string} hex - hex color - * @returns {string} - * - * @example - * // returns "255 255 255" - * hex2rgb("#ffffff") - */ -function hex2rgb(hex) { - const r = parseInt(hex.slice(1, 3), 16) - const g = parseInt(hex.slice(3, 5), 16) - const b = parseInt(hex.slice(5, 7), 16) - - return `${r} ${g} ${b}` -} - -baseStyles.forEach((style) => { - createCustomLog(style.name, style.color) -}) - -/** - * Create a custom log - * @param {string} name - Name of the custom log - * @param {string} baseColor - Base color of the custom log in hex format - * - * @example - * // Create a custom log with name "misc" and base color "#9333ea" - * createCustomLog("misc", "#9333ea") - */ -export function createCustomLog(name, baseColor) { - if (!name || !baseColor) { - throw new Error('Missing parameters') - } - - const logStyle = document.createElement('style') - - logStyle.textContent = ` - .command.command-name-log-${name} span.command-method { - margin-right: 0.5rem; - min-width: 10px; - border-radius: 0.125rem; - border-width: 1px; - padding-left: 0.375rem; - padding-right: 0.375rem; - padding-top: 0.125rem; - padding-bottom: 0.125rem; - text-transform: uppercase; - - border-color: rgb(${hex2rgb(baseColor)} / 1); - background-color: rgb(${hex2rgb(baseColor)} / 0.2); - color: rgb(${hex2rgb(baseColor)} / 1) !important; - } - - .command.command-name-log-${name} span.command-message{ - color: rgb(${hex2rgb(baseColor)} / 1); - font-weight: normal; - } - - .command.command-name-log-${name} span.command-message strong, - .command.command-name-log-${name} span.command-message em { - color: rgb(${hex2rgb(baseColor)} / 1); - } - ` - - Cypress.$(window.top.document.head).append(logStyle) -} - -/** - * Print a message with a formatted style - * @param {Object} log - The message to be printed. - * @param {string} log.title - The title of the message. - * @param {string} log.message - The content of the message. - * @param {('info' | 'warning' | 'error' | 'success')} log.type - The type of the message. - * - * @example - * // Print a message with a formatted style e.g. success - * cy.print({ title: 'foo', message: 'bar', type: 'success' }) - */ -function cyPrint({ title, message, type }) { - Cypress.log({ - name: `log-${type}`, - displayName: `${title}`, - message, - }) -} - -Cypress.Commands.add('SNAPSHOT_prettyprint', cyPrint) require('../../src/index').register() diff --git a/src/register.js b/src/register.js index e1b1fa0..8a77604 100644 --- a/src/register.js +++ b/src/register.js @@ -2,12 +2,119 @@ const lazy = require("lazy-ass"); const is = require("check-more-types"); const snapshot = require("./snapshot"); +const baseStyles = [ + { + name: 'info', + color: '#cbd5e1', + }, + { + name: 'success', + color: '#10b981', + }, + { + name: 'warning', + color: '#fbbf24', + }, + { + name: 'error', + color: '#dc2626', + }, +] + +/** +* Helper function to convert hex colors to rgb +* @param {string} hex - hex color +* @returns {string} +* +* @example +* // returns "255 255 255" +* hex2rgb("#ffffff") +*/ +function hex2rgb(hex) { + const r = parseInt(hex.slice(1, 3), 16) + const g = parseInt(hex.slice(3, 5), 16) + const b = parseInt(hex.slice(5, 7), 16) + + return `${r} ${g} ${b}` +} + +baseStyles.forEach((style) => { + createCustomLog(style.name, style.color) +}) + +/** +* Create a custom log +* @param {string} name - Name of the custom log +* @param {string} baseColor - Base color of the custom log in hex format +* +* @example +* // Create a custom log with name "misc" and base color "#9333ea" +* createCustomLog("misc", "#9333ea") +*/ +export function createCustomLog(name, baseColor) { + if (!name || !baseColor) { + throw new Error('Missing parameters') + } + + const logStyle = document.createElement('style') + + logStyle.textContent = ` + .command.command-name-log-${name} span.command-method { + margin-right: 0.5rem; + min-width: 10px; + border-radius: 0.125rem; + border-width: 1px; + padding-left: 0.375rem; + padding-right: 0.375rem; + padding-top: 0.125rem; + padding-bottom: 0.125rem; + text-transform: uppercase; + + border-color: rgb(${hex2rgb(baseColor)} / 1); + background-color: rgb(${hex2rgb(baseColor)} / 0.2); + color: rgb(${hex2rgb(baseColor)} / 1) !important; + } + + .command.command-name-log-${name} span.command-message{ + color: rgb(${hex2rgb(baseColor)} / 1); + font-weight: normal; + } + + .command.command-name-log-${name} span.command-message strong, + .command.command-name-log-${name} span.command-message em { + color: rgb(${hex2rgb(baseColor)} / 1); + } + ` + + Cypress.$(window.top.document.head).append(logStyle) +} + +/** +* Print a message with a formatted style +* @param {Object} log - The message to be printed. +* @param {string} log.title - The title of the message. +* @param {string} log.message - The content of the message. +* @param {('info' | 'warning' | 'error' | 'success')} log.type - The type of the message. +* +* @example +* // Print a message with a formatted style e.g. success +* cy.print({ title: 'foo', message: 'bar', type: 'success' }) +*/ +function cyPrint({ title, message, type }) { + Cypress.log({ + name: `log-${type}`, + displayName: `${title}`, + message, + }) +} + module.exports = () => { lazy(is.fn(global.before), "Missing global before function"); lazy(is.fn(global.after), "Missing global after function"); lazy(is.object(global.Cypress), "Missing Cypress object"); Cypress.Commands.add("snapshot", { prevSubject: "optional" }, snapshot); + Cypress.Commands.add('SNAPSHOT_prettyprint', cyPrint) - return snapshot; + return Cypress; }; From bc6ffad697d420436e3010ca3684be2c15fd37c4 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 5 Feb 2024 16:21:31 +0100 Subject: [PATCH 11/19] register() doesn't need to return anything --- src/register.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/register.js b/src/register.js index 8a77604..4e1c398 100644 --- a/src/register.js +++ b/src/register.js @@ -116,5 +116,4 @@ module.exports = () => { Cypress.Commands.add("snapshot", { prevSubject: "optional" }, snapshot); Cypress.Commands.add('SNAPSHOT_prettyprint', cyPrint) - return Cypress; }; From d45d7479f0c394449ae53beb8d0ae55d078f29d4 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 5 Feb 2024 16:25:50 +0100 Subject: [PATCH 12/19] remove export from createCustomLog function --- src/register.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/register.js b/src/register.js index 4e1c398..3e34641 100644 --- a/src/register.js +++ b/src/register.js @@ -51,7 +51,7 @@ baseStyles.forEach((style) => { * // Create a custom log with name "misc" and base color "#9333ea" * createCustomLog("misc", "#9333ea") */ -export function createCustomLog(name, baseColor) { +function createCustomLog(name, baseColor) { if (!name || !baseColor) { throw new Error('Missing parameters') } From 930662045ca7843be3f6208dd08752f761cb9ce1 Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 28 Mar 2024 10:44:10 +0100 Subject: [PATCH 13/19] working code --- README.md | 5 +++-- cypress.config.js | 2 +- src/snapshot.js | 3 ++- .../simple-types/works-with-arrays.json | 8 ++++++++ 4 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 undefined/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json diff --git a/README.md b/README.md index 883bc45..bf020e6 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ This will register a new Command `.snapshot()`, to create new Snapshots and once ## Config You can pass `updateSnapshots` and `useFolders` as options in the `cypress.config.js` file - +![Example Settings for the Module](./.github/assets/config.png) Alternatively, you can also add `snapshotUpdate` as an Environment Variable to update your snapshots. @@ -75,4 +75,5 @@ If a step wasn't named, it will instead use the ``for the file name, though Of course, if a value changed, it will no longer match the snapshot and throw an Error. -![](./.github/assets/Error.png) \ No newline at end of file +![](./.github/assets/Error.png) + diff --git a/cypress.config.js b/cypress.config.js index b774daf..9301451 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -1,7 +1,7 @@ const { defineConfig } = require("cypress"); module.exports = defineConfig({ - + fixturesFolder: "cypress/fixtures", snapshot: { // updateSnapshots: true, useFolders: true, diff --git a/src/snapshot.js b/src/snapshot.js index 1dc6c74..41b369b 100644 --- a/src/snapshot.js +++ b/src/snapshot.js @@ -22,9 +22,10 @@ const parseTextToJSON = (text) => text.replace(/\| [✅➖➕⭕]/g, "").trim(). const store_snapshot = (props = { value, name, raiser }) => { if (Cypress.env().updateSnapshots || Cypress.config('snapshot').updateSnapshots) { cy.SNAPSHOT_prettyprint({ title: "INFO", type: "info", message: "Saving Snapshot" }) - cy.writeFile(`${props.name}.json`, JSON.stringify(props.value, null, 2)) + cy.writeFile(`${Cypress.env().fixturesFolder}/${props.name}.json`, JSON.stringify(props.value, null, 2)) } else { // TODO: Figure out how to replace the fixture folder name if people move it + // const fixtureName = props.name.replace(Cypress.env().fixturesFolder, "") const fixtureName = props.name.replace("cypress/fixtures", "") cy.fixture(fixtureName).then(content => props.raiser({ value: props.value, expected: content })) } diff --git a/undefined/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json b/undefined/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json new file mode 100644 index 0000000..dc8d53f --- /dev/null +++ b/undefined/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json @@ -0,0 +1,8 @@ +{ + "data": [ + 1, + 2, + 3, + 4 + ] +} \ No newline at end of file From b4f841d878fc62f872fa1ecb0f7b533a0c817b0d Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 11 Apr 2024 18:35:45 +0200 Subject: [PATCH 14/19] fixtures now read and write from cypress --- cypress.config.js | 2 +- src/snapshot.js | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/cypress.config.js b/cypress.config.js index 9301451..a006fa4 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -1,7 +1,7 @@ const { defineConfig } = require("cypress"); module.exports = defineConfig({ - fixturesFolder: "cypress/fixtures", + // fixturesFolder: "cypress/fixtures", snapshot: { // updateSnapshots: true, useFolders: true, diff --git a/src/snapshot.js b/src/snapshot.js index 41b369b..6790b0e 100644 --- a/src/snapshot.js +++ b/src/snapshot.js @@ -22,12 +22,9 @@ const parseTextToJSON = (text) => text.replace(/\| [✅➖➕⭕]/g, "").trim(). const store_snapshot = (props = { value, name, raiser }) => { if (Cypress.env().updateSnapshots || Cypress.config('snapshot').updateSnapshots) { cy.SNAPSHOT_prettyprint({ title: "INFO", type: "info", message: "Saving Snapshot" }) - cy.writeFile(`${Cypress.env().fixturesFolder}/${props.name}.json`, JSON.stringify(props.value, null, 2)) + cy.writeFile(path.join(Cypress.config().fixturesFolder,`${props.name}.json`), JSON.stringify(props.value, null, 2)) } else { - // TODO: Figure out how to replace the fixture folder name if people move it - // const fixtureName = props.name.replace(Cypress.env().fixturesFolder, "") - const fixtureName = props.name.replace("cypress/fixtures", "") - cy.fixture(fixtureName).then(content => props.raiser({ value: props.value, expected: content })) + cy.fixture(props.name).then(content => props.raiser({ value: props.value, expected: content })) } }; @@ -115,9 +112,7 @@ module.exports = (value, stepName, options = { json: true }) => { options.asFolder = Cypress.config('snapshot').useFolders || false set_snapshot({ - snapshotName: path.join( - options.snapshotPath || Cypress.config('snapshot').snapshotPath || 'cypress/fixtures/snapshots', - `/${get_snapshot_name(options.asFolder, stepName)}`), + snapshotName: `/${get_snapshot_name(options.asFolder, stepName)}`, serialized, value, }); From dc1290ec04ad73128bbd734ea1e1885a6f2f3b2c Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 11 Apr 2024 18:36:18 +0200 Subject: [PATCH 15/19] update tests --- .../complex-types/works-based-on-fixtures.json | 14 ++++++++++++++ .../works-with-more-complicated-Objects.json | 15 +++++++++++++++ .../simple-types/works-with-arrays.json | 0 .../simple-types/works-with-numbers.json | 3 +++ .../simple-types/works-with-objects.json | 4 ++++ .../simple-types/works-with-strings.json | 3 +++ 6 files changed, 39 insertions(+) create mode 100644 cypress/fixtures/datashard-snapshot/complex-types/works-based-on-fixtures.json create mode 100644 cypress/fixtures/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json rename {undefined/cypress/fixtures/snapshots => cypress/fixtures}/datashard-snapshot/simple-types/works-with-arrays.json (100%) create mode 100644 cypress/fixtures/datashard-snapshot/simple-types/works-with-numbers.json create mode 100644 cypress/fixtures/datashard-snapshot/simple-types/works-with-objects.json create mode 100644 cypress/fixtures/datashard-snapshot/simple-types/works-with-strings.json diff --git a/cypress/fixtures/datashard-snapshot/complex-types/works-based-on-fixtures.json b/cypress/fixtures/datashard-snapshot/complex-types/works-based-on-fixtures.json new file mode 100644 index 0000000..ac6239a --- /dev/null +++ b/cypress/fixtures/datashard-snapshot/complex-types/works-based-on-fixtures.json @@ -0,0 +1,14 @@ +{ + "jsonapi": { + "version": "2.0" + }, + "included": [ + { + "type": "users", + "id": "2", + "attributes": { + "name": "Test" + } + } + ] +} \ No newline at end of file diff --git a/cypress/fixtures/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json b/cypress/fixtures/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json new file mode 100644 index 0000000..0b48984 --- /dev/null +++ b/cypress/fixtures/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json @@ -0,0 +1,15 @@ +{ + "status": 200, + "response": { + "array": [ + 0, + 1, + 2, + "4" + ], + "object": { + "with": "more details" + } + }, + "thisisnew": "wtf" +} \ No newline at end of file diff --git a/undefined/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json b/cypress/fixtures/datashard-snapshot/simple-types/works-with-arrays.json similarity index 100% rename from undefined/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json rename to cypress/fixtures/datashard-snapshot/simple-types/works-with-arrays.json diff --git a/cypress/fixtures/datashard-snapshot/simple-types/works-with-numbers.json b/cypress/fixtures/datashard-snapshot/simple-types/works-with-numbers.json new file mode 100644 index 0000000..7941fc3 --- /dev/null +++ b/cypress/fixtures/datashard-snapshot/simple-types/works-with-numbers.json @@ -0,0 +1,3 @@ +{ + "data": 42 +} \ No newline at end of file diff --git a/cypress/fixtures/datashard-snapshot/simple-types/works-with-objects.json b/cypress/fixtures/datashard-snapshot/simple-types/works-with-objects.json new file mode 100644 index 0000000..c65ca7b --- /dev/null +++ b/cypress/fixtures/datashard-snapshot/simple-types/works-with-objects.json @@ -0,0 +1,4 @@ +{ + "foo": "bar", + "Fizzy Drink": "Pop" +} \ No newline at end of file diff --git a/cypress/fixtures/datashard-snapshot/simple-types/works-with-strings.json b/cypress/fixtures/datashard-snapshot/simple-types/works-with-strings.json new file mode 100644 index 0000000..c36f355 --- /dev/null +++ b/cypress/fixtures/datashard-snapshot/simple-types/works-with-strings.json @@ -0,0 +1,3 @@ +{ + "data": "foo-bar" +} \ No newline at end of file From 8add20790e0899661ec77f37e553ebbc77e4e3e4 Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 11 Apr 2024 18:44:21 +0200 Subject: [PATCH 16/19] forgot a thing --- .../Random-Context/Random-It/Arrays.json | 0 .../Random-Context/Random-It/Numbers.json | 0 .../Random-Context/Random-It/Strings.json | 0 .../complex-types/works-based-on-fixtures.json | 14 -------------- .../works-with-more-complicated-Objects.json | 15 --------------- .../simple-types/works-with-arrays.json | 8 -------- .../simple-types/works-with-numbers.json | 3 --- .../simple-types/works-with-objects.json | 4 ---- .../simple-types/works-with-strings.json | 3 --- 9 files changed, 47 deletions(-) rename cypress/fixtures/{snapshots => }/Random-Describe/Random-Context/Random-It/Arrays.json (100%) rename cypress/fixtures/{snapshots => }/Random-Describe/Random-Context/Random-It/Numbers.json (100%) rename cypress/fixtures/{snapshots => }/Random-Describe/Random-Context/Random-It/Strings.json (100%) delete mode 100644 cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-based-on-fixtures.json delete mode 100644 cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json delete mode 100644 cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json delete mode 100644 cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-numbers.json delete mode 100644 cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-objects.json delete mode 100644 cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-strings.json diff --git a/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Arrays.json b/cypress/fixtures/Random-Describe/Random-Context/Random-It/Arrays.json similarity index 100% rename from cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Arrays.json rename to cypress/fixtures/Random-Describe/Random-Context/Random-It/Arrays.json diff --git a/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Numbers.json b/cypress/fixtures/Random-Describe/Random-Context/Random-It/Numbers.json similarity index 100% rename from cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Numbers.json rename to cypress/fixtures/Random-Describe/Random-Context/Random-It/Numbers.json diff --git a/cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Strings.json b/cypress/fixtures/Random-Describe/Random-Context/Random-It/Strings.json similarity index 100% rename from cypress/fixtures/snapshots/Random-Describe/Random-Context/Random-It/Strings.json rename to cypress/fixtures/Random-Describe/Random-Context/Random-It/Strings.json diff --git a/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-based-on-fixtures.json b/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-based-on-fixtures.json deleted file mode 100644 index ac6239a..0000000 --- a/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-based-on-fixtures.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "jsonapi": { - "version": "2.0" - }, - "included": [ - { - "type": "users", - "id": "2", - "attributes": { - "name": "Test" - } - } - ] -} \ No newline at end of file diff --git a/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json b/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json deleted file mode 100644 index 0b48984..0000000 --- a/cypress/fixtures/snapshots/datashard-snapshot/complex-types/works-with-more-complicated-Objects.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "status": 200, - "response": { - "array": [ - 0, - 1, - 2, - "4" - ], - "object": { - "with": "more details" - } - }, - "thisisnew": "wtf" -} \ No newline at end of file diff --git a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json deleted file mode 100644 index dc8d53f..0000000 --- a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-arrays.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "data": [ - 1, - 2, - 3, - 4 - ] -} \ No newline at end of file diff --git a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-numbers.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-numbers.json deleted file mode 100644 index 7941fc3..0000000 --- a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-numbers.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "data": 42 -} \ No newline at end of file diff --git a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-objects.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-objects.json deleted file mode 100644 index c65ca7b..0000000 --- a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-objects.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "foo": "bar", - "Fizzy Drink": "Pop" -} \ No newline at end of file diff --git a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-strings.json b/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-strings.json deleted file mode 100644 index c36f355..0000000 --- a/cypress/fixtures/snapshots/datashard-snapshot/simple-types/works-with-strings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "data": "foo-bar" -} \ No newline at end of file From a12634c9a3ac30c3622c46b298e495180050d7bd Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 18 Apr 2024 16:39:36 +0200 Subject: [PATCH 17/19] shorten code tiny bit --- src/snapshot.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/snapshot.js b/src/snapshot.js index 6790b0e..99bc50c 100644 --- a/src/snapshot.js +++ b/src/snapshot.js @@ -19,12 +19,12 @@ const pickSerializer = (asJson, value) => { const parseTextToJSON = (text) => text.replace(/\| [✅➖➕⭕]/g, "").trim().replace(/(.*?),\s*(\}|])/g, "$1$2").replace(/},(?!")$/g, "}").replaceAll(/[╺┿╳]/g, "") -const store_snapshot = (props = { value, name, raiser }) => { +const store_snapshot = ({ value, name, raiser } = { value, name, raiser }) => { if (Cypress.env().updateSnapshots || Cypress.config('snapshot').updateSnapshots) { cy.SNAPSHOT_prettyprint({ title: "INFO", type: "info", message: "Saving Snapshot" }) - cy.writeFile(path.join(Cypress.config().fixturesFolder,`${props.name}.json`), JSON.stringify(props.value, null, 2)) + cy.writeFile(path.join(Cypress.config().fixturesFolder, `${name}.json`), JSON.stringify(value, null, 2)) } else { - cy.fixture(props.name).then(content => props.raiser({ value: props.value, expected: content })) + cy.fixture(name).then(expected => raiser({ value, expected })) } }; @@ -38,10 +38,9 @@ const set_snapshot = ({ snapshotName, serialized, value }) => { name: "snapshot", message: snapshotName, consoleProps: () => { return devToolsLog }, + ...(value && { $el: value }) }; - if (value) options.$el = value; - const raiser = ({ value, expected }) => { const result = compareValues({ expected, value }); if ((!Cypress.env().updateSnapshots || !Cypress.config('snapshot').updateSnapshots) && !result.success) { From 71fe145047203777b25b085f6d20606934471d28 Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 25 Apr 2024 13:01:00 +0200 Subject: [PATCH 18/19] Expand Readme, remove Gleb, up version number --- .github/assets/Correct.png | Bin 0 -> 9263 bytes .github/assets/Error.png | Bin 0 -> 14862 bytes .npmignore | 3 ++- .vscode/settings.json | 2 -- README.md | 16 ++++++++++------ package.json | 10 +++++----- 6 files changed, 17 insertions(+), 14 deletions(-) create mode 100644 .github/assets/Correct.png create mode 100644 .github/assets/Error.png delete mode 100644 .vscode/settings.json diff --git a/.github/assets/Correct.png b/.github/assets/Correct.png new file mode 100644 index 0000000000000000000000000000000000000000..4e9366785117a821c7b211e7fc8a437ed4d076ae GIT binary patch literal 9263 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 literal 0 HcmV?d00001 diff --git a/.github/assets/Error.png b/.github/assets/Error.png new file mode 100644 index 0000000000000000000000000000000000000000..5ee573ea1a2d012b12fa33a6ae5c5fa92fbc6d5b GIT binary patch literal 14862 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 literal 0 HcmV?d00001 diff --git a/.npmignore b/.npmignore index 16a2599..6aed89d 100644 --- a/.npmignore +++ b/.npmignore @@ -1,3 +1,4 @@ cypress/ cypress.config.js -.github/workflows/ \ No newline at end of file +.github/workflows/ +.vscode/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 7a73a41..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} \ No newline at end of file diff --git a/README.md b/README.md index bf020e6..7e36e12 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,9 @@ Alternatively, you can also add `snapshotUpdate` as an Environment Variable to u Simply pass `--env updateSnapshots=true` when running Cypress. -> If you don't use the default fixture folder, you will also need to add `snapshotPath` to this module's config with the same path you use for `fixtureFolder`. - ## Usage -If properly added, usage of this plugin is rather simple, simply add `.snapshot()` to cypress functions that return valid JSON. +If properly added, usage of this plugin is rather simple, just add `.snapshot()` to cypress functions that return valid JSON. (i.e. `cy.wrap`) ### Example ```js @@ -64,16 +62,22 @@ cypress/fixtures/snapshots/my-tests/works/bar.json ``` -Snapshots will generally be saved using this convention, provided by Cypress: +Snapshots will generally be saved using this convention, provided by the Cypress Test Steps: +Passing a name to the Snapshot function is required, but not checked, if you want to take multiple snapshots in the same block. +If you have two Snapshots in the same Block, the last one ***WILL*** overwrite the previous one while updating and the then updated Test will fail on the first snapshot. ``` {fixtureFolder}/---.json {fixtureFolder}////.json ``` -If a step wasn't named, it will instead use the ``for the file name, though this means that you will not be able to have more than 1 Snapshot in your It Block, as it would overwrite the previously created Snapshot files. +While running your Tests, if a value changed, it will, of course, no longer match the snapshot and throw an Error. + +Which looks like this: -Of course, if a value changed, it will no longer match the snapshot and throw an Error. ![](./.github/assets/Error.png) +When the Test succeeds, it will instead log a Success in the Log and let you know where the File has been saved to, relative to the Fixture Snapshot Folder + +![](./.github/assets/Correct.png) diff --git a/package.json b/package.json index e66eac3..d94f1ce 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "@datashard/snapshot", - "description": "Adds value / object / DOM element snapshot testing support to Cypress test runner", - "version": "2.3.2", - "author": "Joshua , Gleb Bahmutov ", + "description": "Adds JSON Snapshot testing support to Cypress", + "version": "3.0.0-beta", + "author": "Joshua ", "bugs": "https://github.com/datashard/snapshot/issues", "engines": { "node": ">=6" @@ -13,13 +13,13 @@ "src/*/**", "!src/*-spec.js" ], - "homepage": "https://github.com/datashard/snapshot#readme", + "homepage": "https://shard.wtf/snapshot", "keywords": [ "cypress", "cypress-io", "plugin", "snapshot", - "testing" + "testing", "json" ], "license": "MIT", "main": "src/index.js", From e4f9cbc5cfa786e697843e89d0ed5413b62152de Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 25 Apr 2024 14:09:41 +0200 Subject: [PATCH 19/19] finish most writings --- .npmignore | 3 ++- LICENSE | 2 +- README.md | 55 +++++++++++++++++++++++++++++++----------------------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/.npmignore b/.npmignore index 6aed89d..76237e1 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,5 @@ cypress/ cypress.config.js .github/workflows/ -.vscode/ \ No newline at end of file +.vscode/ +renovate.json \ No newline at end of file diff --git a/LICENSE b/LICENSE index 2c12d72..b22f0b8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2023-2024 Joshua <data@shard.wtf> +Copyright (c) 2023-2024 Joshua data@shard.wtf Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/README.md b/README.md index 7e36e12..6aaec3f 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,19 @@ # @datashard/snapshot -> Adds support for Value, Object, and Dom Element Snapshot Testing to Cypress +> Adds JSON Snapshot comparison to Cypress -## Breaking Changes -> [!WARNING] -The `readFileMaybe` task was required in previous Versions, this has been changed so this Module now uses the `cy.fixture` Command to get the contents of existing files. This means that this module will only be able to write new tests if `updateSnapshots` (previously `SNAPSHOT_UPDATE`) is set to true through Environment Variables or through the Cypress config. -\ -This also means, that previous tests will likely be broken, *please make sure that your tests pass before updating to the latest version of this module* +## ⚠️ Breaking Changes ⚠️ + +- With V3, the `readFileMaybe` task has been removed, we now rely on `cy.fixture` internally. +- the previous `SNAPSHOT_UPDATE` Environment/Config Variable has been changed to `updateSnapshots` + +> [!DANGER] +This means that previous tests will likely be broken, *please make sure that your tests pass before updating to the latest version of this Plugin*. + +This current release will be released as `3.0.0-beta`, should Bugs be found by me or my Employer, I will open Issues/PRs to fix those, should anyone else find Bugs/Edgecases, etc. please open an Issue. ## Install + Requires Node 16 or above ```sh @@ -16,20 +21,22 @@ npm i --save-dev @datashard/snapshot ``` ## Import + After Installing, you'll need to add the following import into your Commands/Support File + > by default this will be `cypress/support/e2e.js` ```js require('@datashard/snapshot').regsiter() ``` -This will register a new Command `.snapshot()`, to create new Snapshots and once created, to compare their Values. +This will register a new Command `.snapshot()`, to create and compare JSON Snapshots. ## Config + You can pass `updateSnapshots` and `useFolders` as options in the `cypress.config.js` file ![Example Settings for the Module](./.github/assets/config.png) - Alternatively, you can also add `snapshotUpdate` as an Environment Variable to update your snapshots. Simply pass `--env updateSnapshots=true` when running Cypress. @@ -38,9 +45,12 @@ Simply pass `--env updateSnapshots=true` when running Cypress. If properly added, usage of this plugin is rather simple, just add `.snapshot()` to cypress functions that return valid JSON. (i.e. `cy.wrap`) +When properly added, you can chain `.snapshot()` off of `cy` functions like `cy.wrap`, just make sure they return valid JSON. + ### Example + ```js -describe("my tests", () => { +describe("my test", () => { it("works", () => { cy.log("first snapshot"); cy.wrap({ foo: 42 }).snapshot("foo"); @@ -50,31 +60,30 @@ describe("my tests", () => { }); ``` -Depending on your settings, this module will then save your snapshots as +This Plugin will then save your snapshots as + ```ts // useFolders: false -cypress/fixtures/snapshots/my-tests__works__foo.json -cypress/fixtures/snapshots/my-tests__works__bar.json +cypress/fixtures/my-test__works__foo.json +cypress/fixtures/my-test__works__bar.json // useFolders: true -cypress/fixtures/snapshots/my-tests/works/foo.json -cypress/fixtures/snapshots/my-tests/works/bar.json +cypress/fixtures/my-test/works/foo.json +cypress/fixtures/my-test/works/bar.json + +// {fixtureFolder}/---.json +// {fixtureFolder}////.json ``` -Snapshots will generally be saved using this convention, provided by the Cypress Test Steps: +Snapshots will generally be saved using this the Convention mentioned in the Comment of the above Codeblock, which is provided by the named Cypress Test Steps. + Passing a name to the Snapshot function is required, but not checked, if you want to take multiple snapshots in the same block. -If you have two Snapshots in the same Block, the last one ***WILL*** overwrite the previous one while updating and the then updated Test will fail on the first snapshot. -``` -{fixtureFolder}/---.json -{fixtureFolder}////.json -``` - - +If you have two or more Snapshots in the same Block, the next one ***WILL*** always overwrite the previous one while updating, causing the First Snapshot in the Block to Fail. While running your Tests, if a value changed, it will, of course, no longer match the snapshot and throw an Error. -Which looks like this: +Which will look like this: ![](./.github/assets/Error.png)