From 4bad752571bb567861ddfa2cc9073f33c4239352 Mon Sep 17 00:00:00 2001 From: Benjamin Koltes Date: Fri, 2 Dec 2022 11:45:55 -0500 Subject: [PATCH] feat: add onlyDiff in options (#317) --- README.md | 1 + __tests__/__snapshots__/index.spec.js.snap | 1 + __tests__/index.spec.js | 3 ++ __tests__/integration.spec.js | 39 ++++++++++++++++++ .../TestImageUpdate1pxOff-onlyDiff-diff.png | Bin 0 -> 3766 bytes src/diff-snapshot.js | 28 ++++++++++--- src/index.js | 3 ++ 7 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 __tests__/stubs/TestImageUpdate1pxOff-onlyDiff-diff.png diff --git a/README.md b/README.md index 253ef08..53f8861 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ See [the examples](./examples/README.md) for more detailed usage or read about a * `customReceivedDir`: A custom absolute path of a directory to keep this received image in * `customSnapshotIdentifier`: A custom name to give this snapshot. If not provided one is computed automatically. When a function is provided it is called with an object containing `testPath`, `currentTestName`, `counter` and `defaultIdentifier` as its first argument. The function must return an identifier to use for the snapshot. If a path is given, the path will be created inside the snapshot/diff directories. * `diffDirection`: (default: `horizontal`) (options `horizontal` or `vertical`) Changes diff image layout direction +* `onlyDiff`: (default: `false`) Either only include the difference between the baseline and the received image in the diff image, or include the 3 images (following the direction set by `diffDirection`). * `noColors`: Removes coloring from console output, useful if storing the results in a file * `failureThreshold`: (default `0`) Sets the threshold that would trigger a test failure based on the `failureThresholdType` selected. This is different to the `customDiffConfig.threshold` above, that is the per pixel failure threshold, this is the failure threshold for the entire comparison. * `failureThresholdType`: (default `pixel`) (options `percent` or `pixel`) Sets the type of threshold that would trigger a failure. diff --git a/__tests__/__snapshots__/index.spec.js.snap b/__tests__/__snapshots__/index.spec.js.snap index ce2d667..dbf3278 100644 --- a/__tests__/__snapshots__/index.spec.js.snap +++ b/__tests__/__snapshots__/index.spec.js.snap @@ -47,6 +47,7 @@ exports[`toMatchImageSnapshot passes diffImageToSnapshot everything it needs to "diffDirection": "horizontal", "failureThreshold": 0, "failureThresholdType": "pixel", + "onlyDiff": false, "receivedDir": undefined, "receivedImageBuffer": "pretendthisisanimagebuffer", "snapshotIdentifier": "test-spec-js-test-1-snap", diff --git a/__tests__/index.spec.js b/__tests__/index.spec.js index 25d4d73..d12c38d 100644 --- a/__tests__/index.spec.js +++ b/__tests__/index.spec.js @@ -443,6 +443,7 @@ describe('toMatchImageSnapshot', () => { comparisonMethod: 'pixelmatch', customDiffConfig: {}, diffDirection: 'horizontal', + onlyDiff: false, failureThreshold: 0, failureThresholdType: 'pixel', receivedImageBuffer: undefined, @@ -513,6 +514,7 @@ describe('toMatchImageSnapshot', () => { storeReceivedOnFailure: true, diffDir: path.join('path', 'to', 'my-custom-diff-dir'), diffDirection: 'vertical', + onlyDiff: false, updateSnapshot: false, updatePassedSnapshot: true, failureThreshold: 1, @@ -572,6 +574,7 @@ describe('toMatchImageSnapshot', () => { receivedDir: path.join('path', 'to', 'my-custom-received-dir'), diffDir: path.join('path', 'to', 'my-custom-diff-dir'), diffDirection: 'horizontal', + onlyDiff: false, storeReceivedOnFailure: true, updateSnapshot: false, updatePassedSnapshot: false, diff --git a/__tests__/integration.spec.js b/__tests__/integration.spec.js index 357e558..0337d19 100644 --- a/__tests__/integration.spec.js +++ b/__tests__/integration.spec.js @@ -410,6 +410,45 @@ describe('toMatchImageSnapshot', () => { .toBe(false); }); + it('only outputs the diff when onlyDiff is enabled', () => { + const failureImageData = fs.readFileSync(fromStubs('TestImageUpdate1pxOff.png')); + const imageFailureOnlyDiffData = + fs.readFileSync(fromStubs('TestImageUpdate1pxOff-onlyDiff-diff.png')); + + 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, + onlyDiff: true, + }) + ) + .not + .toThrowError(); + + // then test against a different image + expect( + () => expect(failureImageData) + .toMatchImageSnapshot({ + customSnapshotIdentifier, + onlyDiff: true, + // required for coverage + runInProcess: true, + }) + ) + .toThrow(/Expected image to match or be a close match/); + + expect(fs.existsSync(pathToResultImage)) + .toBe(true); + + expect(fs.readFileSync(pathToResultImage)).toEqual(imageFailureOnlyDiffData); + // just because file was written does not mean it is a png image + expect(sizeOf(pathToResultImage)) + .toHaveProperty('type', 'png'); + }); + it('handles diffs for large images', () => { const largeImageData = fs.readFileSync(fromStubs('LargeTestImage.png')); const largeFailureImageData = fs.readFileSync(fromStubs('LargeTestImageFailure.png')); diff --git a/__tests__/stubs/TestImageUpdate1pxOff-onlyDiff-diff.png b/__tests__/stubs/TestImageUpdate1pxOff-onlyDiff-diff.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ac0491353766d148f5323a776a7038d9a8a575 GIT binary patch literal 3766 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