Skip to content

Commit bfac469

Browse files
authored
Merge pull request #106 from mircohacker/feature/add_full_stacktrace_to_error_message
Print full stack trace if verifyAllWhenMocksCalled fails
2 parents 647c968 + 5c227e8 commit bfac469

File tree

2 files changed

+42
-13
lines changed

2 files changed

+42
-13
lines changed

src/when.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const assert = require('assert')
22

33
let registry = new Set()
44

5-
const getCallLine = () => (new Error()).stack.split('\n')[4]
5+
const getCallLines = () => (new Error()).stack.split('\n').slice(4).join('\n')
66

77
/**
88
* A hack to capture a reference to the `equals` jasmineUtil
@@ -73,7 +73,7 @@ class WhenMock {
7373
// * `once` mocks are used prioritized
7474
this.callMocks = this.callMocks
7575
.filter((callMock) => once || callMock.once || !equals(callMock.matchers, matchers))
76-
.concat({ matchers, mockImplementation, expectCall, once, called: false, id: this.nextCallMockId, callLine: getCallLine() })
76+
.concat({ matchers, mockImplementation, expectCall, once, called: false, id: this.nextCallMockId, callLines: getCallLines() })
7777
.sort((a, b) => {
7878
// Once mocks should appear before the rest
7979
if (a.once !== b.once) {
@@ -95,12 +95,12 @@ class WhenMock {
9595
let isMatch = false
9696

9797
if (matchers && matchers[0] &&
98-
// is a possible all args matcher object
99-
(typeof matchers[0] === 'function' || typeof matchers[0] === 'object') &&
100-
// ensure not a proxy
101-
'_isAllArgsFunctionMatcher' in matchers[0] &&
102-
// check for the special property name
103-
matchers[0]._isAllArgsFunctionMatcher === true
98+
// is a possible all args matcher object
99+
(typeof matchers[0] === 'function' || typeof matchers[0] === 'object') &&
100+
// ensure not a proxy
101+
'_isAllArgsFunctionMatcher' in matchers[0] &&
102+
// check for the special property name
103+
matchers[0]._isAllArgsFunctionMatcher === true
104104
) {
105105
if (matchers.length > 1) throw new Error('When using when.allArgs, it must be the one and only matcher provided to calledWith. You have incorrectly provided other matchers along with when.allArgs.')
106106
isMatch = checkArgumentMatchers(expectCall, [args])(true, matchers[0], 0)
@@ -224,11 +224,11 @@ const verifyAllWhenMocksCalled = () => {
224224
}, [[], [], []])
225225

226226
const callLines = uncalledMocks
227-
.filter(m => Boolean(m.callLine))
228-
.map(m => `\n ${String(m.callLine).trim()}`)
227+
.filter(m => Boolean(m.callLines))
228+
.map(m => `\n ${String(m.callLines).trim()}`)
229229
.join('')
230230

231-
const msg = `Failed verifyAllWhenMocksCalled: ${uncalledMocks.length} not called at:${callLines}\n\n\n...rest of the stack...`
231+
const msg = `Failed verifyAllWhenMocksCalled: ${uncalledMocks.length} not called: ${callLines}\n\n\n...rest of the stack...`
232232

233233
assert.equal(`called mocks: ${calledMocks.length}`, `called mocks: ${allMocks.length}`, msg)
234234
}

src/when.test.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,29 @@ describe('When', () => {
109109
expect(caughtErr.message).toMatch(/Failed verifyAllWhenMocksCalled: 2 not called/)
110110
})
111111

112+
it('should print a full stacktrace if verification check fails', () => {
113+
const fn1 = jest.fn()
114+
115+
function extractedWhenConfiguration () {
116+
when(fn1).expectCalledWith(expect.anything()).mockReturnValueOnce('z')
117+
}
118+
119+
extractedWhenConfiguration()
120+
extractedWhenConfiguration()
121+
122+
fn1(1)
123+
124+
let caughtErr
125+
126+
try {
127+
verifyAllWhenMocksCalled()
128+
} catch (e) {
129+
caughtErr = e
130+
}
131+
132+
expect(caughtErr.message).toContain('at Object.extractedWhenConfiguration')
133+
})
134+
112135
it('fails verification check if all mocks were not called with line numbers', () => {
113136
const fn1 = jest.fn()
114137
const fn2 = jest.fn()
@@ -121,8 +144,14 @@ describe('When', () => {
121144
fn1(1)
122145
fn2(1)
123146

124-
// Should be two call lines printed, hence the {2} at the end of the regex
125-
expect(verifyAllWhenMocksCalled).toThrow(/(src(?:\\|\/)when\.test\.js:\d{3}(.|\s)*){2}/)
147+
try {
148+
verifyAllWhenMocksCalled()
149+
} catch (e) {
150+
const errorLines = e.message.split('\n')
151+
const currentFilePathPattern = /src(?:\\|\/)when\.test\.js:\d{3}(.|\s)*/
152+
const numberOfMatches = errorLines.filter(line => currentFilePathPattern.test(line)).length
153+
expect(numberOfMatches).toBe(2)
154+
}
126155
})
127156
})
128157

0 commit comments

Comments
 (0)