Skip to content

Commit

Permalink
To match image snapshot (#7)
Browse files Browse the repository at this point in the history
* Add `toMatchImageSnapshot` command

* Made creating "diff image" optional by adding `createDiffImage` to `imageConfig`

* Fix `toMatchImageSnapshot` tests

* Add automatic resizing for high DPI (Retina screens)

* Fix unpublished `[email protected]` package

* Fix tests on Travis

* Fix imageConfig is undefined and move `resizeImage` to seperate file

* Fix sharp

* Travis: trying to use internal travis GCC

* Use Jimp

* Fix jest test

* Remove exploited event-stream version

* Run tests in Chrome

* Increase threshold to see if this fixes it on Travis
  • Loading branch information
meinaart authored Dec 1, 2018
1 parent 068a491 commit 31fd4a5
Show file tree
Hide file tree
Showing 73 changed files with 4,654 additions and 1,641 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.DS_Store
node_modules
/cypress/cypress/screenshots
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ cache:
- npm run cy:verify
notifications:
email: false
addons:
chrome: stable
install:
- npm ci
- npm --prefix cypress ci
Expand Down
49 changes: 42 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
## Installation
`npm i cypress-plugin-snapshots -S`

## Usage
## Usage for text snapshots
```javascript
describe('data test', () => {
it('toMatchSnapshot - JSON', () => {
Expand Down Expand Up @@ -52,14 +52,43 @@ You can pass the following options to `toMatchSnapshot` to override default beha
Use `replace` with caution. Tests should be deterministic. It's often a better solution to influence your
test result instead of your snapshot (by mocking data for example).

## Config Cypress.io
## Usage for image snapshots
```javascript
it('toMatchImageSnapshot - element', () => {
cy.visit('/static/stub.html')
.then(() => {
cy.get('[data-test=test]')
.toMatchImageSnapshot();
});
});

it('toMatchImageSnapshot - whole page', () => {
cy.visit('/static/stub.html')
.then(() => {
cy.document()
.toMatchImageSnapshot();
});
});
```

You can pass the following options to `toMatchImageSnapshot` to override default behavior.
```javascript
{
"createDiffImage": true, // Should a "diff image" be created, can be disabled for performance
"threshold": 0.01, // Amount in pixels or percentage before snapshot image is invalid
"thresholdType": "percent" // Can be either "pixels" or "percent"
}
```

## Configure Cypress.io
Add this to your `cypress.json` configuration file:
```json
"ignoreTestFiles": [
"**/*.snap",
"**/__snapshot__/*"
"**/__snapshots__/*",
"**/__image_snapshots__/*"
]
```

### Plugin
Find your `cypress/plugins/index.js` file and change it to look like this:

Expand Down Expand Up @@ -95,6 +124,12 @@ Add the configuration below to your `cypress.json` file to make changes to the d
"ignoreExtraFields": false, // Ignore extra fields that are not in `snapshot`
"normalizeJson": true, // Alphabetically sort keys in JSON
"prettier": true, // Enable `prettier` for formatting HTML before comparison
"imageConfig": {
"createDiffImage": true, // Should a "diff image" be created, can be disabled for performance
"resizeDevicePixelRatio": true,// Resize image to base resolution when Cypress is running on high DPI screen, `cypress run` always runs on base resolution
"threshold": 0.01, // Amount in pixels or percentage before snapshot image is invalid
"thresholdType": "percent" // Can be either "pixels" or "percent"
},
"serverEnabled": true, // Enable "update snapshot" server and button in diff modal
"serverHost": "localhost", // Hostname for "update snapshot server"
"serverPort": 2121, // Port number for "update snapshot server"
Expand All @@ -106,12 +141,12 @@ Add the configuration below to your `cypress.json` file to make changes to the d
## Roadmap
Below is a list of functionality that is under consideration for implementing in a next version.

- Fix handling of update snapshot via UI that contains a replacable field
- Fix handling of "update snapshot" button that contains a replacable field
- Fix handling of updating image snapshots
- Resize images before comparison
- Disable "update snapshots" server in headless mode
- Add more unit tests
- Add [JSDoc](http://usejsdoc.org/) documentation
- Consider code coverage tests with [Coveralls](https://coveralls.io/) and [Istanbul](http://gotwarlost.github.io/istanbul/)
- Consider implementing visual snapshots with [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot)

## Contributing
In lieu of a formal styleguide, take care to maintain the existing coding style.
Expand Down
15 changes: 7 additions & 8 deletions __tests__/commands.test.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
const { initCommands } = require('../commands');

global.Cypress = {
env: () => {},
env: () => ({}),
config: () => {},
Commands: {
add: jest.fn(),
},
Commands: { add: jest.fn(), },
on: () => ({}),
};

global.cy = {};

describe('command', () => {
it('should create command', () => {
describe('commands', () => {
it('initCommands', () => {
global.before = jest.fn();
global.after = jest.fn();
global.cy.task = jest.fn().mockResolvedValue({ passed: true });

initCommands();
global.cy.task = jest.fn().mockResolvedValue({ pass: true });

expect(global.Cypress.Commands.add).toBeCalled();
expect(global.Cypress.Commands.add.mock.calls.length).toEqual(1);
expect(global.Cypress.Commands.add.mock.calls.length).toEqual(2);
expect(global.Cypress.Commands.add.mock.calls[0][0]).toEqual('toMatchSnapshot');
expect(global.after).toBeCalled();
expect(global.before).toBeCalled();
Expand Down
7 changes: 4 additions & 3 deletions __tests__/plugin.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const configModule = require('../config');
/* eslint no-template-curly-in-string: 0 */
const configModule = require('../src/config');

jest.mock("../config.js");
jest.mock("../src/config.js");

jest.spyOn(configModule, 'initConfig')
.mockImplementation((config) => config);
Expand Down Expand Up @@ -31,6 +32,6 @@ describe('plugin', () => {
const { initPlugin } = require('../plugin');

initPlugin(on, globalConfig);
expect(on).toBeCalledTimes(1);
expect(on).toBeCalledTimes(2);
});
});
19 changes: 0 additions & 19 deletions __tests__/tasks/snapshots.test.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`utils/snapshot keepKeysFromExpected ignoreExtraFields: false, ignoreExtraArrayItems: false 1`] = `
exports[`utils/keepKeysFromExpected ignoreExtraFields: false, ignoreExtraArrayItems: false 1`] = `
Object {
"extra": "extra",
"field": "value",
Expand Down Expand Up @@ -31,7 +31,7 @@ Object {
}
`;

exports[`utils/snapshot keepKeysFromExpected ignoreExtraFields: false, ignoreExtraArrayItems: true 1`] = `
exports[`utils/keepKeysFromExpected ignoreExtraFields: false, ignoreExtraArrayItems: true 1`] = `
Object {
"extra": "extra",
"field": "value",
Expand All @@ -55,7 +55,7 @@ Object {
}
`;

exports[`utils/snapshot keepKeysFromExpected ignoreExtraFields: true, ignoreExtraArrayItems: false 1`] = `
exports[`utils/keepKeysFromExpected ignoreExtraFields: true, ignoreExtraArrayItems: false 1`] = `
Object {
"field": "value",
"items": Array [
Expand Down Expand Up @@ -84,7 +84,7 @@ Object {
}
`;

exports[`utils/snapshot keepKeysFromExpected ignoreExtraFields: true, ignoreExtraArrayItems: true 1`] = `
exports[`utils/keepKeysFromExpected ignoreExtraFields: true, ignoreExtraArrayItems: true 1`] = `
Object {
"field": "value",
"items": Array [
Expand All @@ -105,18 +105,3 @@ Object {
],
}
`;

exports[`utils/snapshot subjectToSnapshot normalizes 1`] = `
Object {
"bar": "foo",
"foo": "bar",
"sub": Object {
"asubsub": Object {
"bar": "foo",
"foo": "bar",
},
"bar": "foo",
"foo": "bar",
},
}
`;
20 changes: 5 additions & 15 deletions __tests__/utils/commands.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const rewire = require('rewire');

const DEFAULT_CONFIG = rewire('../../config').__get__('DEFAULT_CONFIG');
const DEFAULT_CONFIG = rewire('../../src/config').__get__('DEFAULT_CONFIG');

global.Cypress = {
env: () => {},
Expand All @@ -27,29 +27,19 @@ describe('utils/command', () => {
return returnValue;
};

const commands = rewire('../../utils/commands');
commands.__set__('Cypress', global.Cypress);

const getConfig = commands.__get__('getConfig');
const config = getConfig();
expect(config).toMatchObject(DEFAULT_CONFIG);
const getConfig = require('../../src/utils/commands/getConfig');
expect(getConfig()).toMatchObject(DEFAULT_CONFIG);
});

it('with config', () => {
global.Cypress.env = () => CONFIG;
const commands = rewire('../../utils/commands');
commands.__set__('Cypress', global.Cypress);

const getConfig = commands.__get__('getConfig');
const getConfig = require('../../src/utils/commands/getConfig');
expect(getConfig()).toMatchObject(CONFIG);
});

it('without config - error should be thrown', () => {
global.Cypress.env = () => undefined;
const commands = rewire('../../utils/commands');
commands.__set__('Cypress', global.Cypress);

const getConfig = commands.__get__('getConfig');
const getConfig = require('../../src/utils/commands/getConfig');
expect(() => { getConfig(); }).toThrow();
});
});
Expand Down
62 changes: 62 additions & 0 deletions __tests__/utils/keepKeysFromExpected.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

describe('utils/keepKeysFromExpected', () => {
const expected = {
field: "value",
items: [
{name: "item1", "items": [{name: "subitem1"}]},
{name: "item2"},
{name: "item3"},
]
};

const actual = {
field: "value",
extra: "extra",
items: [
{name: "item1", "items": [{name: "subitem1", extra: 'extra1'}, {name: "subitem2", extra: 'extra2'}]},
{name: "item2"},
{name: "item3"},
{name: "item4"},
]
};

it('ignoreExtraFields: false, ignoreExtraArrayItems: false', () => {
const config = {
ignoreExtraFields: false,
ignoreExtraArrayItems: false,
};
const keepKeysFromExpected = require('../../src/utils/keepKeysFromExpected');
const result = keepKeysFromExpected(actual, expected, config);
expect(result).toMatchSnapshot();
});

it('ignoreExtraFields: true, ignoreExtraArrayItems: false', () => {
const config = {
ignoreExtraFields: true,
ignoreExtraArrayItems: false,
};
const keepKeysFromExpected = require('../../src/utils/keepKeysFromExpected');
const result = keepKeysFromExpected(actual, expected, config);
expect(result).toMatchSnapshot();
});

it('ignoreExtraFields: true, ignoreExtraArrayItems: true', () => {
const config = {
ignoreExtraFields: true,
ignoreExtraArrayItems: true,
};
const keepKeysFromExpected = require('../../src/utils/keepKeysFromExpected');
const result = keepKeysFromExpected(actual, expected, config);
expect(result).toMatchSnapshot();
});

it('ignoreExtraFields: false, ignoreExtraArrayItems: true', () => {
const config = {
ignoreExtraFields: false,
ignoreExtraArrayItems: true,
};
const keepKeysFromExpected = require('../../src/utils/keepKeysFromExpected');
const result = keepKeysFromExpected(actual, expected, config);
expect(result).toMatchSnapshot();
});
});
Loading

0 comments on commit 31fd4a5

Please sign in to comment.