Skip to content

Commit

Permalink
Merge pull request #106 from mircohacker/feature/add_full_stacktrace_…
Browse files Browse the repository at this point in the history
…to_error_message

Print full stack trace if verifyAllWhenMocksCalled fails
  • Loading branch information
timkindberg authored Aug 7, 2023
2 parents 647c968 + 5c227e8 commit bfac469
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 13 deletions.
22 changes: 11 additions & 11 deletions src/when.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const assert = require('assert')

let registry = new Set()

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

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

if (matchers && matchers[0] &&
// is a possible all args matcher object
(typeof matchers[0] === 'function' || typeof matchers[0] === 'object') &&
// ensure not a proxy
'_isAllArgsFunctionMatcher' in matchers[0] &&
// check for the special property name
matchers[0]._isAllArgsFunctionMatcher === true
// is a possible all args matcher object
(typeof matchers[0] === 'function' || typeof matchers[0] === 'object') &&
// ensure not a proxy
'_isAllArgsFunctionMatcher' in matchers[0] &&
// check for the special property name
matchers[0]._isAllArgsFunctionMatcher === true
) {
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.')
isMatch = checkArgumentMatchers(expectCall, [args])(true, matchers[0], 0)
Expand Down Expand Up @@ -224,11 +224,11 @@ const verifyAllWhenMocksCalled = () => {
}, [[], [], []])

const callLines = uncalledMocks
.filter(m => Boolean(m.callLine))
.map(m => `\n ${String(m.callLine).trim()}`)
.filter(m => Boolean(m.callLines))
.map(m => `\n ${String(m.callLines).trim()}`)
.join('')

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

assert.equal(`called mocks: ${calledMocks.length}`, `called mocks: ${allMocks.length}`, msg)
}
Expand Down
33 changes: 31 additions & 2 deletions src/when.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,29 @@ describe('When', () => {
expect(caughtErr.message).toMatch(/Failed verifyAllWhenMocksCalled: 2 not called/)
})

it('should print a full stacktrace if verification check fails', () => {
const fn1 = jest.fn()

function extractedWhenConfiguration () {
when(fn1).expectCalledWith(expect.anything()).mockReturnValueOnce('z')
}

extractedWhenConfiguration()
extractedWhenConfiguration()

fn1(1)

let caughtErr

try {
verifyAllWhenMocksCalled()
} catch (e) {
caughtErr = e
}

expect(caughtErr.message).toContain('at Object.extractedWhenConfiguration')
})

it('fails verification check if all mocks were not called with line numbers', () => {
const fn1 = jest.fn()
const fn2 = jest.fn()
Expand All @@ -121,8 +144,14 @@ describe('When', () => {
fn1(1)
fn2(1)

// Should be two call lines printed, hence the {2} at the end of the regex
expect(verifyAllWhenMocksCalled).toThrow(/(src(?:\\|\/)when\.test\.js:\d{3}(.|\s)*){2}/)
try {
verifyAllWhenMocksCalled()
} catch (e) {
const errorLines = e.message.split('\n')
const currentFilePathPattern = /src(?:\\|\/)when\.test\.js:\d{3}(.|\s)*/
const numberOfMatches = errorLines.filter(line => currentFilePathPattern.test(line)).length
expect(numberOfMatches).toBe(2)
}
})
})

Expand Down

0 comments on commit bfac469

Please sign in to comment.