diff --git a/CHANGELOG.md b/CHANGELOG.md index 51ca552dcf52..accab0fc74f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Fixes +- `[expect]` Display expectedDiff more carefully in toBeCloseTo ([#8389](https://github.com/facebook/jest/pull/8389)) - `[jest-fake-timers]` `getTimerCount` will not include cancelled immediates ([#8764](https://github.com/facebook/jest/pull/8764)) ### Chore & Maintenance diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index 45aa734410be..9c018a897cee 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -469,7 +469,7 @@ Expected: false Received: true" `; -exports[`.toBeCloseTo() {pass: false} expect(-Infinity)toBeCloseTo( -1.23) 1`] = ` +exports[`.toBeCloseTo {pass: false} expect(-Infinity).toBeCloseTo(-1.23) 1`] = ` "expect(received).toBeCloseTo(expected) Expected: -1.23 @@ -480,7 +480,62 @@ Expected difference: < 0.005 Received difference: Infinity" `; -exports[`.toBeCloseTo() {pass: false} expect(Infinity)toBeCloseTo( -Infinity) 1`] = ` +exports[`.toBeCloseTo {pass: false} expect(0).toBeCloseTo(0.01) 1`] = ` +"expect(received).toBeCloseTo(expected) + +Expected: 0.01 +Received: 0 + +Expected precision: 2 +Expected difference: < 0.005 +Received difference: 0.01" +`; + +exports[`.toBeCloseTo {pass: false} expect(1).toBeCloseTo(1.23) 1`] = ` +"expect(received).toBeCloseTo(expected) + +Expected: 1.23 +Received: 1 + +Expected precision: 2 +Expected difference: < 0.005 +Received difference: 0.22999999999999998" +`; + +exports[`.toBeCloseTo {pass: false} expect(1.23).toBeCloseTo(1.2249999) 1`] = ` +"expect(received).toBeCloseTo(expected) + +Expected: 1.2249999 +Received: 1.23 + +Expected precision: 2 +Expected difference: < 0.005 +Received difference: 0.005000099999999952" +`; + +exports[`.toBeCloseTo {pass: false} expect(3.141592e-7).toBeCloseTo(3e-7, 8) 1`] = ` +"expect(received).toBeCloseTo(expected, precision) + +Expected: 3e-7 +Received: 3.141592e-7 + +Expected precision: 8 +Expected difference: < 5e-9 +Received difference: 1.4159200000000025e-8" +`; + +exports[`.toBeCloseTo {pass: false} expect(56789).toBeCloseTo(51234, -4) 1`] = ` +"expect(received).toBeCloseTo(expected, precision) + +Expected: 51234 +Received: 56789 + +Expected precision: -4 +Expected difference: < 5000 +Received difference: 5555" +`; + +exports[`.toBeCloseTo {pass: false} expect(Infinity).toBeCloseTo(-Infinity) 1`] = ` "expect(received).toBeCloseTo(expected) Expected: -Infinity @@ -491,7 +546,7 @@ Expected difference: < 0.005 Received difference: Infinity" `; -exports[`.toBeCloseTo() {pass: false} expect(Infinity)toBeCloseTo( 1.23) 1`] = ` +exports[`.toBeCloseTo {pass: false} expect(Infinity).toBeCloseTo(1.23) 1`] = ` "expect(received).toBeCloseTo(expected) Expected: 1.23 @@ -502,21 +557,43 @@ Expected difference: < 0.005 Received difference: Infinity" `; -exports[`.toBeCloseTo() {pass: true} expect(-Infinity)toBeCloseTo( -Infinity) 1`] = ` +exports[`.toBeCloseTo {pass: true} expect(-Infinity).toBeCloseTo(-Infinity) 1`] = ` "expect(received).not.toBeCloseTo(expected) Expected: not -Infinity " `; -exports[`.toBeCloseTo() {pass: true} expect(0)toBeCloseTo( 0) 1`] = ` +exports[`.toBeCloseTo {pass: true} expect(0).toBeCloseTo(0) 1`] = ` "expect(received).not.toBeCloseTo(expected) Expected: not 0 " `; -exports[`.toBeCloseTo() {pass: true} expect(0)toBeCloseTo( 0.001) 1`] = ` +exports[`.toBeCloseTo {pass: true} expect(0).toBeCloseTo(0.000004, 5) 1`] = ` +"expect(received).not.toBeCloseTo(expected, precision) + +Expected: not 0.000004 +Received: 0 + +Expected precision: 5 +Expected difference: not < 0.000005 +Received difference: 0.000004" +`; + +exports[`.toBeCloseTo {pass: true} expect(0).toBeCloseTo(0.0001, 3) 1`] = ` +"expect(received).not.toBeCloseTo(expected, precision) + +Expected: not 0.0001 +Received: 0 + +Expected precision: 3 +Expected difference: not < 0.0005 +Received difference: 0.0001" +`; + +exports[`.toBeCloseTo {pass: true} expect(0).toBeCloseTo(0.001) 1`] = ` "expect(received).not.toBeCloseTo(expected) Expected: not 0.001 @@ -527,7 +604,18 @@ Expected difference: not < 0.005 Received difference: 0.001" `; -exports[`.toBeCloseTo() {pass: true} expect(1.23)toBeCloseTo( 1.225) 1`] = ` +exports[`.toBeCloseTo {pass: true} expect(0).toBeCloseTo(0.1, 0) 1`] = ` +"expect(received).not.toBeCloseTo(expected, precision) + +Expected: not 0.1 +Received: 0 + +Expected precision: 0 +Expected difference: not < 0.5 +Received difference: 0.1" +`; + +exports[`.toBeCloseTo {pass: true} expect(1.23).toBeCloseTo(1.225) 1`] = ` "expect(received).not.toBeCloseTo(expected) Expected: not 1.225 @@ -538,7 +626,7 @@ Expected difference: not < 0.005 Received difference: 0.004999999999999893" `; -exports[`.toBeCloseTo() {pass: true} expect(1.23)toBeCloseTo( 1.226) 1`] = ` +exports[`.toBeCloseTo {pass: true} expect(1.23).toBeCloseTo(1.226) 1`] = ` "expect(received).not.toBeCloseTo(expected) Expected: not 1.226 @@ -549,7 +637,7 @@ Expected difference: not < 0.005 Received difference: 0.0040000000000000036" `; -exports[`.toBeCloseTo() {pass: true} expect(1.23)toBeCloseTo( 1.229) 1`] = ` +exports[`.toBeCloseTo {pass: true} expect(1.23).toBeCloseTo(1.229) 1`] = ` "expect(received).not.toBeCloseTo(expected) Expected: not 1.229 @@ -560,7 +648,7 @@ Expected difference: not < 0.005 Received difference: 0.0009999999999998899" `; -exports[`.toBeCloseTo() {pass: true} expect(1.23)toBeCloseTo( 1.234) 1`] = ` +exports[`.toBeCloseTo {pass: true} expect(1.23).toBeCloseTo(1.234) 1`] = ` "expect(received).not.toBeCloseTo(expected) Expected: not 1.234 @@ -571,80 +659,25 @@ Expected difference: not < 0.005 Received difference: 0.0040000000000000036" `; -exports[`.toBeCloseTo() {pass: true} expect(Infinity)toBeCloseTo( Infinity) 1`] = ` -"expect(received).not.toBeCloseTo(expected) - -Expected: not Infinity -" -`; - -exports[`.toBeCloseTo() accepts an optional precision argument: [0, 0.000004, 5] 1`] = ` +exports[`.toBeCloseTo {pass: true} expect(2.0000002).toBeCloseTo(2, 5) 1`] = ` "expect(received).not.toBeCloseTo(expected, precision) -Expected: not 0.000004 -Received: 0 +Expected: not 2 +Received: 2.0000002 Expected precision: 5 -Expected difference: not < 0.000005 -Received difference: 0.000004" +Expected difference: not < 5e-6 +Received difference: 2.0000000011677344e-7" `; -exports[`.toBeCloseTo() accepts an optional precision argument: [0, 0.0001, 3] 1`] = ` -"expect(received).not.toBeCloseTo(expected, precision) - -Expected: not 0.0001 -Received: 0 - -Expected precision: 3 -Expected difference: not < 0.0005 -Received difference: 0.0001" -`; - -exports[`.toBeCloseTo() accepts an optional precision argument: [0, 0.1, 0] 1`] = ` -"expect(received).not.toBeCloseTo(expected, precision) - -Expected: not 0.1 -Received: 0 - -Expected precision: 0 -Expected difference: not < 0.5 -Received difference: 0.1" -`; - -exports[`.toBeCloseTo() throws: [0, 0.01] 1`] = ` -"expect(received).toBeCloseTo(expected) - -Expected: 0.01 -Received: 0 - -Expected precision: 2 -Expected difference: < 0.005 -Received difference: 0.01" -`; - -exports[`.toBeCloseTo() throws: [1, 1.23] 1`] = ` -"expect(received).toBeCloseTo(expected) - -Expected: 1.23 -Received: 1 - -Expected precision: 2 -Expected difference: < 0.005 -Received difference: 0.22999999999999998" -`; - -exports[`.toBeCloseTo() throws: [1.23, 1.2249999] 1`] = ` -"expect(received).toBeCloseTo(expected) - -Expected: 1.2249999 -Received: 1.23 +exports[`.toBeCloseTo {pass: true} expect(Infinity).toBeCloseTo(Infinity) 1`] = ` +"expect(received).not.toBeCloseTo(expected) -Expected precision: 2 -Expected difference: < 0.005 -Received difference: 0.005000099999999952" +Expected: not Infinity +" `; -exports[`.toBeCloseTo() throws: Matcher error promise empty isNot false received 1`] = ` +exports[`.toBeCloseTo throws: Matcher error promise empty isNot false received 1`] = ` "expect(received).toBeCloseTo(expected, precision) Matcher error: received value must be a number @@ -653,7 +686,7 @@ Received has type: string Received has value: \\"\\"" `; -exports[`.toBeCloseTo() throws: Matcher error promise empty isNot true expected 1`] = ` +exports[`.toBeCloseTo throws: Matcher error promise empty isNot true expected 1`] = ` "expect(received).not.toBeCloseTo(expected) Matcher error: expected value must be a number @@ -661,7 +694,7 @@ exports[`.toBeCloseTo() throws: Matcher error promise empty isNot true expected Expected has value: undefined" `; -exports[`.toBeCloseTo() throws: Matcher error promise rejects isNot false expected 1`] = ` +exports[`.toBeCloseTo throws: Matcher error promise rejects isNot false expected 1`] = ` "expect(received).rejects.toBeCloseTo(expected) Matcher error: expected value must be a number @@ -670,7 +703,7 @@ Expected has type: string Expected has value: \\"0\\"" `; -exports[`.toBeCloseTo() throws: Matcher error promise rejects isNot true received 1`] = ` +exports[`.toBeCloseTo throws: Matcher error promise rejects isNot true received 1`] = ` "expect(received).rejects.not.toBeCloseTo(expected) Matcher error: received value must be a number @@ -679,7 +712,7 @@ Received has type: symbol Received has value: Symbol(0.1)" `; -exports[`.toBeCloseTo() throws: Matcher error promise resolves isNot false received 1`] = ` +exports[`.toBeCloseTo throws: Matcher error promise resolves isNot false received 1`] = ` "expect(received).resolves.toBeCloseTo(expected, precision) Matcher error: received value must be a number @@ -688,7 +721,7 @@ Received has type: boolean Received has value: false" `; -exports[`.toBeCloseTo() throws: Matcher error promise resolves isNot true expected 1`] = ` +exports[`.toBeCloseTo throws: Matcher error promise resolves isNot true expected 1`] = ` "expect(received).resolves.not.toBeCloseTo(expected, precision) Matcher error: expected value must be a number diff --git a/packages/expect/src/__tests__/matchers.test.js b/packages/expect/src/__tests__/matchers.test.js index e7b683898e43..a4cbb0800e9b 100644 --- a/packages/expect/src/__tests__/matchers.test.js +++ b/packages/expect/src/__tests__/matchers.test.js @@ -1110,7 +1110,7 @@ describe('.toContain(), .toContainEqual()', () => { }); }); -describe('.toBeCloseTo()', () => { +describe('.toBeCloseTo', () => { [ [0, 0], [0, 0.001], @@ -1118,8 +1118,10 @@ describe('.toBeCloseTo()', () => { [1.23, 1.226], [1.23, 1.225], [1.23, 1.234], + [Infinity, Infinity], + [-Infinity, -Infinity], ].forEach(([n1, n2]) => { - it(`{pass: true} expect(${n1})toBeCloseTo( ${n2})`, () => { + it(`{pass: true} expect(${n1}).toBeCloseTo(${n2})`, () => { jestExpect(n1).toBeCloseTo(n2); expect(() => @@ -1128,48 +1130,45 @@ describe('.toBeCloseTo()', () => { }); }); - [[0, 0.01], [1, 1.23], [1.23, 1.2249999]].forEach(([n1, n2]) => { - it(`throws: [${n1}, ${n2}]`, () => { + [ + [0, 0.01], + [1, 1.23], + [1.23, 1.2249999], + [Infinity, -Infinity], + [Infinity, 1.23], + [-Infinity, -1.23], + ].forEach(([n1, n2]) => { + it(`{pass: false} expect(${n1}).toBeCloseTo(${n2})`, () => { + jestExpect(n1).not.toBeCloseTo(n2); + expect(() => jestExpect(n1).toBeCloseTo(n2), ).toThrowErrorMatchingSnapshot(); - - jestExpect(n1).not.toBeCloseTo(n2); }); }); - [[Infinity, Infinity], [-Infinity, -Infinity]].forEach(([n1, n2]) => { - it(`{pass: true} expect(${n1})toBeCloseTo( ${n2})`, () => { - jestExpect(n1).toBeCloseTo(n2); + [[3.141592e-7, 3e-7, 8], [56789, 51234, -4]].forEach(([n1, n2, p]) => { + it(`{pass: false} expect(${n1}).toBeCloseTo(${n2}, ${p})`, () => { + jestExpect(n1).not.toBeCloseTo(n2, p); expect(() => - jestExpect(n1).not.toBeCloseTo(n2), + jestExpect(n1).toBeCloseTo(n2, p), ).toThrowErrorMatchingSnapshot(); }); }); - [[Infinity, -Infinity], [Infinity, 1.23], [-Infinity, -1.23]].forEach( - ([n1, n2]) => { - it(`{pass: false} expect(${n1})toBeCloseTo( ${n2})`, () => { - jestExpect(n1).not.toBeCloseTo(n2); + [[0, 0.1, 0], [0, 0.0001, 3], [0, 0.000004, 5], [2.0000002, 2, 5]].forEach( + ([n1, n2, p]) => { + it(`{pass: true} expect(${n1}).toBeCloseTo(${n2}, ${p})`, () => { + jestExpect(n1).toBeCloseTo(n2, p); expect(() => - jestExpect(n1).toBeCloseTo(n2), + jestExpect(n1).not.toBeCloseTo(n2, p), ).toThrowErrorMatchingSnapshot(); }); }, ); - [[0, 0.1, 0], [0, 0.0001, 3], [0, 0.000004, 5]].forEach(([n1, n2, p]) => { - it(`accepts an optional precision argument: [${n1}, ${n2}, ${p}]`, () => { - jestExpect(n1).toBeCloseTo(n2, p); - - expect(() => - jestExpect(n1).not.toBeCloseTo(n2, p), - ).toThrowErrorMatchingSnapshot(); - }); - }); - describe('throws: Matcher error', () => { test('promise empty isNot false received', () => { const precision = 3; diff --git a/packages/expect/src/matchers.ts b/packages/expect/src/matchers.ts index c9ee95c4f670..c461fee88464 100644 --- a/packages/expect/src/matchers.ts +++ b/packages/expect/src/matchers.ts @@ -27,6 +27,7 @@ import { } from 'jest-matcher-utils'; import {MatcherState, MatchersObject} from './types'; import { + printCloseTo, printExpectedConstructorName, printExpectedConstructorNameNot, printReceivedArrayContainExpectedItem, @@ -129,8 +130,9 @@ const matchers: MatchersObject = { ) { const matcherName = 'toBeCloseTo'; const secondArgument = arguments.length === 3 ? 'precision' : undefined; + const isNot = this.isNot; const options: MatcherHintOptions = { - isNot: this.isNot, + isNot, promise: this.promise, secondArgument, secondArgumentColor: (arg: string) => arg, @@ -160,18 +162,14 @@ const matchers: MatchersObject = { ? '' : `Received: ${printReceived(received)}\n` + '\n' + - `Expected precision: ${stringify(precision)}\n` + - `Expected difference: not < ${printExpected(expectedDiff)}\n` + - `Received difference: ${printReceived(receivedDiff)}`) + printCloseTo(receivedDiff, expectedDiff, precision, isNot)) : () => matcherHint(matcherName, undefined, undefined, options) + '\n\n' + `Expected: ${printExpected(expected)}\n` + `Received: ${printReceived(received)}\n` + '\n' + - `Expected precision: ${stringify(precision)}\n` + - `Expected difference: < ${printExpected(expectedDiff)}\n` + - `Received difference: ${printReceived(receivedDiff)}`; + printCloseTo(receivedDiff, expectedDiff, precision, isNot); return {message, pass}; }, diff --git a/packages/expect/src/print.ts b/packages/expect/src/print.ts index aa03601398d8..10aac847cf75 100644 --- a/packages/expect/src/print.ts +++ b/packages/expect/src/print.ts @@ -61,6 +61,34 @@ export const printReceivedArrayContainExpectedItem = ( ']', ); +export const printCloseTo = ( + receivedDiff: number, + expectedDiff: number, + precision: number, + isNot: boolean, +): string => { + const receivedDiffString = stringify(receivedDiff); + const expectedDiffString = receivedDiffString.includes('e') + ? // toExponential arg is number of digits after the decimal point. + expectedDiff.toExponential(0) + : 0 <= precision && precision < 20 + ? // toFixed arg is number of digits after the decimal point. + // It may be a value between 0 and 20 inclusive. + // Implementations may optionally support a larger range of values. + expectedDiff.toFixed(precision + 1) + : stringify(expectedDiff); + + return ( + `Expected precision: ${isNot ? ' ' : ''} ${stringify(precision)}\n` + + `Expected difference: ${isNot ? 'not ' : ''}< ${EXPECTED_COLOR( + expectedDiffString, + )}\n` + + `Received difference: ${isNot ? ' ' : ''} ${RECEIVED_COLOR( + receivedDiffString, + )}` + ); +}; + export const printExpectedConstructorName = ( label: string, expected: Function,