Skip to content

Commit f857d30

Browse files
authored
expect: Throw matcher error when received cannot be jasmine spy (#8747)
* expect: Improve report when mock-spy matcher fails, part 5 * Update CHANGELOG.md * Edit CHANGELOG.md
1 parent cb322d1 commit f857d30

File tree

4 files changed

+115
-37
lines changed

4 files changed

+115
-37
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- `[expect]` Improve report when mock-spy matcher fails, part 2 ([#8649](https://github.com/facebook/jest/pull/8649))
99
- `[expect]` Improve report when mock-spy matcher fails, part 3 ([#8697](https://github.com/facebook/jest/pull/8697))
1010
- `[expect]` Improve report when mock-spy matcher fails, part 4 ([#8710](https://github.com/facebook/jest/pull/8710))
11+
- `[expect]` Throw matcher error when received cannot be jasmine spy ([#8747](https://github.com/facebook/jest/pull/8747))
1112
- `[jest-snapshot]` Highlight substring differences when matcher fails, part 3 ([#8569](https://github.com/facebook/jest/pull/8569))
1213
- `[jest-cli]` Improve chai support (with detailed output, to match jest exceptions) ([#8454](https://github.com/facebook/jest/pull/8454))
1314
- `[*]` Manage the global timeout with `--testTimeout` command line argument. ([#8456](https://github.com/facebook/jest/pull/8456))

packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ Number of returns: <red>3</>"
180180
exports[`lastReturnedWith works only on spies or jest.fn 1`] = `
181181
"<dim>expect(</><red>received</><dim>).</>lastReturnedWith<dim>(</><green>expected</><dim>)</>
182182

183-
<bold>Matcher error</>: <red>received</> value must be a mock or spy function
183+
<bold>Matcher error</>: <red>received</> value must be a mock function
184184

185185
Received has type: function
186186
Received has value: <red>[Function fn]</>"
@@ -590,7 +590,7 @@ Number of returns: <red>3</>"
590590
exports[`nthReturnedWith works only on spies or jest.fn 1`] = `
591591
"<dim>expect(</><red>received</><dim>).</>nthReturnedWith<dim>(</><green>n</><dim>, </><green>expected</><dim>)</>
592592

593-
<bold>Matcher error</>: <red>received</> value must be a mock or spy function
593+
<bold>Matcher error</>: <red>received</> value must be a mock function
594594

595595
Received has type: function
596596
Received has value: <red>[Function fn]</>"
@@ -699,7 +699,7 @@ Expected has value: <green>555</>"
699699
`;
700700

701701
exports[`toBeCalled .not passes when called 1`] = `
702-
"<dim>expect(</><red>jest.fn()</><dim>).</>toBeCalled<dim>()</>
702+
"<dim>expect(</><red>spy</><dim>).</>toBeCalled<dim>()</>
703703

704704
Expected number of calls: >= <green>1</>
705705
Received number of calls: <red>0</>"
@@ -880,7 +880,7 @@ Expected has value: <green>[Function anonymous]</>"
880880
`;
881881

882882
exports[`toBeCalledTimes passes if function called equal to expected times 1`] = `
883-
"<dim>expect(</><red>jest.fn()</><dim>).</>not<dim>.</>toBeCalledTimes<dim>(</><green>expected</><dim>)</>
883+
"<dim>expect(</><red>spy</><dim>).</>not<dim>.</>toBeCalledTimes<dim>(</><green>expected</><dim>)</>
884884

885885
Expected number of calls: not <green>2</>"
886886
`;
@@ -1029,7 +1029,7 @@ Expected has value: <green>555</>"
10291029
`;
10301030

10311031
exports[`toHaveBeenCalled .not passes when called 1`] = `
1032-
"<dim>expect(</><red>jest.fn()</><dim>).</>toHaveBeenCalled<dim>()</>
1032+
"<dim>expect(</><red>spy</><dim>).</>toHaveBeenCalled<dim>()</>
10331033

10341034
Expected number of calls: >= <green>1</>
10351035
Received number of calls: <red>0</>"
@@ -1210,7 +1210,7 @@ Expected has value: <green>[Function anonymous]</>"
12101210
`;
12111211

12121212
exports[`toHaveBeenCalledTimes passes if function called equal to expected times 1`] = `
1213-
"<dim>expect(</><red>jest.fn()</><dim>).</>not<dim>.</>toHaveBeenCalledTimes<dim>(</><green>expected</><dim>)</>
1213+
"<dim>expect(</><red>spy</><dim>).</>not<dim>.</>toHaveBeenCalledTimes<dim>(</><green>expected</><dim>)</>
12141214

12151215
Expected number of calls: not <green>2</>"
12161216
`;
@@ -1689,7 +1689,7 @@ Number of returns: <red>3</>"
16891689
exports[`toHaveLastReturnedWith works only on spies or jest.fn 1`] = `
16901690
"<dim>expect(</><red>received</><dim>).</>toHaveLastReturnedWith<dim>(</><green>expected</><dim>)</>
16911691

1692-
<bold>Matcher error</>: <red>received</> value must be a mock or spy function
1692+
<bold>Matcher error</>: <red>received</> value must be a mock function
16931693

16941694
Received has type: function
16951695
Received has value: <red>[Function fn]</>"
@@ -1939,7 +1939,7 @@ Number of returns: <red>3</>"
19391939
exports[`toHaveNthReturnedWith works only on spies or jest.fn 1`] = `
19401940
"<dim>expect(</><red>received</><dim>).</>toHaveNthReturnedWith<dim>(</><green>n</><dim>, </><green>expected</><dim>)</>
19411941

1942-
<bold>Matcher error</>: <red>received</> value must be a mock or spy function
1942+
<bold>Matcher error</>: <red>received</> value must be a mock function
19431943

19441944
Received has type: function
19451945
Received has value: <red>[Function fn]</>"
@@ -2073,7 +2073,7 @@ Received number of returns: <red>0</>"
20732073
exports[`toHaveReturned .not works only on jest.fn 1`] = `
20742074
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toHaveReturned<dim>()</>
20752075

2076-
<bold>Matcher error</>: <red>received</> value must be a mock or spy function
2076+
<bold>Matcher error</>: <red>received</> value must be a mock function
20772077

20782078
Received has type: function
20792079
Received has value: <red>[Function fn]</>"
@@ -2135,6 +2135,15 @@ Received number of returns: <red>1</>
21352135
1: <red>undefined</>"
21362136
`;
21372137

2138+
exports[`toHaveReturned throw matcher error if received is spy 1`] = `
2139+
"<dim>expect(</><red>received</><dim>).</>toHaveReturned<dim>()</>
2140+
2141+
<bold>Matcher error</>: <red>received</> value must be a mock function
2142+
2143+
Received has type: function
2144+
Received has value: <red>[Function spy]</>"
2145+
`;
2146+
21382147
exports[`toHaveReturnedTimes .not only accepts a number argument 1`] = `
21392148
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toHaveReturnedTimes<dim>(</><green>expected</><dim>)</>
21402149

@@ -2300,13 +2309,13 @@ exports[`toHaveReturnedTimes passes if function returned equal to expected times
23002309
Expected number of returns: not <green>2</>"
23012310
`;
23022311

2303-
exports[`toHaveReturnedTimes works only on spies or jest.fn 1`] = `
2304-
"<dim>expect(</><red>received</><dim>).</>toHaveReturnedTimes<dim>(</><green>expected</><dim>)</>
2312+
exports[`toHaveReturnedTimes throw matcher error if received is spy 1`] = `
2313+
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toHaveReturnedTimes<dim>(</><green>expected</><dim>)</>
23052314

2306-
<bold>Matcher error</>: <red>received</> value must be a mock or spy function
2315+
<bold>Matcher error</>: <red>received</> value must be a mock function
23072316

23082317
Received has type: function
2309-
Received has value: <red>[Function fn]</>"
2318+
Received has value: <red>[Function spy]</>"
23102319
`;
23112320

23122321
exports[`toHaveReturnedWith a call that throws is not considered to have returned 1`] = `
@@ -2365,7 +2374,7 @@ Number of returns: <red>6</>"
23652374
exports[`toHaveReturnedWith works only on spies or jest.fn 1`] = `
23662375
"<dim>expect(</><red>received</><dim>).</>toHaveReturnedWith<dim>(</><green>expected</><dim>)</>
23672376

2368-
<bold>Matcher error</>: <red>received</> value must be a mock or spy function
2377+
<bold>Matcher error</>: <red>received</> value must be a mock function
23692378

23702379
Received has type: function
23712380
Received has value: <red>[Function fn]</>"
@@ -2489,7 +2498,7 @@ Received number of returns: <red>0</>"
24892498
exports[`toReturn .not works only on jest.fn 1`] = `
24902499
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toReturn<dim>()</>
24912500

2492-
<bold>Matcher error</>: <red>received</> value must be a mock or spy function
2501+
<bold>Matcher error</>: <red>received</> value must be a mock function
24932502

24942503
Received has type: function
24952504
Received has value: <red>[Function fn]</>"
@@ -2551,6 +2560,15 @@ Received number of returns: <red>1</>
25512560
1: <red>undefined</>"
25522561
`;
25532562

2563+
exports[`toReturn throw matcher error if received is spy 1`] = `
2564+
"<dim>expect(</><red>received</><dim>).</>toReturn<dim>()</>
2565+
2566+
<bold>Matcher error</>: <red>received</> value must be a mock function
2567+
2568+
Received has type: function
2569+
Received has value: <red>[Function spy]</>"
2570+
`;
2571+
25542572
exports[`toReturnTimes .not only accepts a number argument 1`] = `
25552573
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toReturnTimes<dim>(</><green>expected</><dim>)</>
25562574

@@ -2716,13 +2734,13 @@ exports[`toReturnTimes passes if function returned equal to expected times 1`] =
27162734
Expected number of returns: not <green>2</>"
27172735
`;
27182736

2719-
exports[`toReturnTimes works only on spies or jest.fn 1`] = `
2720-
"<dim>expect(</><red>received</><dim>).</>toReturnTimes<dim>(</><green>expected</><dim>)</>
2737+
exports[`toReturnTimes throw matcher error if received is spy 1`] = `
2738+
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toReturnTimes<dim>(</><green>expected</><dim>)</>
27212739

2722-
<bold>Matcher error</>: <red>received</> value must be a mock or spy function
2740+
<bold>Matcher error</>: <red>received</> value must be a mock function
27232741

27242742
Received has type: function
2725-
Received has value: <red>[Function fn]</>"
2743+
Received has value: <red>[Function spy]</>"
27262744
`;
27272745

27282746
exports[`toReturnWith a call that throws is not considered to have returned 1`] = `
@@ -2781,7 +2799,7 @@ Number of returns: <red>6</>"
27812799
exports[`toReturnWith works only on spies or jest.fn 1`] = `
27822800
"<dim>expect(</><red>received</><dim>).</>toReturnWith<dim>(</><green>expected</><dim>)</>
27832801

2784-
<bold>Matcher error</>: <red>received</> value must be a mock or spy function
2802+
<bold>Matcher error</>: <red>received</> value must be a mock function
27852803

27862804
Received has type: function
27872805
Received has value: <red>[Function fn]</>"

packages/expect/src/__tests__/spyMatchers.test.js

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@
88
const Immutable = require('immutable');
99
const jestExpect = require('../');
1010

11+
// Given a Jest mock function, return a minimal mock of a Jasmine spy.
12+
const createSpy = fn => {
13+
const spy = function() {};
14+
15+
spy.calls = {
16+
all() {
17+
return fn.mock.calls.map(args => ({args}));
18+
},
19+
count() {
20+
return fn.mock.calls.length;
21+
},
22+
};
23+
24+
return spy;
25+
};
26+
1127
['toBeCalled', 'toHaveBeenCalled'].forEach(called => {
1228
describe(`${called}`, () => {
1329
test(`works only on spies or jest.fn`, () => {
@@ -19,15 +35,18 @@ const jestExpect = require('../');
1935
test(`passes when called`, () => {
2036
const fn = jest.fn();
2137
fn('arg0', 'arg1', 'arg2');
38+
jestExpect(createSpy(fn))[called]();
2239
jestExpect(fn)[called]();
2340
expect(() => jestExpect(fn).not[called]()).toThrowErrorMatchingSnapshot();
2441
});
2542

2643
test(`.not passes when called`, () => {
2744
const fn = jest.fn();
45+
const spy = createSpy(fn);
2846

47+
jestExpect(spy).not[called]();
2948
jestExpect(fn).not[called]();
30-
expect(() => jestExpect(fn)[called]()).toThrowErrorMatchingSnapshot();
49+
expect(() => jestExpect(spy)[called]()).toThrowErrorMatchingSnapshot();
3150
});
3251

3352
test(`fails with any argument passed`, () => {
@@ -93,10 +112,12 @@ const jestExpect = require('../');
93112
fn();
94113
fn();
95114

115+
const spy = createSpy(fn);
116+
jestExpect(spy)[calledTimes](2);
96117
jestExpect(fn)[calledTimes](2);
97118

98119
expect(() =>
99-
jestExpect(fn).not[calledTimes](2),
120+
jestExpect(spy).not[calledTimes](2),
100121
).toThrowErrorMatchingSnapshot();
101122
});
102123

@@ -106,6 +127,10 @@ const jestExpect = require('../');
106127
fn();
107128
fn();
108129

130+
const spy = createSpy(fn);
131+
jestExpect(spy)[calledTimes](3);
132+
jestExpect(spy).not[calledTimes](2);
133+
109134
jestExpect(fn)[calledTimes](3);
110135
jestExpect(fn).not[calledTimes](2);
111136

@@ -118,6 +143,10 @@ const jestExpect = require('../');
118143
const fn = jest.fn();
119144
fn();
120145

146+
const spy = createSpy(fn);
147+
jestExpect(spy)[calledTimes](1);
148+
jestExpect(spy).not[calledTimes](2);
149+
121150
jestExpect(fn)[calledTimes](1);
122151
jestExpect(fn).not[calledTimes](2);
123152

@@ -164,6 +193,7 @@ const jestExpect = require('../');
164193

165194
test(`works when not called`, () => {
166195
const fn = jest.fn();
196+
caller(jestExpect(createSpy(fn)).not[calledWith], 'foo', 'bar');
167197
caller(jestExpect(fn).not[calledWith], 'foo', 'bar');
168198

169199
expect(() =>
@@ -174,13 +204,15 @@ const jestExpect = require('../');
174204
test(`works with no arguments`, () => {
175205
const fn = jest.fn();
176206
fn();
207+
caller(jestExpect(createSpy(fn))[calledWith]);
177208
caller(jestExpect(fn)[calledWith]);
178209
});
179210

180211
test(`works with arguments that don't match`, () => {
181212
const fn = jest.fn();
182213
fn('foo', 'bar1');
183214

215+
caller(jestExpect(createSpy(fn)).not[calledWith], 'foo', 'bar');
184216
caller(jestExpect(fn).not[calledWith], 'foo', 'bar');
185217

186218
expect(() =>
@@ -192,6 +224,7 @@ const jestExpect = require('../');
192224
const fn = jest.fn();
193225
fn('foo', 'bar');
194226

227+
caller(jestExpect(createSpy(fn))[calledWith], 'foo', 'bar');
195228
caller(jestExpect(fn)[calledWith], 'foo', 'bar');
196229

197230
expect(() =>
@@ -389,6 +422,12 @@ const jestExpect = require('../');
389422
).toThrowErrorMatchingSnapshot();
390423
});
391424

425+
test(`throw matcher error if received is spy`, () => {
426+
const spy = createSpy(jest.fn());
427+
428+
expect(() => jestExpect(spy)[returned]()).toThrowErrorMatchingSnapshot();
429+
});
430+
392431
test(`passes when returned`, () => {
393432
const fn = jest.fn(() => 42);
394433
fn();
@@ -525,11 +564,11 @@ const jestExpect = require('../');
525564

526565
['toReturnTimes', 'toHaveReturnedTimes'].forEach(returnedTimes => {
527566
describe(`${returnedTimes}`, () => {
528-
test('works only on spies or jest.fn', () => {
529-
const fn = function fn() {};
567+
test('throw matcher error if received is spy', () => {
568+
const spy = createSpy(jest.fn());
530569

531570
expect(() =>
532-
jestExpect(fn)[returnedTimes](2),
571+
jestExpect(spy).not[returnedTimes](2),
533572
).toThrowErrorMatchingSnapshot();
534573
});
535574

0 commit comments

Comments
 (0)