Skip to content

Commit 965cefc

Browse files
authored
fix(expect)!: pass current equality testers to asymmetric matcher (#6825)
1 parent 9a79b90 commit 965cefc

File tree

3 files changed

+43
-14
lines changed

3 files changed

+43
-14
lines changed

packages/expect/src/jest-asymmetric-matchers.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable unicorn/no-instanceof-builtins -- we check both */
22

3-
import type { ChaiPlugin, MatcherState } from './types'
3+
import type { ChaiPlugin, MatcherState, Tester } from './types'
44
import { GLOBAL_EXPECT } from './constants'
55
import {
66
diff,
@@ -19,7 +19,7 @@ import {
1919
import { getState } from './state'
2020

2121
export interface AsymmetricMatcherInterface {
22-
asymmetricMatch: (other: unknown) => boolean
22+
asymmetricMatch: (other: unknown, customTesters?: Array<Tester>) => boolean
2323
toString: () => string
2424
getExpectedType?: () => string
2525
toAsymmetricMatcher?: () => string
@@ -50,7 +50,7 @@ export abstract class AsymmetricMatcher<
5050
}
5151
}
5252

53-
abstract asymmetricMatch(other: unknown): boolean
53+
abstract asymmetricMatch(other: unknown, customTesters?: Array<Tester>): boolean
5454
abstract toString(): string
5555
getExpectedType?(): string
5656
toAsymmetricMatcher?(): string
@@ -147,7 +147,7 @@ export class ObjectContaining extends AsymmetricMatcher<
147147
]
148148
}
149149

150-
asymmetricMatch(other: any): boolean {
150+
asymmetricMatch(other: any, customTesters?: Array<Tester>): boolean {
151151
if (typeof this.sample !== 'object') {
152152
throw new TypeError(
153153
`You must provide an object to ${this.toString()}, not '${typeof this
@@ -157,7 +157,6 @@ export class ObjectContaining extends AsymmetricMatcher<
157157

158158
let result = true
159159

160-
const matcherContext = this.getMatcherContext()
161160
const properties = this.getProperties(this.sample)
162161
for (const property of properties) {
163162
if (
@@ -171,7 +170,7 @@ export class ObjectContaining extends AsymmetricMatcher<
171170
if (!equals(
172171
value,
173172
otherValue,
174-
matcherContext.customTesters,
173+
customTesters,
175174
)
176175
) {
177176
result = false
@@ -196,21 +195,20 @@ export class ArrayContaining<T = unknown> extends AsymmetricMatcher<Array<T>> {
196195
super(sample, inverse)
197196
}
198197

199-
asymmetricMatch(other: Array<T>): boolean {
198+
asymmetricMatch(other: Array<T>, customTesters?: Array<Tester>): boolean {
200199
if (!Array.isArray(this.sample)) {
201200
throw new TypeError(
202201
`You must provide an array to ${this.toString()}, not '${typeof this
203202
.sample}'.`,
204203
)
205204
}
206205

207-
const matcherContext = this.getMatcherContext()
208206
const result
209207
= this.sample.length === 0
210208
|| (Array.isArray(other)
211209
&& this.sample.every(item =>
212210
other.some(another =>
213-
equals(item, another, matcherContext.customTesters),
211+
equals(item, another, customTesters),
214212
),
215213
))
216214

packages/expect/src/jest-utils.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2222
2323
*/
2424

25+
import type { AsymmetricMatcher } from './jest-asymmetric-matchers'
2526
import type { Tester, TesterContext } from './types'
2627
import { isObject } from '@vitest/utils/helpers'
2728

@@ -38,7 +39,7 @@ export function equals(
3839

3940
const functionToString = Function.prototype.toString
4041

41-
export function isAsymmetric(obj: any): boolean {
42+
export function isAsymmetric(obj: any): obj is AsymmetricMatcher<any> {
4243
return (
4344
!!obj
4445
&& typeof obj === 'object'
@@ -67,7 +68,7 @@ export function hasAsymmetric(obj: any, seen: Set<any> = new Set()): boolean {
6768
return false
6869
}
6970

70-
function asymmetricMatch(a: any, b: any) {
71+
function asymmetricMatch(a: any, b: any, customTesters: Array<Tester>) {
7172
const asymmetricA = isAsymmetric(a)
7273
const asymmetricB = isAsymmetric(b)
7374

@@ -76,11 +77,11 @@ function asymmetricMatch(a: any, b: any) {
7677
}
7778

7879
if (asymmetricA) {
79-
return a.asymmetricMatch(b)
80+
return a.asymmetricMatch(b, customTesters)
8081
}
8182

8283
if (asymmetricB) {
83-
return b.asymmetricMatch(a)
84+
return b.asymmetricMatch(a, customTesters)
8485
}
8586
}
8687

@@ -96,7 +97,7 @@ function eq(
9697
): boolean {
9798
let result = true
9899

99-
const asymmetricResult = asymmetricMatch(a, b)
100+
const asymmetricResult = asymmetricMatch(a, b, customTesters)
100101
if (asymmetricResult !== undefined) {
101102
return asymmetricResult
102103
}

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,36 @@ describe('jest-expect', () => {
203203
}).toThrowErrorMatchingInlineSnapshot(`[AssertionError: expected { sum: 0.30000000000000004 } to deeply equal { sum: NumberCloseTo 0.4 (2 digits) }]`)
204204
})
205205

206+
it('asymmetric matchers and equality testers', () => {
207+
// iterable equality testers
208+
expect([new Set(['x'])]).toEqual(
209+
expect.arrayContaining([new Set(['x'])]),
210+
)
211+
expect([new Set()]).not.toEqual(
212+
expect.arrayContaining([new Set(['x'])]),
213+
)
214+
expect({ foo: new Set(['x']) }).toEqual(
215+
expect.objectContaining({ foo: new Set(['x']) }),
216+
)
217+
expect({ foo: new Set() }).not.toEqual(
218+
expect.objectContaining({ foo: new Set(['x']) }),
219+
)
220+
221+
// `toStrictEqual` testers
222+
class Stock {
223+
constructor(public type: string) {}
224+
}
225+
expect([new Stock('x')]).toEqual(
226+
expect.arrayContaining([{ type: 'x' }]),
227+
)
228+
expect([new Stock('x')]).not.toStrictEqual(
229+
expect.arrayContaining([{ type: 'x' }]),
230+
)
231+
expect([new Stock('x')]).toStrictEqual(
232+
expect.arrayContaining([new Stock('x')]),
233+
)
234+
})
235+
206236
it('asymmetric matchers negate', () => {
207237
expect('bar').toEqual(expect.not.stringContaining('zoo'))
208238
expect('bar').toEqual(expect.not.stringMatching(/zoo/))

0 commit comments

Comments
 (0)