From cee46b1fc94f962c34900a8b655d22665cea2854 Mon Sep 17 00:00:00 2001 From: Adrian Jost <22987140+adrianjost@users.noreply.github.com> Date: Fri, 17 Apr 2020 03:08:04 +0000 Subject: [PATCH] feat(options): add option to pass on size missmatch (#174) if the option `allowSizeMismatch` is set, a build will not always fail on images with different sizes. Missing or Added Pixel will be counted as a mismatch and respected by the set threshold. Related #83, #85 --- README.md | 1 + __tests__/diff-snapshot.spec.js | 38 ++++++++++++++++++++ src/diff-snapshot.js | 62 +++++++++++++++++++++++++-------- 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 5635f90..f895c6e 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ See [the examples](./examples/README.md) for more detailed usage or read about a * `blur`: (default `0`) Applies Gaussian Blur on compared images, accepts radius in pixels as value. Useful when you have noise after scaling images per different resolutions on your target website, usually setting its value to 1-2 should be enough to solve that problem. * `runInProcess`: (default `false`) Runs the diff in process without spawning a child process. * `dumpDiffToConsole`: (default `false`) Will output base64 string of a diff image to console in case of failed tests (in addition to creating a diff image). This string can be copy-pasted to a browser address string to preview the diff for a failed test. +* `allowSizeMismatch`: (default `false`) If set to true, the build will not fail when the screenshots to compare have different sizes. ```javascript it('should demonstrate this matcher`s usage with a custom pixelmatch config', () => { diff --git a/__tests__/diff-snapshot.spec.js b/__tests__/diff-snapshot.spec.js index 7270668..59d3501 100644 --- a/__tests__/diff-snapshot.spec.js +++ b/__tests__/diff-snapshot.spec.js @@ -244,6 +244,44 @@ describe('diff-snapshot', () => { expect(result.diffRatio).toBe(0.025); }); + it('should pass with allowSizeMismatch: true if image passed is a different size but <= failureThreshold pixel', () => { + const diffImageToSnapshot = setupTest({ snapshotExists: true, pixelmatchResult: 250 }); + const result = diffImageToSnapshot({ + receivedImageBuffer: mockBigImageBuffer, + snapshotIdentifier: mockSnapshotIdentifier, + snapshotsDir: mockSnapshotsDir, + diffDir: mockDiffDir, + updateSnapshot: false, + failureThreshold: 250, + failureThresholdType: 'pixel', + allowSizeMismatch: true, + }); + + expect(result.pass).toBe(true); + expect(result.diffSize).toBe(true); + expect(result.diffPixelCount).toBe(250); + expect(result.diffRatio).toBe(0.1 / 9); + }); + + it('should fail with allowSizeMismatch: true if image passed is a different size but > failureThreshold pixel', () => { + const diffImageToSnapshot = setupTest({ snapshotExists: true, pixelmatchResult: 250 }); + const result = diffImageToSnapshot({ + receivedImageBuffer: mockBigImageBuffer, + snapshotIdentifier: mockSnapshotIdentifier, + snapshotsDir: mockSnapshotsDir, + diffDir: mockDiffDir, + updateSnapshot: false, + failureThreshold: 0, + failureThresholdType: 'pixel', + allowSizeMismatch: true, + }); + + expect(result.pass).toBe(false); + expect(result.diffSize).toBe(true); + expect(result.diffPixelCount).toBe(250); + expect(result.diffRatio).toBe(0.1 / 9); + }); + it('should pass = image checksums', () => { const diffImageToSnapshot = setupTest({ snapshotExists: true, pixelmatchResult: 0 }); const result = diffImageToSnapshot({ diff --git a/src/diff-snapshot.js b/src/diff-snapshot.js index 245eaf9..fd83fcb 100644 --- a/src/diff-snapshot.js +++ b/src/diff-snapshot.js @@ -83,6 +83,38 @@ const shouldUpdate = ({ pass, updateSnapshot, updatePassedSnapshot }) => ( (!pass && updateSnapshot) || (pass && updatePassedSnapshot) ); +const shouldFail = ({ + totalPixels, + diffPixelCount, + hasSizeMismatch, + allowSizeMismatch, + failureThresholdType, + failureThreshold, +}) => { + let pass = false; + let diffSize = false; + const diffRatio = diffPixelCount / totalPixels; + if (hasSizeMismatch) { + // do not fail if allowSizeMismatch is set + pass = allowSizeMismatch; + diffSize = true; + } + if (!diffSize || pass === true) { + if (failureThresholdType === 'pixel') { + pass = diffPixelCount <= failureThreshold; + } else if (failureThresholdType === 'percent') { + pass = diffRatio <= failureThreshold; + } else { + throw new Error(`Unknown failureThresholdType: ${failureThresholdType}. Valid options are "pixel" or "percent".`); + } + } + return { + pass, + diffSize, + diffRatio, + }; +}; + function diffImageToSnapshot(options) { const { receivedImageBuffer, @@ -96,6 +128,7 @@ function diffImageToSnapshot(options) { failureThreshold, failureThresholdType, blur, + allowSizeMismatch = false, } = options; let result = {}; @@ -140,9 +173,6 @@ function diffImageToSnapshot(options) { const diffImage = new PNG({ width: imageWidth, height: imageHeight }); - let pass = false; - let diffSize = false; - let diffRatio = 0; let diffPixelCount = 0; diffPixelCount = pixelmatch( @@ -155,18 +185,19 @@ function diffImageToSnapshot(options) { ); const totalPixels = imageWidth * imageHeight; - diffRatio = diffPixelCount / totalPixels; - // Always fail test on image size mismatch - if (hasSizeMismatch) { - pass = false; - diffSize = true; - } else if (failureThresholdType === 'pixel') { - pass = diffPixelCount <= failureThreshold; - } else if (failureThresholdType === 'percent') { - pass = diffRatio <= failureThreshold; - } else { - throw new Error(`Unknown failureThresholdType: ${failureThresholdType}. Valid options are "pixel" or "percent".`); - } + + const { + pass, + diffSize, + diffRatio, + } = shouldFail({ + totalPixels, + diffPixelCount, + hasSizeMismatch, + allowSizeMismatch, + failureThresholdType, + failureThreshold, + }); if (isFailure({ pass, updateSnapshot })) { mkdirp.sync(diffDir); @@ -213,6 +244,7 @@ function diffImageToSnapshot(options) { } else { result = { pass, + diffSize, diffRatio, diffPixelCount, diffOutputPath,