From 367343a58177b218d13dc641ce4d2af6d9238a00 Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Sun, 20 Jan 2019 17:59:23 +0100 Subject: [PATCH] support jest-diffing numbers and booleans --- CHANGELOG.md | 1 + packages/expect/src/matchers.js | 6 ++++- packages/jest-diff/src/__tests__/diff.test.js | 15 ++++++++--- packages/jest-diff/src/index.js | 16 ++++++++++-- .../src/__tests__/index.test.js | 25 +++++++++++++++++++ packages/jest-matcher-utils/src/index.js | 13 ++++++++++ 6 files changed, 69 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d3305ac0c93..2937be0fe079 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features - `[jest-runtime]` Add `jest.isolateModules` for scoped module initialization ([#6701](https://github.com/facebook/jest/pull/6701)) +- `[jest-diff]` [**BREAKING**] Support diffing numbers and booleans instead of returning null for different ones ([#7605](https://github.com/facebook/jest/pull/7605)) - `[jest-diff]` [**BREAKING**] Replace `diff` with `diff-sequences` package ([#6961](https://github.com/facebook/jest/pull/6961)) - `[jest-cli]` [**BREAKING**] Only set error process error codes when they are non-zero ([#7363](https://github.com/facebook/jest/pull/7363)) - `[jest-config]` [**BREAKING**] Deprecate `setupTestFrameworkScriptFile` in favor of new `setupFilesAfterEnv` ([#7119](https://github.com/facebook/jest/pull/7119)) diff --git a/packages/expect/src/matchers.js b/packages/expect/src/matchers.js index 345f40341f87..6cfc3c8c119e 100644 --- a/packages/expect/src/matchers.js +++ b/packages/expect/src/matchers.js @@ -9,7 +9,7 @@ import type {MatchersObject} from 'types/Matchers'; -import diff from 'jest-diff'; +import jestDiff from 'jest-diff'; import getType from 'jest-get-type'; import {escapeStrForRegex} from 'jest-regex-util'; import { @@ -25,6 +25,7 @@ import { printReceived, printExpected, printWithType, + shouldPrintDiff, } from 'jest-matcher-utils'; import { getObjectSubset, @@ -44,6 +45,9 @@ type ContainIterable = | DOMTokenList | HTMLCollection; +const diff: typeof jestDiff = (a, b, options) => + shouldPrintDiff(a, b) ? jestDiff(a, b, options) : null; + const matchers: MatchersObject = { toBe(received: any, expected: any) { const comment = 'Object.is equality'; diff --git a/packages/jest-diff/src/__tests__/diff.test.js b/packages/jest-diff/src/__tests__/diff.test.js index 58a622b89c18..50df67c274f7 100644 --- a/packages/jest-diff/src/__tests__/diff.test.js +++ b/packages/jest-diff/src/__tests__/diff.test.js @@ -48,9 +48,12 @@ describe('no visual difference', () => { [[], []], [[1, 2], [1, 2]], [11, 11], + [NaN, NaN], + [Number.NaN, NaN], [() => {}, () => {}], [null, null], [undefined, undefined], + [false, false], [{a: 1}, {a: 1}], [{a: {b: 5}}, {a: {b: 5}}], ].forEach(values => { @@ -178,13 +181,17 @@ describe('objects', () => { }); test('numbers', () => { - const result = diff(123, 234); - expect(result).toBe(null); + expect(stripped(1, 2)).toEqual(expect.stringContaining('- 1\n+ 2')); +}); + +test('-0 and 0', () => { + expect(stripped(-0, 0)).toEqual(expect.stringContaining('- -0\n+ 0')); }); test('booleans', () => { - const result = diff(true, false); - expect(result).toBe(null); + expect(stripped(false, true)).toEqual( + expect.stringContaining('- false\n+ true'), + ); }); describe('multiline string non-snapshot', () => { diff --git a/packages/jest-diff/src/index.js b/packages/jest-diff/src/index.js index 32b62ae4b9dc..a52fa1c1b524 100644 --- a/packages/jest-diff/src/index.js +++ b/packages/jest-diff/src/index.js @@ -83,9 +83,9 @@ function diff(a: any, b: any, options: ?DiffOptions): ?string { switch (aType) { case 'string': return diffStrings(a, b, options); - case 'number': case 'boolean': - return null; + case 'number': + return comparePrimitive(a, b, options); case 'map': return compareObjects(sortMap(a), sortMap(b), options); case 'set': @@ -95,6 +95,18 @@ function diff(a: any, b: any, options: ?DiffOptions): ?string { } } +function comparePrimitive( + a: number | boolean, + b: number | boolean, + options: ?DiffOptions, +) { + return diffStrings( + prettyFormat(a, FORMAT_OPTIONS), + prettyFormat(b, FORMAT_OPTIONS), + options, + ); +} + function sortMap(map) { return new Map(Array.from(map.entries()).sort()); } diff --git a/packages/jest-matcher-utils/src/__tests__/index.test.js b/packages/jest-matcher-utils/src/__tests__/index.test.js index 229e8f5b8a72..fcd1e1fd7e77 100644 --- a/packages/jest-matcher-utils/src/__tests__/index.test.js +++ b/packages/jest-matcher-utils/src/__tests__/index.test.js @@ -11,6 +11,7 @@ import { ensureNoExpected, getLabelPrinter, pluralize, + shouldPrintDiff, stringify, } from '../'; @@ -129,6 +130,30 @@ describe('.ensureNoExpected()', () => { }); }); +describe('shouldPrintDiff', () => { + test('true', () => { + [ + ['a', 'b'], + ['a', {}], + ['a', null], + ['a', undefined], + ['a', 1], + ['a', true], + [1, true], + ].forEach(([actual, expected]) => + expect(shouldPrintDiff(actual, expected)).toBe(true), + ); + }); + + test('two booleans', () => { + expect(shouldPrintDiff(false, true)).toBe(false); + }); + + test('two numbers', () => { + expect(shouldPrintDiff(1, 2)).toBe(false); + }); +}); + describe('.pluralize()', () => { test('one', () => expect(pluralize('apple', 1)).toEqual('one apple')); test('two', () => expect(pluralize('apple', 2)).toEqual('two apples')); diff --git a/packages/jest-matcher-utils/src/index.js b/packages/jest-matcher-utils/src/index.js index f969e9363b9b..69edbc51b31f 100644 --- a/packages/jest-matcher-utils/src/index.js +++ b/packages/jest-matcher-utils/src/index.js @@ -160,6 +160,19 @@ export const ensureNumbers = ( ensureExpectedIsNumber(expected, matcherName); }; +// Sometimes, e.g. when comparing two numbers, the output from jest-diff +// does not contain more information than the `Expected:` / `Received:` already gives. +// In those cases, we do not print a diff to make the output shorter and not redundant. +export const shouldPrintDiff = (actual: any, expected: any) => { + if (typeof actual === 'number' && typeof expected === 'number') { + return false; + } + if (typeof actual === 'boolean' && typeof expected === 'boolean') { + return false; + } + return true; +}; + export const pluralize = (word: string, count: number) => (NUMBERS[count] || count) + ' ' + word + (count === 1 ? '' : 's');