Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expect, jest-matcher-utils: Improve report when matcher fails, part 9 #7940

Merged
merged 5 commits into from Feb 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@

- `[expect]`: Improve report when matcher fails, part 7 ([#7866](https://github.com/facebook/jest/pull/7866))
- `[expect]`: Improve report when matcher fails, part 8 ([#7876](https://github.com/facebook/jest/pull/7876))
- `[expect]`: Improve report when matcher fails, part 9 ([#7940](https://github.com/facebook/jest/pull/7940))
- `[pretty-format]` Support `React.memo` ([#7891](https://github.com/facebook/jest/pull/7891))
- `[jest-config]` Print error information on preset normalization error ([#7935](https://github.com/facebook/jest/pull/7935))

Expand Down
52 changes: 52 additions & 0 deletions packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap
Expand Up @@ -563,6 +563,58 @@ Expected difference: < <green>0.005</>
Received difference: <red>0.005000099999999952</>"
`;

exports[`.toBeCloseTo() throws: Matcher error promise empty isNot false received 1`] = `
"<dim>expect(</><red>received</><dim>).</>toBeCloseTo<dim>(</><green>expected</><dim>, </><green>precision</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a number

Received has type: string
Received has value: <red>\\"\\"</>"
`;

exports[`.toBeCloseTo() throws: Matcher error promise empty isNot true expected 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toBeCloseTo<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <green>expected</> value must be a number

Expected has value: <green>undefined</>"
`;

exports[`.toBeCloseTo() throws: Matcher error promise rejects isNot false expected 1`] = `
"<dim>expect(</><red>received</><dim>).</>rejects<dim>.</>toBeCloseTo<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <green>expected</> value must be a number

Expected has type: string
Expected has value: <green>\\"0\\"</>"
`;

exports[`.toBeCloseTo() throws: Matcher error promise rejects isNot true received 1`] = `
"<dim>expect(</><red>received</><dim>).</>rejects<dim>.</>not<dim>.</>toBeCloseTo<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a number

Received has type: symbol
Received has value: <red>Symbol(0.1)</>"
`;

exports[`.toBeCloseTo() throws: Matcher error promise resolves isNot false received 1`] = `
"<dim>expect(</><red>received</><dim>).</>resolves<dim>.</>toBeCloseTo<dim>(</><green>expected</><dim>, </><green>precision</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a number

Received has type: boolean
Received has value: <red>false</>"
`;

exports[`.toBeCloseTo() throws: Matcher error promise resolves isNot true expected 1`] = `
"<dim>expect(</><red>received</><dim>).</>resolves<dim>.</>not<dim>.</>toBeCloseTo<dim>(</><green>expected</><dim>, </><green>precision</><dim>)</>

<bold>Matcher error</>: <green>expected</> value must be a number

Expected has value: <green>null</>"
`;

exports[`.toBeDefined(), .toBeUndefined() '"a"' is defined 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toBeDefined<dim>()</>

Expand Down
53 changes: 53 additions & 0 deletions packages/expect/src/__tests__/matchers.test.js
Expand Up @@ -998,6 +998,59 @@ describe('.toBeCloseTo()', () => {
).toThrowErrorMatchingSnapshot();
});
});

describe('throws: Matcher error', () => {
test('promise empty isNot false received', () => {
const precision = 3;
const expected = 0;
const received = '';
expect(() => {
jestExpect(received).toBeCloseTo(expected, precision);
}).toThrowErrorMatchingSnapshot();
});

test('promise empty isNot true expected', () => {
const received = 0.1;
// expected is undefined
expect(() => {
jestExpect(received).not.toBeCloseTo();
}).toThrowErrorMatchingSnapshot();
});

test('promise rejects isNot false expected', () => {
const expected = '0';
const received = Promise.reject(0.01);
return expect(
jestExpect(received).rejects.toBeCloseTo(expected),
).rejects.toThrowErrorMatchingSnapshot();
});

test('promise rejects isNot true received', () => {
const expected = 0;
const received = Promise.reject(Symbol('0.1'));
return expect(
jestExpect(received).rejects.not.toBeCloseTo(expected),
).rejects.toThrowErrorMatchingSnapshot();
});

test('promise resolves isNot false received', () => {
const precision = 3;
const expected = 0;
const received = Promise.resolve(false);
return expect(
jestExpect(received).resolves.toBeCloseTo(expected, precision),
).rejects.toThrowErrorMatchingSnapshot();
});

test('promise resolves isNot true expected', () => {
const precision = 3;
const expected = null;
const received = Promise.resolve(0.1);
expect(
jestExpect(received).resolves.not.toBeCloseTo(expected, precision),
).rejects.toThrowErrorMatchingSnapshot();
});
});
});

describe('.toMatch()', () => {
Expand Down
13 changes: 6 additions & 7 deletions packages/expect/src/matchers.ts
Expand Up @@ -93,13 +93,12 @@ const matchers: MatchersObject = {
precision: number = 2,
) {
const secondArgument = arguments.length === 3 ? 'precision' : undefined;
const isNot = this.isNot;
const options: MatcherHintOptions = {
isNot,
isNot: this.isNot,
promise: this.promise,
secondArgument,
};
ensureNumbers(received, expected, '.toBeCloseTo');
ensureNumbers(received, expected, 'toBeCloseTo', options);

let pass = false;
let expectedDiff = 0;
Expand Down Expand Up @@ -180,7 +179,7 @@ const matchers: MatchersObject = {
isNot,
promise: this.promise,
};
ensureNumbers(received, expected, '.toBeGreaterThan');
ensureNumbers(received, expected, 'toBeGreaterThan', options);

const pass = received > expected;

Expand All @@ -203,7 +202,7 @@ const matchers: MatchersObject = {
isNot,
promise: this.promise,
};
ensureNumbers(received, expected, '.toBeGreaterThanOrEqual');
ensureNumbers(received, expected, 'toBeGreaterThanOrEqual', options);

const pass = received >= expected;

Expand Down Expand Up @@ -266,7 +265,7 @@ const matchers: MatchersObject = {
isNot,
promise: this.promise,
};
ensureNumbers(received, expected, '.toBeLessThan');
ensureNumbers(received, expected, 'toBeLessThan', options);

const pass = received < expected;

Expand All @@ -285,7 +284,7 @@ const matchers: MatchersObject = {
isNot,
promise: this.promise,
};
ensureNumbers(received, expected, '.toBeLessThanOrEqual');
ensureNumbers(received, expected, 'toBeLessThanOrEqual', options);

const pass = received <= expected;

Expand Down
Expand Up @@ -18,24 +18,76 @@ Expected has type: object
Expected has value: <green>{\\"a\\": 1}</>"
`;

exports[`.ensureNumbers() throws error when expected is not a number 1`] = `
"<dim>expect(</><red>received</><dim>)[.not]This matcher(</><green>expected</><dim>)</>
exports[`.ensureNumbers() throws error when expected is not a number (backward compatibility) 1`] = `
"<dim>expect(</><red>received</><dim>)[.not].toBeCloseTo(</><green>expected</><dim>)</>

<bold>Matcher error</>: <green>expected</> value must be a number

Expected has type: string
Expected has value: <green>\\"not_a_number\\"</>"
`;

exports[`.ensureNumbers() throws error when received is not a number 1`] = `
"<dim>expect(</><red>received</><dim>)[.not]This matcher(</><green>expected</><dim>)</>
exports[`.ensureNumbers() throws error when received is not a number (backward compatibility) 1`] = `
"<dim>expect(</><red>received</><dim>)[.not].toBeCloseTo(</><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a number

Received has type: string
Received has value: <red>\\"not_a_number\\"</>"
`;

exports[`.ensureNumbers() with options promise empty isNot false received 1`] = `
"<dim>expect(</><red>received</><dim>).</>toBeCloseTo<dim>(</><green>expected</><dim>, </><green>precision</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a number

Received has type: string
Received has value: <red>\\"\\"</>"
`;

exports[`.ensureNumbers() with options promise empty isNot true expected 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toBeCloseTo<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <green>expected</> value must be a number

Expected has value: <green>undefined</>"
`;

exports[`.ensureNumbers() with options promise rejects isNot false expected 1`] = `
"<dim>expect(</><red>received</><dim>).</>rejects<dim>.</>toBeCloseTo<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <green>expected</> value must be a number

Expected has type: string
Expected has value: <green>\\"0\\"</>"
`;

exports[`.ensureNumbers() with options promise rejects isNot true received 1`] = `
"<dim>expect(</><red>received</><dim>).</>rejects<dim>.</>not<dim>.</>toBeCloseTo<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a number

Received has type: symbol
Received has value: <red>Symbol(0.1)</>"
`;

exports[`.ensureNumbers() with options promise resolves isNot false received 1`] = `
"<dim>expect(</><red>received</><dim>).</>resolves<dim>.</>toBeCloseTo<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a number

Received has type: boolean
Received has value: <red>false</>"
`;

exports[`.ensureNumbers() with options promise resolves isNot true expected 1`] = `
"<dim>expect(</><red>received</><dim>).</>resolves<dim>.</>not<dim>.</>toBeCloseTo<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <green>expected</> value must be a number

Expected has value: <green>null</>"
`;

exports[`.stringify() reduces maxDepth if stringifying very large objects 1`] = `"{\\"a\\": 1, \\"b\\": [Object]}"`;

exports[`.stringify() reduces maxDepth if stringifying very large objects 2`] = `"{\\"a\\": 1, \\"b\\": {\\"0\\": \\"test\\", \\"1\\": \\"test\\", \\"2\\": \\"test\\", \\"3\\": \\"test\\", \\"4\\": \\"test\\", \\"5\\": \\"test\\", \\"6\\": \\"test\\", \\"7\\": \\"test\\", \\"8\\": \\"test\\", \\"9\\": \\"test\\"}}"`;
Expand Down
80 changes: 76 additions & 4 deletions packages/jest-matcher-utils/src/__tests__/index.test.ts
Expand Up @@ -13,6 +13,7 @@ import {
getLabelPrinter,
pluralize,
stringify,
MatcherHintOptions,
} from '../';

describe('.stringify()', () => {
Expand Down Expand Up @@ -98,19 +99,90 @@ describe('.ensureNumbers()', () => {
}).not.toThrow();
});

test('throws error when expected is not a number', () => {
test('throws error when expected is not a number (backward compatibility)', () => {
expect(() => {
// @ts-ignore
ensureNumbers(1, 'not_a_number');
ensureNumbers(1, 'not_a_number', '.toBeCloseTo');
}).toThrowErrorMatchingSnapshot();
});

test('throws error when received is not a number', () => {
test('throws error when received is not a number (backward compatibility)', () => {
expect(() => {
// @ts-ignore
ensureNumbers('not_a_number', 3);
ensureNumbers('not_a_number', 3, '.toBeCloseTo');
}).toThrowErrorMatchingSnapshot();
});

describe('with options', () => {
const matcherName = 'toBeCloseTo';

test('promise empty isNot false received', () => {
const options: MatcherHintOptions = {
isNot: false,
promise: '',
secondArgument: 'precision',
};
expect(() => {
// @ts-ignore
ensureNumbers('', 0, matcherName, options);
}).toThrowErrorMatchingSnapshot();
});

test('promise empty isNot true expected', () => {
const options: MatcherHintOptions = {
isNot: true,
// promise undefined is equivalent to empty string
};
expect(() => {
// @ts-ignore
ensureNumbers(0.1, undefined, matcherName, options);
}).toThrowErrorMatchingSnapshot();
});

test('promise rejects isNot false expected', () => {
const options: MatcherHintOptions = {
isNot: false,
promise: 'rejects',
};
expect(() => {
// @ts-ignore
ensureNumbers(0.01, '0', matcherName, options);
}).toThrowErrorMatchingSnapshot();
});

test('promise rejects isNot true received', () => {
const options: MatcherHintOptions = {
isNot: true,
promise: 'rejects',
};
expect(() => {
// @ts-ignore
ensureNumbers(Symbol('0.1'), 0, matcherName, options);
}).toThrowErrorMatchingSnapshot();
});

test('promise resolves isNot false received', () => {
const options: MatcherHintOptions = {
isNot: false,
promise: 'resolves',
};
expect(() => {
// @ts-ignore
ensureNumbers(false, 0, matcherName, options);
}).toThrowErrorMatchingSnapshot();
});

test('promise resolves isNot true expected', () => {
const options: MatcherHintOptions = {
isNot: true,
promise: 'resolves',
};
expect(() => {
// @ts-ignore
ensureNumbers(0.1, null, matcherName, options);
}).toThrowErrorMatchingSnapshot();
});
});
});

describe('.ensureNoExpected()', () => {
Expand Down