Skip to content

Commit

Permalink
feat(diff-snapshot): add side to side comparison to result image (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
anescobar1991 authored Jan 12, 2018
1 parent caa6e45 commit f5c6b9b
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 12 deletions.
15 changes: 9 additions & 6 deletions __tests__/diff-snapshot.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
/* eslint-disable global-require */
const fs = require('fs');
const path = require('path');
const mockSpawn = require('mock-spawn')();

describe('diff-snapshot', () => {
beforeEach(() => {
Expand Down Expand Up @@ -47,6 +48,9 @@ describe('diff-snapshot', () => {
writeFileSync: mockWriteFileSync,
readFileSync: jest.fn(),
});

mockSpawn.setDefault(mockSpawn.simple(0));
jest.mock('child_process', () => ({ spawnSync: mockSpawn }));
jest.mock('fs', () => mockFs);
jest.mock('mkdirp', () => ({ sync: mockMkdirpSync }));
const { diffImageToSnapshot } = require('../src/diff-snapshot');
Expand Down Expand Up @@ -127,7 +131,7 @@ describe('diff-snapshot', () => {
// Check that pixelmatch was called
expect(mockPixelMatch).toHaveBeenCalledTimes(1);
// Check that that it did not attempt to write a diff
expect(mockWriteFileSync).not.toHaveBeenCalled();
expect(mockSpawn.calls).toEqual([]);
});

it('should write a diff image if the test fails', () => {
Expand Down Expand Up @@ -156,11 +160,10 @@ describe('diff-snapshot', () => {
100,
{ threshold: 0.01 }
);
expect(mockWriteFileSync).toHaveBeenCalledTimes(1);
expect(mockWriteFileSync).toHaveBeenCalledWith(
path.join(mockSnapshotsDir, '__diff_output__', 'id1-diff.png'),
expect.any(Buffer)
);

expect(mockSpawn.calls[0].args[0]).toBe(path.resolve('./src/write-result-diff-image.js'));
expect(mockSpawn.calls[0].command).toBe('node');
expect(mockSpawn.calls[0].opts.input).toEqual(expect.any(Buffer));
});

it('should pass <= failureThreshold pixel', () => {
Expand Down
11 changes: 7 additions & 4 deletions __tests__/integration.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const fs = require('fs');
const path = require('path');
const rimraf = require('rimraf');
const uniqueId = require('lodash/uniqueId');
const isPng = require('is-png');

describe('toMatchImageSnapshot', () => {
const imagePath = path.resolve(__dirname, './stubs', 'TestImage.png');
Expand Down Expand Up @@ -122,7 +123,7 @@ describe('toMatchImageSnapshot', () => {

it('writes a result image for failing tests', () => {
const customSnapshotIdentifier = getIdentifierIndicatingCleanupIsRequired();

const pathToResultImage = path.join(__dirname, diffOutputDir(), `${customSnapshotIdentifier}-diff.png`);
// First we need to write a new snapshot image
expect(
() => expect(imageData).toMatchImageSnapshot({ customSnapshotIdentifier })
Expand All @@ -133,9 +134,11 @@ describe('toMatchImageSnapshot', () => {
() => expect(failImageData).toMatchImageSnapshot({ customSnapshotIdentifier })
).toThrow();

expect(
fs.existsSync(path.join(__dirname, diffOutputDir(), `${customSnapshotIdentifier}-diff.png`))
).toBe(true);
expect(fs.existsSync(pathToResultImage)).toBe(true);

const imageBuffer = fs.readFileSync(pathToResultImage);
// just because file was written does not mean it is a png image
expect(isPng(imageBuffer)).toBe(true);
});
});
});
9 changes: 9 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
],
"jest": {
"preset": "amex-jest-preset",
"collectCoverageFrom": [
"src/*.js",
"!src/write-result-diff-image.js",
"!**/node_modules/**",
"!test-results/**"
],
"testMatch": ["<rootDir>/__tests__/**/*.js"],
"coveragePathIgnorePatterns": ["/node_modules/", "<rootDir>/examples"]
},
Expand All @@ -34,12 +40,15 @@
"amex-jest-preset": "^4.0.2",
"eslint": "^4.15.0",
"eslint-config-amex": "^7.0.0",
"is-png": "^1.1.0",
"jest": "^22.0.0",
"lodash": "^4.17.4",
"mock-spawn": "^0.2.6",
"rimraf": "^2.6.2"
},
"dependencies": {
"chalk": "^1.1.3",
"get-stdin": "^5.0.1",
"lodash": "^4.17.4",
"mkdirp": "^0.5.1",
"pixelmatch": "^4.0.2",
Expand Down
24 changes: 22 additions & 2 deletions src/diff-snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

const fs = require('fs');
const path = require('path');
const childProcess = require('child_process');
const pixelmatch = require('pixelmatch');
const mkdirp = require('mkdirp');
const { PNG } = require('pngjs');
Expand Down Expand Up @@ -75,8 +76,27 @@ function diffImageToSnapshot(options) {

if (!pass) {
mkdirp.sync(outputDir);
const buffer = PNG.sync.write(diffImage);
fs.writeFileSync(diffOutputPath, buffer);
const compositeResultImage = new PNG({
width: imageWidth * 3,
height: imageHeight,
});
// copy baseline, diff, and received images into composite result image
PNG.bitblt(
baselineImage, compositeResultImage, 0, 0, imageWidth, imageHeight, 0, 0
);
PNG.bitblt(
diffImage, compositeResultImage, 0, 0, imageWidth, imageHeight, imageWidth, 0
);
PNG.bitblt(
receivedImage, compositeResultImage, 0, 0, imageWidth, imageHeight, imageWidth * 2, 0
);

const input = { imagePath: diffOutputPath, image: compositeResultImage };

// writing diff in separate process to avoid perf issues associated with Math in Jest VM (https://github.com/facebook/jest/issues/5163)
const writeDiffProcess = childProcess.spawnSync('node', [`${__dirname}/write-result-diff-image.js`], { input: Buffer.from(JSON.stringify(input)) });
// in case of error print to console
if (writeDiffProcess.stderr.toString()) { console.log(writeDiffProcess.stderr.toString()); } // eslint-disable-line no-console, max-len
}

result = {
Expand Down
33 changes: 33 additions & 0 deletions src/write-result-diff-image.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2018 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/

const { PNG } = require('pngjs');
const fs = require('fs');
const getStdin = require('get-stdin');

getStdin.buffer().then((buffer) => {
try {
const input = JSON.parse(buffer);
const { imagePath, image } = input;

image.data = Buffer.from(image.data);

const pngBuffer = PNG.sync.write(image);
fs.writeFileSync(imagePath, pngBuffer);
process.exit(0);
} catch (error) {
console.error(error); // eslint-disable-line no-console
process.exit(1);
}
});

0 comments on commit f5c6b9b

Please sign in to comment.