Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
Updated to match new cy.screenshot behavior (closes jaredpalmer#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
jackjocross committed Jul 10, 2018
1 parent f310414 commit 95687af
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 76 deletions.
21 changes: 9 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ npm install cypress-image-snapshot
then add the following in your project's `<rootDir>/cypress/plugins/index.js`:

```js
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
const {
addMatchImageSnapshotPlugin,
} = require('cypress-image-snapshot/plugin');

module.exports = on => {
addMatchImageSnapshotPlugin(on);
Expand Down Expand Up @@ -68,33 +70,29 @@ cy.matchImageSnapshot(name, options);
describe('Login', () => {
it('should be publicly accessible', () => {
cy.visit('/login');

// snapshot name will be the test title
cy.matchImageSnapshot();

// snapshot name will be the name passed in
cy.matchImageSnapshot('login');

// options object passed in
cy.matchImageSnapshot(options);

// match element snapshot
cy.get('#login').matchImageSnapshot();
});
});
```



## Options

Any options for [`cy.screenshot()`](https://docs.cypress.io/api/commands/screenshot.html#Arguments) and [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot#optional-configuration) can be passed in the `options` argument to `addMatchImageSnapshotCommand` and `cy.matchImageSnapshot()`. The local options in `cy.matchImageSnapshot()` will overwrite the default options set in `addMatchImageSnapshot`.
Any options for [`cy.screenshot()`](https://docs.cypress.io/api/commands/screenshot.html#Arguments) and [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot#optional-configuration) can be passed in the `options` argument to `addMatchImageSnapshotCommand` and `cy.matchImageSnapshot()`. The local options in `cy.matchImageSnapshot()` will overwrite the default options set in `addMatchImageSnapshot`.

For example, the default options we use in `<rootDir>/cypress/support/commands.js` are:

```js
import kebabCase from 'lodash/kebabcase';

addMatchImageSnapshotCommand({
failureThreshold: 0.03, // threshold for entire image
failureThresholdType: 'percent', // percent of image or number of pixels
Expand All @@ -111,6 +109,5 @@ The workflow of `cy.matchImageSnapshot()` when running Cypress is:

1. Take a screenshot with `cy.screenshot()` named according to the current test.
2. Check if a saved snapshot exists in `<rootDir>/cypress/snapshots` and if so diff against that snapshot.
3. If there is a resulting diff, save it to `<rootDir>/cypress/snapshots/__diff_output__` and `<rootDir>/cypress/screenshots` (so that the diff is uploaded to Cypress' dashboard).
3. If there is a resulting diff, save it to `<rootDir>/cypress/snapshots/__diff_output__`.
4. If the diff is intended, run Cypress again with `--config updateSnapshots=true` to update the snapshots.

6 changes: 0 additions & 6 deletions __tests__/__snapshots__/command.test.js.snap

This file was deleted.

9 changes: 4 additions & 5 deletions __tests__/command.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,14 @@ const commandOptions = {
};

describe('command', () => {
it('should pass options through', async () => {
it('should pass options through', () => {
global.cy = {
task: jest.fn().mockResolvedValue({ pass: true }),
};

await boundMatchImageSnapshot(subject, commandOptions);
boundMatchImageSnapshot(subject, commandOptions);

expect(cy.task).toHaveBeenCalledWith('matchImageSnapshot', {
fileName: 'snap',
expect(cy.task).toHaveBeenCalledWith('Matching image snapshot', {
screenshotsFolder: 'cheese',
fileServerFolder: 'cheese',
updateSnapshots: 'cheese',
Expand Down Expand Up @@ -76,7 +75,7 @@ describe('command', () => {

expect(
boundMatchImageSnapshot(subject, commandOptions)
).rejects.toThrowErrorMatchingSnapshot();
).resolves.toThrowErrorMatchingSnapshot();
});

it('should add command', () => {
Expand Down
18 changes: 8 additions & 10 deletions __tests__/plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,37 @@

import childProcess from 'child_process';
import { diffImageToSnapshot } from 'jest-image-snapshot/src/diff-snapshot';
import { matchImageSnapshotPlugin } from '../src/plugin';
import {
matchImageSnapshotPlugin,
matchImageSnapshotOptions,
} from '../src/plugin';

jest.mock('jest-image-snapshot/src/diff-snapshot', () => ({
diffImageToSnapshot: jest
.fn()
.mockReturnValue({ diffOutputPath: '/path/to/diff' }),
}));
jest.mock('child_process');
jest.mock('fs', () => ({ readFileSync: () => 'cheese' }));

describe('plugin', () => {
it('should pass options through', () => {
const options = {
fileName: 'snap',
screenshotsFolder: '/screenshots',
fileServerFolder: '/fileserver',
updateSnapshots: true,
};

matchImageSnapshotPlugin(options);
matchImageSnapshotOptions(options);

const result = matchImageSnapshotPlugin({ path: 'cheese', name: 'snap' });
expect(result).toEqual({ path: '/path/to/diff' });
expect(diffImageToSnapshot).toHaveBeenCalledWith({
snapshotsDir: '/fileserver/cypress/snapshots',
snapshotsDir: 'cheese',
updateSnapshot: true,
receivedImageBuffer: 'cheese',
snapshotIdentifier: 'snap',
failureThreshold: 0,
failureThresholdType: 'pixel',
});

expect(childProcess.spawnSync).toHaveBeenCalledWith('cp', [
'/path/to/diff',
'/screenshots/snap.png',
]);
});
});
1 change: 1 addition & 0 deletions examples/cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 25 additions & 19 deletions src/command.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,53 @@
*/

import kebabCase from 'lodash.kebabcase';
import { TASK } from './plugin';

const screenshotsFolder = Cypress.config('screenshotsFolder');
const fileServerFolder = Cypress.config('fileServerFolder');
const updateSnapshots = Cypress.config('updateSnapshots') || false;

const defaultFileNameTransform = (name = '', test) =>
kebabCase(`${test.parent.title}-${test.title}-${name}`);
kebabCase(`${test.title}-${name}`);

export function matchImageSnapshotCommand(defaultOptions) {
return async function matchImageSnapshot(subject, name, commandOptions) {
return function matchImageSnapshot(subject, name, commandOptions) {
const options = {
...defaultOptions,
...((typeof name === 'string' ? commandOptions : name) || {}),
};

const { fileNameTransform = defaultFileNameTransform } = options;
const fileName = fileNameTransform(name, this.test);
const target = subject ? subject : cy;
target.screenshot(fileName, options);

const {
pass,
added,
updated,
diffRatio,
diffPixelCount,
diffOutputPath,
} = await cy.task('matchImageSnapshot', {
fileName,
cy.task(TASK.OPTIONS, {
screenshotsFolder,
fileServerFolder,
updateSnapshots,
options,
});

const differencePercentage = diffRatio * 100;
if (!pass && !added && !updated) {
throw new Error(
`Screenshot was ${differencePercentage}% different from saved snapshot with ${diffPixelCount} different pixels.\n See diff for details: ${diffOutputPath}`
const target = subject ? subject : cy;
target.screenshot(fileName, options);

return cy
.task(TASK.RESULTS)
.then(
({
pass,
added,
updated,
diffRatio,
diffPixelCount,
diffOutputPath,
}) => {
if (!pass && !added && !updated) {
const differencePercentage = diffRatio * 100;
throw new Error(
`Screenshot was ${differencePercentage}% different from saved snapshot with ${diffPixelCount} different pixels.\n See diff for details: ${diffOutputPath}`
);
}
}
);
}
};
}

Expand Down
79 changes: 55 additions & 24 deletions src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,73 @@
* LICENSE file in the root directory of this source tree.
*/

const fs = require('fs');
const path = require('path');
const childProcess = require('child_process');
const {
diffImageToSnapshot,
} = require('jest-image-snapshot/src/diff-snapshot');
import fs from 'fs';
import { diffImageToSnapshot } from 'jest-image-snapshot/src/diff-snapshot';

export const TASK = {
OPTIONS: 'Matching image snapshot',
RESULTS: 'Recording snapshot results',
};

let snapshotOptions = {};
let snapshotResults = {};

export function matchImageSnapshotOptions(options) {
snapshotOptions = options;
return null;
}

export function matchImageSnapshotResults() {
snapshotOptions = {};
return snapshotResults;
}

export function matchImageSnapshotPlugin({
fileName,
screenshotsFolder,
fileServerFolder,
updateSnapshots,
options: {
failureThreshold = 0,
failureThresholdType = 'pixel',
...options
} = {},
path: screenshotsPath,
name: snapshotIdentifier,
}) {
const snapshotPath = path.join(screenshotsFolder, `${fileName}.png`);
const receivedImageBuffer = fs.readFileSync(snapshotPath);
const {
screenshotsFolder,
fileServerFolder,
updateSnapshots,
options: {
failureThreshold = 0,
failureThresholdType = 'pixel',
...options
} = {},
} = snapshotOptions;

const result = diffImageToSnapshot({
snapshotsDir: path.join(fileServerFolder, 'cypress', 'snapshots'),
updateSnapshot: updateSnapshots,
const receivedImageBuffer = fs.readFileSync(screenshotsPath);
const snapshotsPath = screenshotsPath.replace('screenshots', 'snapshots');
const snapshotsDir = snapshotsPath.replace(`/${snapshotIdentifier}.png`, '');

snapshotResults = diffImageToSnapshot({
snapshotsDir,
receivedImageBuffer,
snapshotIdentifier: fileName,
snapshotIdentifier,
failureThreshold,
failureThresholdType,
updateSnapshot: updateSnapshots,
...options,
});

childProcess.spawnSync('cp', [result.diffOutputPath, snapshotPath]);
const { pass, added, updated, diffOutputPath } = snapshotResults;

return result;
if (!pass && !added && !updated) {
return {
path: diffOutputPath,
};
}

return {
path: snapshotsPath,
};
}

export function addMatchImageSnapshotPlugin(on) {
on('task', { matchImageSnapshot: matchImageSnapshotPlugin });
on('task', {
[TASK.OPTIONS]: matchImageSnapshotOptions,
[TASK.RESULTS]: matchImageSnapshotResults,
});
on('after:screenshot', matchImageSnapshotPlugin);
}

0 comments on commit 95687af

Please sign in to comment.