This commit is contained in:
Joshua 2023-02-20 19:17:38 +01:00
parent 6e0b81a522
commit af82f108ad
31 changed files with 11056 additions and 11198 deletions

View file

@ -1,12 +1,12 @@
{ {
"extends": [ "extends": [
"plugin:cypress-dev/general" "plugin:cypress-dev/general"
], ],
"rules": { "rules": {
"comma-dangle": "off", "comma-dangle": "off",
"no-debugger": "warn" "no-debugger": "warn"
}, },
"env": { "env": {
"node": true "node": true
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

8
.gitignore vendored
View file

@ -1,4 +1,4 @@
node_modules/ node_modules/
.DS_Store .DS_Store
npm-debug.log npm-debug.log
cypress/videos/ cypress/videos/

8
.npmrc
View file

@ -1,4 +1,4 @@
registry=http://registry.npmjs.org/ registry=http://registry.npmjs.org/
save-exact=true save-exact=true
progress=false progress=false
package-lock=true package-lock=true

View file

@ -1,16 +1,16 @@
language: node_js language: node_js
notifications: notifications:
email: true email: true
node_js: node_js:
- 10 - 10
# Retry install on fail to avoid failing a build on network/disk/external errors # Retry install on fail to avoid failing a build on network/disk/external errors
install: install:
- travis_retry npm ci - travis_retry npm ci
script: script:
- npm run test - npm run test
- npm run cypress:run - npm run cypress:run
after_success: after_success:
- npm run semantic-release - npm run semantic-release

View file

@ -1,7 +0,0 @@
{
"standard.enable": false,
"eslint.enable": true,
"eslint.autoFixOnSave": false,
"git.ignoreLimitWarning": true,
"standard.autoFixOnSave": false
}

336
README.md
View file

@ -1,168 +1,168 @@
# @cypress/snapshot # @cypress/snapshot
> Adds value / object / DOM element snapshot testing support to Cypress test runner > Adds value / object / DOM element snapshot testing support to Cypress test runner
[![NPM][npm-icon] ][npm-url] [![NPM][npm-icon] ][npm-url]
[![Build status][ci-image] ][ci-url] [![Build status][ci-image] ][ci-url]
[![semantic-release][semantic-image] ][semantic-url] [![semantic-release][semantic-image] ][semantic-url]
[![renovate-app badge][renovate-badge]][renovate-app] [![renovate-app badge][renovate-badge]][renovate-app]
> **Note** \ > **Note** \
> \ > \
> Please take a look at a few other Cypress snapshot plugins: > Please take a look at a few other Cypress snapshot plugins:
> >
> - [cypress-plugin-snapshots](https://github.com/meinaart/cypress-plugin-snapshots) > - [cypress-plugin-snapshots](https://github.com/meinaart/cypress-plugin-snapshots)
> - [cypress-image-snapshot](https://github.com/palmerhq/cypress-image-snapshot). > - [cypress-image-snapshot](https://github.com/palmerhq/cypress-image-snapshot).
## Install ## Install
Requires [Node](https://nodejs.org/en/) version 10 or above. Requires [Node](https://nodejs.org/en/) version 10 or above.
```sh ```sh
npm install --save-dev @cypress/snapshot npm install --save-dev @cypress/snapshot
``` ```
## Import ## Import
After installing, add the following to your `cypress/support/commands.js` file After installing, add the following to your `cypress/support/commands.js` file
```js ```js
require("@cypress/snapshot").register(); require("@cypress/snapshot").register();
``` ```
This registers a new command to create new snapshot or compare value to old snapshot This registers a new command to create new snapshot or compare value to old snapshot
and add the following to your `cypress.config.js` and add the following to your `cypress.config.js`
```js ```js
e2e: { e2e: {
setupNodeEvents(on, config) { setupNodeEvents(on, config) {
require("@cypress/snapshot").tasks(on, config) require("@cypress/snapshot").tasks(on, config)
}, },
``` ```
**Note:** `@cypress/snapshot` **requires** the `readFileMaybe` plugin to be included, which can be easily done using the code above **Note:** `@cypress/snapshot` **requires** the `readFileMaybe` plugin to be included, which can be easily done using the code above
# Usage # Usage
Currently, if you want to take more than one snapshot, you need to pass a Step Name to prevent overwrites / test failures Currently, if you want to take more than one snapshot, you need to pass a Step Name to prevent overwrites / test failures
```js ```js
describe("my tests", () => { describe("my tests", () => {
it("works", () => { it("works", () => {
cy.log("first snapshot"); cy.log("first snapshot");
cy.wrap({ foo: 42 }).snapshot("foo"); cy.wrap({ foo: 42 }).snapshot("foo");
cy.log("second snapshot"); cy.log("second snapshot");
cy.wrap({ bar: 101 }).snapshot("bar"); cy.wrap({ bar: 101 }).snapshot("bar");
}); });
}); });
``` ```
In the above case, you can find the stored snapshot in their own files, mentioned above them In the above case, you can find the stored snapshot in their own files, mentioned above them
```json ```json
// cypress/snapshots/my-tests-works-foo.json // cypress/snapshots/my-tests-works-foo.json
{"foo": 42} {"foo": 42}
// cypress/snapshots/my-tests-works-bar.json // cypress/snapshots/my-tests-works-bar.json
{"bar": 101} {"bar": 101}
``` ```
If you change the site values, the saved snapshot will no longer match, throwing an error If you change the site values, the saved snapshot will no longer match, throwing an error
( picture taken from `cypress/snapshots/Arrays.json`) ( picture taken from `cypress/snapshots/Arrays.json`)
![Snapshot mismatch](.github/assets/updated-mismatch.png) ![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. Click on the `SNAPSHOT` step in the Command Log to see expected and current value printed in the DevTools.
### Options ### Options
You can control snapshot comparison and behavior through a few options. You can control snapshot comparison and behavior through a few options.
```js ```js
cy.get(...).snapshot({ cy.get(...).snapshot({
snapshotName: 'Snapshot Name', // to use as a File Name snapshotName: 'Snapshot Name', // to use as a File Name
snapshotPath: 'cypress/not_snapshots', // where to save the Snapshot snapshotPath: 'cypress/not_snapshots', // where to save the Snapshot
json: false // convert DOM elements into JSON json: false // convert DOM elements into JSON
}) // when storing in the snapshot file }) // when storing in the snapshot file
// will save as // will save as
// cypress/not_snapshots/Snapshot-Name.json // cypress/not_snapshots/Snapshot-Name.json
``` ```
You can also pass a "Step Name" to the Function You can also pass a "Step Name" to the Function
```js ```js
cy.get(...).snapshot("Intercepted API Request") cy.get(...).snapshot("Intercepted API Request")
// will save as // will save as
// cypress/snapshots/<context>-<describe>-<it>-Intercepted-API-Request.json // cypress/snapshots/<context>-<describe>-<it>-Intercepted-API-Request.json
// to prevent duplications // to prevent duplications
``` ```
or both or both
```js ```js
cy.get(...).snapshot("Intercepted API Request", { cy.get(...).snapshot("Intercepted API Request", {
snapshotPath: "cypress/snapshots/api", snapshotPath: "cypress/snapshots/api",
snapshotName: "first_intercept" snapshotName: "first_intercept"
}) })
// will save as // will save as
// cypress/snapshots/api/first_intercept.json // cypress/snapshots/api/first_intercept.json
``` ```
### Configuration ### Configuration
This module provides some configuration options: This module provides some configuration options:
#### snapshotPath #### snapshotPath
Sets the default Path for saving Snapshots (default: `cypress/snapshots`) Sets the default Path for saving Snapshots (default: `cypress/snapshots`)
## Debugging ## Debugging
To debug this module run with environment variable `DEBUG=@cypress/snapshot` To debug this module run with environment variable `DEBUG=@cypress/snapshot`
# #
### Small print ### Small print
Author: Gleb Bahmutov &lt;gleb@cypress.io&gt; &amp; Joshua D. &lt;[data@shard.wtf](mailto:data@shard.wtf)&gt; &copy; Cypress.io 2017-2022 Author: Gleb Bahmutov &lt;gleb@cypress.io&gt; &amp; Joshua D. &lt;[data@shard.wtf](mailto:data@shard.wtf)&gt; &copy; Cypress.io 2017-2022
<br> <br>
License: MIT - do anything with the code, but don't blame us if it does not work. 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, email / tweet / Support: If you find any problems with this module, email / tweet /
[open issue](https://github.com/cypress-io/snapshot/issues) on Github [open issue](https://github.com/cypress-io/snapshot/issues) on Github
## MIT License ## MIT License
Copyright (c) 2017-2022 Cypress.io &lt;hello@cypress.io&gt; Copyright (c) 2017-2022 Cypress.io &lt;hello@cypress.io&gt;
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following Software is furnished to do so, subject to the following
conditions: conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE. OTHER DEALINGS IN THE SOFTWARE.
[npm-icon]: https://nodei.co/npm/@cypress/snapshot.svg?downloads=true [npm-icon]: https://nodei.co/npm/@cypress/snapshot.svg?downloads=true
[npm-url]: https://npmjs.org/package/@cypress/snapshot [npm-url]: https://npmjs.org/package/@cypress/snapshot
[ci-image]: https://travis-ci.org/cypress-io/snapshot.svg?branch=master [ci-image]: https://travis-ci.org/cypress-io/snapshot.svg?branch=master
[ci-url]: https://travis-ci.org/cypress-io/snapshot [ci-url]: https://travis-ci.org/cypress-io/snapshot
[semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg [semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
[semantic-url]: https://github.com/semantic-release/semantic-release [semantic-url]: https://github.com/semantic-release/semantic-release
[renovate-badge]: https://img.shields.io/badge/renovate-app-blue.svg [renovate-badge]: https://img.shields.io/badge/renovate-app-blue.svg
[renovate-app]: https://renovateapp.com/ [renovate-app]: https://renovateapp.com/

View file

@ -1,27 +1,27 @@
/* eslint-env mocha */ /* eslint-env mocha */
/* global cy */ /* global cy */
describe("Random Describe", () => { describe("Random Describe", () => {
context("Random Context", () => { context("Random Context", () => {
it("Random It", () => { it("Random It", () => {
cy.fixture("File").snapshot("Fixture File", { cy.fixture("File").snapshot("Fixture File", {
humanName: "Random Fixture File" humanName: "Random Fixture File"
}); });
// cy.fixture("File2").snapshot("Fixture File", // cy.fixture("File2").snapshot("Fixture File",
}); });
// it("works with numbers", () => { // it("works with numbers", () => {
// console.log(cy.wrap(42)) // console.log(cy.wrap(42))
// cy.wrap(42).snapshot(); // cy.wrap(42).snapshot();
// }); // });
// it("works with strings", () => { // it("works with strings", () => {
// console.log(cy.wrap("foo-bar")) // console.log(cy.wrap("foo-bar"))
// cy.wrap("foo-bar").snapshot(); // cy.wrap("foo-bar").snapshot();
// }); // });
// it("works with arrays", () => { // it("works with arrays", () => {
// console.log(cy.wrap([1, 2, 3])) // console.log(cy.wrap([1, 2, 3]))
// cy.wrap([1, 2, 3]).snapshot(); // cy.wrap([1, 2, 3]).snapshot();
// }); // });
}); });
}); });

View file

@ -1,33 +1,33 @@
/* eslint-env mocha */ /* eslint-env mocha */
/* global cy */ /* global cy */
describe("@cypress/snapshot", () => { describe("@cypress/snapshot", () => {
context("simple types", () => { context("simple types", () => {
it("works with objects", () => { it("works with objects", () => {
cy.fixture("File2").snapshot({ cy.fixture("File2").snapshot({
snapshotPath: "cypress/snapshots", snapshotPath: "cypress/snapshots",
snapshotName: "Objects", snapshotName: "Objects",
}); });
}); });
it("works with numbers", () => { it("works with numbers", () => {
cy.wrap(42).snapshot({ cy.wrap(42).snapshot({
snapshotPath: "cypress/snapshots", snapshotPath: "cypress/snapshots",
snapshotName: "Numbers", snapshotName: "Numbers",
}); });
}); });
it("works with strings", () => { it("works with strings", () => {
cy.wrap("foo-bar").snapshot({ cy.wrap("foo-bar").snapshot({
snapshotPath: "cypress/snapshots", snapshotPath: "cypress/snapshots",
snapshotName: "Strings", snapshotName: "Strings",
}); });
}); });
it("works with arrays", () => { it("works with arrays", () => {
cy.wrap([1, 2, 3]).snapshot({ cy.wrap([1, 2, 3]).snapshot({
snapshotPath: "cypress/snapshots", snapshotPath: "cypress/snapshots",
snapshotName: "Arrays", snapshotName: "Arrays",
}); });
}); });
}); });
}); });

View file

@ -1,4 +1,4 @@
{ {
"foo": "bar", "foo": "bar",
"Fizzy Drink": "Soda" "Fizzy Drink": "Soda"
} }

View file

@ -1,4 +1,4 @@
{ {
"foo": "bar", "foo": "bar",
"Fizzy Drink": "Pop" "Fizzy Drink": "Pop"
} }

View file

@ -1,17 +1,17 @@
// *********************************************************** // ***********************************************************
// This example plugins/index.js can be used to load plugins // This example plugins/index.js can be used to load plugins
// //
// You can change the location of this file or turn off loading // You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option. // the plugins file with the 'pluginsFile' configuration option.
// //
// You can read more here: // You can read more here:
// https://on.cypress.io/plugins-guide // https://on.cypress.io/plugins-guide
// *********************************************************** // ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to // This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing) // the project's config changing)
module.exports = (on, config) => { module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits // `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config // `config` is the resolved Cypress config
} }

View file

@ -1,2 +1,2 @@
// register .snapshot() command // register .snapshot() command
require('../..').register() require('../..').register()

View file

@ -1,20 +1,20 @@
// *********************************************************** // ***********************************************************
// This example support/index.js is processed and // This example support/index.js is processed and
// loaded automatically before your test files. // loaded automatically before your test files.
// //
// This is a great place to put global configuration and // This is a great place to put global configuration and
// behavior that modifies Cypress. // behavior that modifies Cypress.
// //
// You can change the location of this file or turn off // You can change the location of this file or turn off
// automatically serving support files with the // automatically serving support files with the
// 'supportFile' configuration option. // 'supportFile' configuration option.
// //
// You can read more here: // You can read more here:
// https://on.cypress.io/configuration // https://on.cypress.io/configuration
// *********************************************************** // ***********************************************************
// Import commands.js using ES2015 syntax: // Import commands.js using ES2015 syntax:
import './commands' import './commands'
// Alternatively you can use CommonJS syntax: // Alternatively you can use CommonJS syntax:
// require('./commands') // require('./commands')

View file

@ -1,12 +1,12 @@
Thank you for taking time to open a new issue. Please answer a few questions to help us fix it faster. You can delete text that is irrelevant to the issue. Thank you for taking time to open a new issue. Please answer a few questions to help us fix it faster. You can delete text that is irrelevant to the issue.
## Is this a bug report or a feature request? ## Is this a bug report or a feature request?
If this is a bug report, please provide as much info as possible If this is a bug report, please provide as much info as possible
- version - version
- platform - platform
- expected behavior - expected behavior
- actual behavior - actual behavior
If this is a new feature request, please describe it below If this is a new feature request, please describe it below

20872
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,70 +1,71 @@
{ {
"name": "cypress-snapshot", "name": "cypress-snapshot",
"description": "Adds value / object / DOM element snapshot testing support to Cypress test runner", "description": "Adds value / object / DOM element snapshot testing support to Cypress test runner",
"version": "1.0.0", "version": "1.0.1",
"author": "Gleb Bahmutov <gleb@cypress.io>", "author": "Joshua D. <data@shard.wtf>, Gleb Bahmutov <gleb@cypress.io>",
"bugs": "https://github.com/cypress-io/snapshot/issues", "bugs": "https://github.com/cypress-io/snapshot/issues",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
}, },
"files": [ "files": [
"img", "img",
"src/*.js", "src/*",
"!src/*-spec.js" "src/*/**",
], "!src/*-spec.js"
"homepage": "https://github.com/cypress-io/snapshot#readme", ],
"keywords": [ "homepage": "https://github.com/cypress-io/snapshot#readme",
"cypress", "keywords": [
"cypress-io", "cypress",
"plugin", "cypress-io",
"snapshot", "plugin",
"testing" "snapshot",
], "testing"
"license": "MIT", ],
"main": "src/", "license": "MIT",
"private": false, "main": "src/index.js",
"publishConfig": { "private": false,
"registry": "http://registry.npmjs.org/" "publishConfig": {
}, "registry": "https://pkgs.dev.azure.com/CPCorporatePlanningAG/_packaging/webclient/npm/registry/"
"repository": { },
"type": "git", "repository": {
"url": "https://github.com/cypress-io/snapshot.git" "type": "git",
}, "url": "https://github.com/cypress-io/snapshot.git"
"scripts": { },
"ban": "ban", "scripts": {
"deps": "deps-ok && dependency-check --no-dev .", "ban": "ban",
"issues": "git-issues", "deps": "deps-ok && dependency-check --no-dev .",
"license": "license-checker --production --onlyunknown --csv", "issues": "git-issues",
"lint": "eslint --fix src/*.js", "license": "license-checker --production --onlyunknown --csv",
"pretest": "npm run lint", "lint": "eslint --fix src/*.js",
"size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";", "pretest": "npm run lint",
"test": "npm run unit", "size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";",
"unit": "mocha src/*-spec.js", "test": "npm run unit",
"unused-deps": "dependency-check --unused --no-dev . --entry src/add-initial-snapshot-file.js", "unit": "mocha src/*-spec.js",
"postinstall": "echo 'no postinstall script'", "unused-deps": "dependency-check --unused --no-dev . --entry src/add-initial-snapshot-file.js",
"semantic-release": "semantic-release", "postinstall": "echo 'no postinstall script'",
"cypress:open": "cypress open", "semantic-release": "semantic-release",
"cypress:run": "cypress run" "cypress:open": "cypress open",
}, "cypress:run": "cypress run"
"devDependencies": { },
"ban-sensitive-files": "1.9.15", "devDependencies": {
"cypress": "10.6.0", "ban-sensitive-files": "1.9.15",
"debug": "3.2.7", "cypress": "10.6.0",
"dependency-check": "2.10.1", "debug": "3.2.7",
"deps-ok": "1.4.1", "dependency-check": "2.10.1",
"eslint": "4.19.1", "deps-ok": "1.4.1",
"eslint-plugin-cypress-dev": "1.1.2", "eslint": "4.19.1",
"git-issues": "1.3.1", "eslint-plugin-cypress-dev": "1.1.2",
"license-checker": "15.0.0", "git-issues": "1.3.1",
"mocha": "6.2.3", "license-checker": "15.0.0",
"semantic-release": "17.4.3" "mocha": "6.2.3",
}, "semantic-release": "17.4.3"
"dependencies": { },
"@wildpeaks/snapshot-dom": "1.6.0", "dependencies": {
"check-more-types": "2.24.0", "@wildpeaks/snapshot-dom": "1.6.0",
"js-beautify": "1.13.13", "check-more-types": "2.24.0",
"lazy-ass": "1.6.0", "js-beautify": "1.13.13",
"snap-shot-compare": "3.0.0", "lazy-ass": "1.6.0",
"snap-shot-store": "1.2.3" "snap-shot-compare": "3.0.0",
} "snap-shot-store": "1.2.3"
} }
}

View file

@ -1,24 +1,24 @@
{ {
"extends": [ "extends": [
"config:base" "config:base"
], ],
"automerge": true, "automerge": true,
"major": { "major": {
"automerge": false "automerge": false
}, },
"updateNotScheduled": false, "updateNotScheduled": false,
"timezone": "America/New_York", "timezone": "America/New_York",
"schedule": [ "schedule": [
"every weekend" "every weekend"
], ],
"lockFileMaintenance": { "lockFileMaintenance": {
"enabled": true "enabled": true
}, },
"separatePatchReleases": true, "separatePatchReleases": true,
"separateMultipleMajor": true, "separateMultipleMajor": true,
"masterIssue": true, "masterIssue": true,
"labels": [ "labels": [
"type: dependencies", "type: dependencies",
"renovate" "renovate"
] ]
} }

View file

@ -1,10 +1,10 @@
'use strict' 'use strict'
// global cy, Cypress // global cy, Cypress
const { functions } = require('./utils/index') const { functions } = require('./utils/index')
module.exports = { module.exports = {
register: functions.register, register: functions.register,
tasks: functions.tasks tasks: functions.tasks
} }

View file

@ -1,16 +1,16 @@
'use strict' 'use strict'
/* eslint-env mocha */ /* eslint-env mocha */
const api = require('.') const api = require('.')
const la = require('lazy-ass') const la = require('lazy-ass')
const is = require('check-more-types') const is = require('check-more-types')
describe('@cypress/snapshot', () => { describe('@cypress/snapshot', () => {
it('is an object', () => { it('is an object', () => {
la(is.object(api)) la(is.object(api))
}) })
it('has register', () => { it('has register', () => {
la(is.fn(api.register)) la(is.fn(api.register))
}) })
}) })

View file

@ -1,5 +1,5 @@
const readFileMaybe = require("../tasks/readFileMaybe"); const readFileMaybe = require("../tasks/readFileMaybe");
module.exports = (on, config) => { module.exports = (on, config) => {
on("task", { readFileMaybe }); on("task", { readFileMaybe });
}; };

View file

@ -1,13 +1,13 @@
const lazy = require("lazy-ass"); const lazy = require("lazy-ass");
const is = require("check-more-types"); const is = require("check-more-types");
const snapshot = require("../snapshots/snapshot"); const snapshot = require("../snapshots/snapshot");
module.exports = () => { module.exports = () => {
lazy(is.fn(global.before), "Missing global before function"); lazy(is.fn(global.before), "Missing global before function");
lazy(is.fn(global.after), "Missing global after function"); lazy(is.fn(global.after), "Missing global after function");
lazy(is.object(global.Cypress), "Missing Cypress object"); lazy(is.object(global.Cypress), "Missing Cypress object");
Cypress.Commands.add("snapshot", { prevSubject: true }, snapshot); Cypress.Commands.add("snapshot", { prevSubject: true }, snapshot);
return snapshot; return snapshot;
}; };

View file

@ -1,28 +1,28 @@
const serializeToHTML = require("./serializers/serializeToHTML"); const serializeToHTML = require("./serializers/serializeToHTML");
const serializeDomElement = require("./serializers/serializeDomElement"); const serializeDomElement = require("./serializers/serializeDomElement");
const compareValues = require("./snapshots/compareValues"); const compareValues = require("./snapshots/compareValues");
const readFileMaybe = require("./tasks/readFileMaybe"); const readFileMaybe = require("./tasks/readFileMaybe");
const identity = (x) => x; const identity = (x) => x;
const publicProps = (name) => !name.startsWith("__"); const publicProps = (name) => !name.startsWith("__");
const countSnapshots = (snapshots) => const countSnapshots = (snapshots) =>
Object.keys(snapshots).filter(publicProps).length; Object.keys(snapshots).filter(publicProps).length;
module.exports = { module.exports = {
serializers: { serializers: {
serializeDomElement, serializeDomElement,
serializeToHTML, serializeToHTML,
identity, identity,
countSnapshots, countSnapshots,
}, },
snapshots: { snapshots: {
compareValues, compareValues,
}, },
functions: { functions: {
register: require("./functions/register"), register: require("./functions/register"),
tasks: require("./functions/addTasks") tasks: require("./functions/addTasks")
}, },
tasks: { tasks: {
readFileMaybe readFileMaybe
}, },
}; };

View file

@ -1,16 +1,16 @@
// remove React and Angular ids, which are transient // remove React and Angular ids, which are transient
module.exports = function deleteTransientIdsFromJson(json) { module.exports = function deleteTransientIdsFromJson(json) {
if (json.attributes) { if (json.attributes) {
delete json.attributes["data-reactid"]; delete json.attributes["data-reactid"];
Object.keys(json.attributes) Object.keys(json.attributes)
.filter((key) => key.startsWith("_ng")) .filter((key) => key.startsWith("_ng"))
.forEach((attr) => delete json.attributes[attr]); .forEach((attr) => delete json.attributes[attr]);
delete json.attributes[""]; delete json.attributes[""];
} }
if (Array.isArray(json.childNodes)) { if (Array.isArray(json.childNodes)) {
json.childNodes.forEach(deleteTransientIdsFromJson); json.childNodes.forEach(deleteTransientIdsFromJson);
} }
return json; return json;
}; };

View file

@ -1,16 +1,16 @@
const sd = require("@wildpeaks/snapshot-dom"); const sd = require("@wildpeaks/snapshot-dom");
const deleteTransientIdsFromJson = require("./deleteTransientIdsFromJson"); const deleteTransientIdsFromJson = require("./deleteTransientIdsFromJson");
// converts DOM element to a JSON object // converts DOM element to a JSON object
module.exports = function serializeDomElement($el) { module.exports = function serializeDomElement($el) {
// console.log('snapshot value!', $el) // console.log('snapshot value!', $el)
const json = sd.toJSON($el[0]); const json = sd.toJSON($el[0]);
// console.log('as json', json) // console.log('as json', json)
// hmm, why is value not serialized? // hmm, why is value not serialized?
if ($el.context.value && !json.attributes.value) { if ($el.context.value && !json.attributes.value) {
json.attributes.value = $el.context.value; json.attributes.value = $el.context.value;
} }
return deleteTransientIdsFromJson(json); return deleteTransientIdsFromJson(json);
}; };

View file

@ -1,16 +1,16 @@
const stripTransientIdAttributes = require("./stripTransientIdAttributes"); const stripTransientIdAttributes = require("./stripTransientIdAttributes");
const beautify = require("js-beautify").html; const beautify = require("js-beautify").html;
module.exports = (el$) => { module.exports = (el$) => {
const html = el$[0].outerHTML; const html = el$[0].outerHTML;
const stripped = stripTransientIdAttributes(html); const stripped = stripTransientIdAttributes(html);
const options = { const options = {
wrap_line_length: 80, wrap_line_length: 80,
indent_inner_html: true, indent_inner_html: true,
indent_size: 2, indent_size: 2,
wrap_attributes: "force", wrap_attributes: "force",
}; };
const pretty = beautify(stripped, options); const pretty = beautify(stripped, options);
return pretty; return pretty;
}; };

View file

@ -1,5 +1,5 @@
module.exports = (html) => { module.exports = (html) => {
const dataReactId = /data\-reactid="[\.\d\$\-abcdfef]+"/g; const dataReactId = /data\-reactid="[\.\d\$\-abcdfef]+"/g;
const angularId = /_ng(content|host)\-[0-9a-z-]+(="")?/g; const angularId = /_ng(content|host)\-[0-9a-z-]+(="")?/g;
return html.replace(dataReactId, "").replace(angularId, ""); return html.replace(dataReactId, "").replace(angularId, "");
}; };

View file

@ -1,6 +1,6 @@
const compare = require("snap-shot-compare"); const compare = require("snap-shot-compare");
module.exports = function compareValues({ expected, value }) { module.exports = function compareValues({ expected, value }) {
const noColor = false; const noColor = false;
const json = true; const json = true;
return compare({ expected, value, noColor, json }); return compare({ expected, value, noColor, json });
}; };

View file

@ -1,130 +1,130 @@
const serializeDomElement = require("../serializers/serializeDomElement"); const serializeDomElement = require("../serializers/serializeDomElement");
const serializeToHTML = require("../serializers/serializeToHTML"); const serializeToHTML = require("../serializers/serializeToHTML");
const compareValues = require("./compareValues"); const compareValues = require("./compareValues");
const { initStore } = require("snap-shot-store"); const { initStore } = require("snap-shot-store");
const path = require("path"); const path = require("path");
const identity = (x) => x; const identity = (x) => x;
const pickSerializer = (asJson, value) => { const pickSerializer = (asJson, value) => {
if (Cypress.dom.isJquery(value)) { if (Cypress.dom.isJquery(value)) {
return asJson ? serializeDomElement : serializeToHTML; return asJson ? serializeDomElement : serializeToHTML;
} }
return identity; return identity;
}; };
let counters = {}; let counters = {};
const newStore = (name) => { const newStore = (name) => {
return initStore(name); return initStore(name);
}; };
const get_snapshot_key = (key) => { const get_snapshot_key = (key) => {
if (key in counters) { if (key in counters) {
// eslint-disable-next-line immutable/no-mutation // eslint-disable-next-line immutable/no-mutation
counters[key] += 1; counters[key] += 1;
} else { } else {
// eslint-disable-next-line immutable/no-mutation // eslint-disable-next-line immutable/no-mutation
counters[key] = 1; counters[key] = 1;
} }
return counters[key]; return counters[key];
}; };
const store_snapshot = (store, props = { value, name, path, raiser }) => { const store_snapshot = (store, props = { value, name, path, raiser }) => {
const fileName = props.name const fileName = props.name
.join("_") .join("_")
.replace(/ /gi, "-") .replace(/ /gi, "-")
.replace(/\//gi, "-"); .replace(/\//gi, "-");
const snapshotPath = const snapshotPath =
props.path || props.path ||
Cypress.config("snapshot").snapshotPath || Cypress.config("snapshot").snapshotPath ||
"cypress/snapshots"; "cypress/snapshots";
const expectedPath = path.join(snapshotPath, `${fileName}.json`); const expectedPath = path.join(snapshotPath, `${fileName}.json`);
cy.task("readFileMaybe", expectedPath).then((exist) => { cy.task("readFileMaybe", expectedPath).then((exist) => {
if (exist) { if (exist) {
props.raiser({ value: props.value, expected: JSON.parse(exist) }); props.raiser({ value: props.value, expected: JSON.parse(exist) });
} else { } else {
cy.writeFile(expectedPath, JSON.stringify(props.value)); cy.writeFile(expectedPath, JSON.stringify(props.value));
} }
}); });
}; };
const set_snapshot = ( const set_snapshot = (
store, store,
{ snapshotName, snapshotPath, serialized, value } { snapshotName, snapshotPath, serialized, value }
) => { ) => {
if (!store) return; if (!store) return;
const message = Cypress._.last(snapshotName); const message = Cypress._.last(snapshotName);
console.log("Current Snapshot name", snapshotName); console.log("Current Snapshot name", snapshotName);
const devToolsLog = { $el: serialized }; const devToolsLog = { $el: serialized };
if (Cypress.dom.isJquery(value)) { if (Cypress.dom.isJquery(value)) {
devToolsLog.$el = value; devToolsLog.$el = value;
} }
const options = { const options = {
name: "snapshot", name: "snapshot",
message, message,
consoleProps: () => devToolsLog, consoleProps: () => devToolsLog,
}; };
if (value) options.$el = value; if (value) options.$el = value;
const raiser = ({ value, expected }) => { const raiser = ({ value, expected }) => {
const result = compareValues({ expected, value }); const result = compareValues({ expected, value });
result.orElse((json) => { result.orElse((json) => {
devToolsLog.message = json.message; devToolsLog.message = json.message;
devToolsLog.expected = expected; devToolsLog.expected = expected;
delete devToolsLog.value; delete devToolsLog.value;
devToolsLog.value = value; devToolsLog.value = value;
throw new Error( throw new Error(
`Snapshot Difference. To update, delete snapshot file and rerun test.\n${json.message}` `Snapshot Difference. To update, delete snapshot file and rerun test.\n${json.message}`
); );
}); });
}; };
Cypress.log(options); Cypress.log(options);
store_snapshot(store, { store_snapshot(store, {
value, value,
name: snapshotName, name: snapshotName,
path: snapshotPath, path: snapshotPath,
raiser, raiser,
}); });
}; };
const get_test_name = (test) => test.titlePath; const get_test_name = (test) => test.titlePath;
const get_snapshot_name = (test, custom_name) => { const get_snapshot_name = (test, custom_name) => {
const names = get_test_name(test); const names = get_test_name(test);
const index = custom_name; const index = custom_name;
names.push(String(index)); names.push(String(index));
if (custom_name) return [custom_name]; if (custom_name) return [custom_name];
return names; return names;
}; };
module.exports = (value, step, options) => { module.exports = (value, step, options) => {
if (typeof step === "object") options = step; if (typeof step === "object") options = step;
if (typeof value !== "object" || Array.isArray(value)) if (typeof value !== "object" || Array.isArray(value))
value = { data: value }; value = { data: value };
console.log("value", value); console.log("value", value);
const name = get_snapshot_name( const name = get_snapshot_name(
Cypress.currentTest, Cypress.currentTest,
options.snapshotName || step options.snapshotName || step
); );
const serializer = pickSerializer(options.json, value); const serializer = pickSerializer(options.json, value);
const serialized = serializer(value); const serialized = serializer(value);
const store = newStore(serialized || {}); const store = newStore(serialized || {});
console.log({ step, options }); console.log({ step, options });
set_snapshot(store, { set_snapshot(store, {
snapshotName: name, snapshotName: name,
snapshotPath: options.snapshotPath, snapshotPath: options.snapshotPath,
serialized, serialized,
value, value,
}); });
}; };

View file

@ -1,9 +1,9 @@
const fs = require("fs"); const fs = require("fs");
module.exports = (filename) => { module.exports = (filename) => {
if (fs.existsSync(filename)) { if (fs.existsSync(filename)) {
return fs.readFileSync(filename, "utf8"); return fs.readFileSync(filename, "utf8");
} }
return false; return false;
}; };