Skip to content

Commit fb34f7b

Browse files
committed
Add a working case of custom matchers with types!
1 parent 5e0b715 commit fb34f7b

File tree

4 files changed

+62
-3
lines changed

4 files changed

+62
-3
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// TODO dprevost should we review this to have the wdio namespace or maybe the expect namespace?
2+
// Name jest is required to augment the jest.Matchers interface
3+
declare namespace jest {
4+
interface AsymmetricMatchers {
5+
toBeCustom(): void;
6+
}
7+
interface Matchers<R, T> {
8+
toBeCustom(): R;
9+
toBeCustomPromise: T extends ChainablePromiseElement ? (expected?: object) => Promise<R> : never;
10+
}
11+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { MatcherFunction } from 'expect'
2+
3+
const toBeCustom: MatcherFunction =
4+
function (actual: ChainablePromiseElement) {
5+
const pass = actual
6+
if (pass) {
7+
return {
8+
message: () => 'failed to be custom',
9+
pass: true,
10+
}
11+
}
12+
return {
13+
message: () => 'failed to not be custom',
14+
pass: false,
15+
}
16+
}
17+
18+
expect.extend({ toBeCustom })

test-types/jest/tsconfig.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@
55
"target": "ES2020",
66
"module": "Node16",
77
"skipLibCheck": true,
8+
"typeRoots": [
9+
"../../node_modules/",
10+
"../../",
11+
"./customMatchers",
12+
],
813
"types": [
914
"@types/jest",
10-
"../../jest.d.ts", // Needed to be after @types/jest to override the toMatchSnapshot typing
11-
"@wdio/globals/types"
12-
]
15+
"jest.d.ts", // Needed to be after @types/jest to override the toMatchSnapshot typing
16+
"@wdio/globals/types",
17+
"customMatchers.d.ts",
18+
],
1319
}
1420
}

test-types/jest/types-jest.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,30 @@ describe('type assertions', async () => {
194194
})
195195
})
196196

197+
describe('Custom matchers', () => {
198+
it('should supported correctly a non-promise custom matcher', async () => {
199+
expectVoid = expect('test').toBeCustom()
200+
expectVoid = expect('test').not.toBeCustom()
201+
202+
// @ts-expect-error
203+
expectPromiseVoid = expect('test').toBeCustom()
204+
// @ts-expect-error
205+
expectPromiseVoid = expect('test').not.toBeCustom()
206+
})
207+
208+
it('should supported correctly a promise custom matcher with only chainableElement as actual', async () => {
209+
expectPromiseVoid = expect(chainableElement).toBeCustomPromise()
210+
expectPromiseVoid = expect(chainableElement).toBeCustomPromise(expect.objectContaining({}))
211+
212+
// @ts-expect-error
213+
expect('test').toBeCustomPromise()
214+
// @ts-expect-error
215+
expectVoid = expect(chainableElement).toBeCustomPromise()
216+
// @ts-expect-error
217+
expectVoid = expect(chainableElement).toBeCustomPromise(expect.objectContaining({}))
218+
})
219+
})
220+
197221
describe('toBe', () => {
198222

199223
it('should expect void type when actual is a boolean', async () => {

0 commit comments

Comments
 (0)