Skip to content

Commit 0fb21fa

Browse files
authored
fix: fix toHaveBeenCalledWith(asymmetricMatcher) with undefined arguments (#7624)
1 parent 6ece0d9 commit 0fb21fa

File tree

2 files changed

+39
-8
lines changed

2 files changed

+39
-8
lines changed

packages/expect/src/jest-expect.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -576,12 +576,19 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
576576
throw new AssertionError(msg)
577577
}
578578
})
579+
580+
// manually compare array elements since `jestEquals` cannot
581+
// apply assymetric matcher to `undefined` array element.
582+
function equalsArgumentArray(a: unknown[], b: unknown[]) {
583+
return a.length === b.length && a.every((aItem, i) =>
584+
jestEquals(aItem, b[i], [...customTesters, iterableEquality]),
585+
)
586+
}
587+
579588
def(['toHaveBeenCalledWith', 'toBeCalledWith'], function (...args) {
580589
const spy = getSpy(this)
581590
const spyName = spy.getMockName()
582-
const pass = spy.mock.calls.some(callArg =>
583-
jestEquals(callArg, args, [...customTesters, iterableEquality]),
584-
)
591+
const pass = spy.mock.calls.some(callArg => equalsArgumentArray(callArg, args))
585592
const isNot = utils.flag(this, 'negate') as boolean
586593

587594
const msg = utils.getMessage(this, [
@@ -599,9 +606,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
599606
const spy = getSpy(this)
600607
const spyName = spy.getMockName()
601608
const callCount = spy.mock.calls.length
602-
const hasCallWithArgs = spy.mock.calls.some(callArg =>
603-
jestEquals(callArg, args, [...customTesters, iterableEquality]),
604-
)
609+
const hasCallWithArgs = spy.mock.calls.some(callArg => equalsArgumentArray(callArg, args))
605610
const pass = hasCallWithArgs && callCount === 1
606611
const isNot = utils.flag(this, 'negate') as boolean
607612

@@ -625,7 +630,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
625630
const callCount = spy.mock.calls.length
626631
const isCalled = times <= callCount
627632
this.assert(
628-
jestEquals(nthCall, args, [...customTesters, iterableEquality]),
633+
nthCall && equalsArgumentArray(nthCall, args),
629634
`expected ${ordinalOf(
630635
times,
631636
)} "${spyName}" call to have been called with #{exp}${
@@ -648,7 +653,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
648653
const lastCall = spy.mock.calls[spy.mock.calls.length - 1]
649654

650655
this.assert(
651-
jestEquals(lastCall, args, [...customTesters, iterableEquality]),
656+
lastCall && equalsArgumentArray(lastCall, args),
652657
`expected last "${spyName}" call to have been called with #{exp}`,
653658
`expected last "${spyName}" call to not have been called with #{exp}`,
654659
args,

test/core/test/jest-expect.test.ts

+26
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,32 @@ describe('toHaveBeenCalled', () => {
715715
}).toThrow(/^expected "spy" to not be called at all[^e]/)
716716
})
717717
})
718+
719+
it('undefined argument', () => {
720+
const fn = vi.fn()
721+
fn(undefined)
722+
expect(fn).not.toHaveBeenCalledWith()
723+
expect(fn).toHaveBeenCalledWith(undefined)
724+
expect(fn).toHaveBeenCalledWith(expect.toSatisfy(() => true))
725+
expect(fn).toHaveBeenCalledWith(expect.not.toSatisfy(() => false))
726+
expect(fn).toHaveBeenCalledWith(expect.toBeOneOf([undefined, null]))
727+
})
728+
729+
it('no argument', () => {
730+
const fn = vi.fn()
731+
fn()
732+
expect(fn).toHaveBeenCalledWith()
733+
expect(fn).not.toHaveBeenCalledWith(undefined)
734+
expect(fn).not.toHaveBeenCalledWith(expect.toSatisfy(() => true))
735+
expect(fn).not.toHaveBeenCalledWith(expect.not.toSatisfy(() => false))
736+
expect(fn).not.toHaveBeenCalledWith(expect.toBeOneOf([undefined, null]))
737+
})
738+
739+
it('no strict equal check for each argument', () => {
740+
const fn = vi.fn()
741+
fn({ x: undefined, z: 123 })
742+
expect(fn).toHaveBeenCalledWith({ y: undefined, z: 123 })
743+
})
718744
})
719745

720746
describe('toHaveBeenCalledWith', () => {

0 commit comments

Comments
 (0)