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: Improve report when matcher fails, part 19 #8367

Merged
merged 5 commits into from Apr 25, 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 @@ -10,6 +10,7 @@
- `[docs]` Add DynamoDB guide ([#8319](https://github.com/facebook/jest/pull/8319))
- `[expect]` Improve report when matcher fails, part 17 ([#8349](https://github.com/facebook/jest/pull/8349))
- `[expect]` Improve report when matcher fails, part 18 ([#8356](https://github.com/facebook/jest/pull/8356))
- `[expect]` Improve report when matcher fails, part 19 ([#8367](https://github.com/facebook/jest/pull/8367))

### Fixes

Expand Down
31 changes: 23 additions & 8 deletions packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap
Expand Up @@ -1265,6 +1265,7 @@ exports[`.toBeInstanceOf() failing "a" and [Function String] 1`] = `
"<dim>expect(</><red>received</><dim>).</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: <green>String</>

Received value has no prototype
Received value: <red>\\"a\\"</>"
`;
Expand All @@ -1274,13 +1275,14 @@ exports[`.toBeInstanceOf() failing /\\w+/ and [Function anonymous] 1`] = `

Expected constructor name is an empty string
Received constructor: <red>RegExp</>
Received value: <red>/\\\\w+/</>"
"
`;

exports[`.toBeInstanceOf() failing {} and [Function A] 1`] = `
"<dim>expect(</><red>received</><dim>).</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: <green>A</>

Received value has no prototype
Received value: <red>{}</>"
`;
Expand All @@ -1290,21 +1292,22 @@ exports[`.toBeInstanceOf() failing {} and [Function B] 1`] = `

Expected constructor: <green>B</>
Received constructor: <red>A</>
Received value: <red>{}</>"
"
`;

exports[`.toBeInstanceOf() failing {} and [Function RegExp] 1`] = `
"<dim>expect(</><red>received</><dim>).</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: <green>RegExp</>
Received constructor name is an empty string
Received value: <red>{}</>"
"
`;

exports[`.toBeInstanceOf() failing 1 and [Function Number] 1`] = `
"<dim>expect(</><red>received</><dim>).</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: <green>Number</>

Received value has no prototype
Received value: <red>1</>"
`;
Expand All @@ -1313,6 +1316,7 @@ exports[`.toBeInstanceOf() failing null and [Function String] 1`] = `
"<dim>expect(</><red>received</><dim>).</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: <green>String</>

Received value has no prototype
Received value: <red>null</>"
`;
Expand All @@ -1321,6 +1325,7 @@ exports[`.toBeInstanceOf() failing true and [Function Boolean] 1`] = `
"<dim>expect(</><red>received</><dim>).</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: <green>Boolean</>

Received value has no prototype
Received value: <red>true</>"
`;
Expand All @@ -1329,6 +1334,7 @@ exports[`.toBeInstanceOf() failing undefined and [Function String] 1`] = `
"<dim>expect(</><red>received</><dim>).</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: <green>String</>

Received value has no prototype
Received value: <red>undefined</>"
`;
Expand All @@ -1337,35 +1343,44 @@ exports[`.toBeInstanceOf() passing [] and [Function Array] 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: not <green>Array</>
Received value: <red>[]</>"
"
`;

exports[`.toBeInstanceOf() passing {} and [Function A] 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: not <green>A</>
Received value: <red>{}</>"
"
`;

exports[`.toBeInstanceOf() passing {} and [Function B] 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: not <green>B</>
Received value: <red>{}</>"
Received constructor: <red>C</> extends <green>B</>
"
`;

exports[`.toBeInstanceOf() passing {} and [Function B] 2`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: not <green>B</>
Received constructor: <red>E</> extends … extends <green>B</>
"
`;

exports[`.toBeInstanceOf() passing {} and [Function name() {}] 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor name is not a string
Received value: <red>{}</>"
"
`;

exports[`.toBeInstanceOf() passing Map {} and [Function Map] 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toBeInstanceOf<dim>(</><green>expected</><dim>)</>

Expected constructor: not <green>Map</>
Received value: <red>Map {}</>"
"
`;

exports[`.toBeInstanceOf() throws if constructor is not a function 1`] = `
Expand Down
Expand Up @@ -89,16 +89,16 @@ Received message: <red>\\"apple\\"</>
exports[`toThrow error class did not throw at all 1`] = `
"<dim>expect(</><red>received</><dim>).</>toThrow<dim>(</><green>expected</><dim>)</>

Expected name: <green>\\"Err\\"</>
Expected constructor: <green>Err</>

Received function did not throw"
`;

exports[`toThrow error class threw, but class did not match (error) 1`] = `
"<dim>expect(</><red>received</><dim>).</>toThrow<dim>(</><green>expected</><dim>)</>

Expected name: <green>\\"Err2\\"</>
Received name: <red>\\"Error\\"</>
Expected constructor: <green>Err2</>
Received constructor: <red>Err</>

Received message: <red>\\"apple\\"</>

Expand All @@ -108,17 +108,38 @@ Received message: <red>\\"apple\\"</>
exports[`toThrow error class threw, but class did not match (non-error falsey) 1`] = `
"<dim>expect(</><red>received</><dim>).</>toThrow<dim>(</><green>expected</><dim>)</>

Expected name: <green>\\"Err2\\"</>
Expected constructor: <green>Err2</>

Received value: <red>undefined</>
"
`;

exports[`toThrow error class threw, but class should not match (error subclass) 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toThrow<dim>(</><green>expected</><dim>)</>

Expected constructor: not <green>Err</>
Received constructor: <red>SubErr</> extends <green>Err</>

Received message: <red>\\"apple\\"</>

<dim>at jestExpect (</>packages/expect/src/__tests__/toThrowMatchers-test.js<dim>:24:74)</>"
`;

exports[`toThrow error class threw, but class should not match (error subsubclass) 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toThrow<dim>(</><green>expected</><dim>)</>

Expected constructor: not <green>Err</>
Received constructor: <red>SubSubErr</> extends … extends <green>Err</>

Received message: <red>\\"apple\\"</>

<dim>at jestExpect (</>packages/expect/src/__tests__/toThrowMatchers-test.js<dim>:24:74)</>"
`;

exports[`toThrow error class threw, but class should not match (error) 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toThrow<dim>(</><green>expected</><dim>)</>

Expected name: <green>\\"Err\\"</>
Received name: <red>\\"Error\\"</>
Expected constructor: not <green>Err</>

Received message: <red>\\"apple\\"</>

Expand Down Expand Up @@ -174,8 +195,8 @@ Received function did not throw"
exports[`toThrow promise/async throws if Error-like object is returned threw, but class did not match 1`] = `
"<dim>expect(</><red>received</><dim>).</>rejects<dim>.</>toThrow<dim>(</><green>expected</><dim>)</>

Expected name: <green>\\"Err2\\"</>
Received name: <red>\\"Error\\"</>
Expected constructor: <green>Err2</>
Received constructor: <red>Err</>

Received message: <red>\\"async apple\\"</>

Expand Down Expand Up @@ -364,16 +385,16 @@ Received message: <red>\\"apple\\"</>
exports[`toThrowError error class did not throw at all 1`] = `
"<dim>expect(</><red>received</><dim>).</>toThrowError<dim>(</><green>expected</><dim>)</>

Expected name: <green>\\"Err\\"</>
Expected constructor: <green>Err</>

Received function did not throw"
`;

exports[`toThrowError error class threw, but class did not match (error) 1`] = `
"<dim>expect(</><red>received</><dim>).</>toThrowError<dim>(</><green>expected</><dim>)</>

Expected name: <green>\\"Err2\\"</>
Received name: <red>\\"Error\\"</>
Expected constructor: <green>Err2</>
Received constructor: <red>Err</>

Received message: <red>\\"apple\\"</>

Expand All @@ -383,17 +404,38 @@ Received message: <red>\\"apple\\"</>
exports[`toThrowError error class threw, but class did not match (non-error falsey) 1`] = `
"<dim>expect(</><red>received</><dim>).</>toThrowError<dim>(</><green>expected</><dim>)</>

Expected name: <green>\\"Err2\\"</>
Expected constructor: <green>Err2</>

Received value: <red>undefined</>
"
`;

exports[`toThrowError error class threw, but class should not match (error subclass) 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toThrowError<dim>(</><green>expected</><dim>)</>

Expected constructor: not <green>Err</>
Received constructor: <red>SubErr</> extends <green>Err</>

Received message: <red>\\"apple\\"</>

<dim>at jestExpect (</>packages/expect/src/__tests__/toThrowMatchers-test.js<dim>:24:74)</>"
`;

exports[`toThrowError error class threw, but class should not match (error subsubclass) 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toThrowError<dim>(</><green>expected</><dim>)</>

Expected constructor: not <green>Err</>
Received constructor: <red>SubSubErr</> extends … extends <green>Err</>

Received message: <red>\\"apple\\"</>

<dim>at jestExpect (</>packages/expect/src/__tests__/toThrowMatchers-test.js<dim>:24:74)</>"
jeysal marked this conversation as resolved.
Show resolved Hide resolved
`;

exports[`toThrowError error class threw, but class should not match (error) 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toThrowError<dim>(</><green>expected</><dim>)</>

Expected name: <green>\\"Err\\"</>
Received name: <red>\\"Error\\"</>
Expected constructor: not <green>Err</>

Received message: <red>\\"apple\\"</>

Expand Down Expand Up @@ -449,8 +491,8 @@ Received function did not throw"
exports[`toThrowError promise/async throws if Error-like object is returned threw, but class did not match 1`] = `
"<dim>expect(</><red>received</><dim>).</>rejects<dim>.</>toThrowError<dim>(</><green>expected</><dim>)</>

Expected name: <green>\\"Err2\\"</>
Received name: <red>\\"Error\\"</>
Expected constructor: <green>Err2</>
Received constructor: <red>Err</>

Received message: <red>\\"async apple\\"</>

Expand Down
5 changes: 4 additions & 1 deletion packages/expect/src/__tests__/matchers.test.js
Expand Up @@ -687,6 +687,8 @@ describe('.toBeInstanceOf()', () => {
class A {}
class B {}
class C extends B {}
class D extends C {}
class E extends D {}

class HasStaticNameMethod {
constructor() {}
Expand All @@ -705,7 +707,8 @@ describe('.toBeInstanceOf()', () => {
[new Map(), Map],
[[], Array],
[new A(), A],
[new C(), B], // subclass
[new C(), B], // C extends B
[new E(), B], // E extends … extends B
[new HasStaticNameMethod(), HasStaticNameMethod],
].forEach(([a, b]) => {
test(`passing ${stringify(a)} and ${stringify(b)}`, () => {
Expand Down
34 changes: 34 additions & 0 deletions packages/expect/src/__tests__/toThrowMatchers.test.js
Expand Up @@ -146,6 +146,24 @@ class customError extends Error {
});

describe('error class', () => {
class SubErr extends Err {
constructor(...args) {
super(...args);
// In a carefully written error subclass,
// name property is equal to constructor name.
this.name = this.constructor.name;
}
}

class SubSubErr extends SubErr {
constructor(...args) {
super(...args);
// In a carefully written error subclass,
// name property is equal to constructor name.
this.name = this.constructor.name;
}
}

it('passes', () => {
jestExpect(() => {
throw new Err();
Expand Down Expand Up @@ -189,6 +207,22 @@ class customError extends Error {
}).not[toThrow](Err);
}).toThrowErrorMatchingSnapshot();
});

test('threw, but class should not match (error subclass)', () => {
expect(() => {
jestExpect(() => {
throw new SubErr('apple');
}).not[toThrow](Err);
}).toThrowErrorMatchingSnapshot();
});

test('threw, but class should not match (error subsubclass)', () => {
expect(() => {
jestExpect(() => {
throw new SubSubErr('apple');
}).not[toThrow](Err);
}).toThrowErrorMatchingSnapshot();
});
});

describe('error-message', () => {
Expand Down