Skip to content

Commit a5b52a5

Browse files
authoredAug 17, 2022
chore(types): separate MatcherContext, MatcherUtils and MatcherState (#13141)
1 parent 79b5e41 commit a5b52a5

File tree

11 files changed

+84
-57
lines changed

11 files changed

+84
-57
lines changed
 

‎CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### Features
44

5+
- `[expect]` [**BREAKING**] Differentiate between `MatcherContext` `MatcherUtils` and `MatcherState` types ([#13141](https://github.com/facebook/jest/pull/13141))
56
- `[jest-config]` [**BREAKING**] Make `snapshotFormat` default to `escapeString: false` and `printBasicPrototype: false` ([#13036](https://github.com/facebook/jest/pull/13036))
67
- `[jest-environment-jsdom]` [**BREAKING**] Upgrade to `jsdom@20` ([#13037](https://github.com/facebook/jest/pull/13037), [#13058](https://github.com/facebook/jest/pull/13058))
78
- `[@jest/globals]` Add `jest.Mocked`, `jest.MockedClass`, `jest.MockedFunction` and `jest.MockedObject` utility types ([#12727](https://github.com/facebook/jest/pull/12727))

‎packages/expect/__typetests__/expect.test.ts

+18-18
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
import {expectAssignable, expectError, expectType} from 'tsd-lite';
99
import type {EqualsFunction, Tester} from '@jest/expect-utils';
1010
import {
11+
MatcherContext,
1112
MatcherFunction,
12-
MatcherFunctionWithState,
13-
MatcherState,
13+
MatcherFunctionWithContext,
1414
Matchers,
1515
expect,
1616
} from 'expect';
@@ -35,16 +35,16 @@ expectType<void>(
3535
toBeWithinRange(actual: number, floor: number, ceiling: number) {
3636
expectType<number>(this.assertionCalls);
3737
expectType<string | undefined>(this.currentTestName);
38-
expectType<(() => void) | undefined>(this.dontThrow);
38+
expectType<() => void>(this.dontThrow);
3939
expectType<Error | undefined>(this.error);
4040
expectType<EqualsFunction>(this.equals);
4141
expectType<boolean | undefined>(this.expand);
42-
expectType<number | null | undefined>(this.expectedAssertionsNumber);
42+
expectType<number | null>(this.expectedAssertionsNumber);
4343
expectType<Error | undefined>(this.expectedAssertionsNumberError);
44-
expectType<boolean | undefined>(this.isExpectingAssertions);
44+
expectType<boolean>(this.isExpectingAssertions);
4545
expectType<Error | undefined>(this.isExpectingAssertionsError);
46-
expectType<boolean>(this.isNot);
47-
expectType<string>(this.promise);
46+
expectType<boolean | undefined>(this.isNot);
47+
expectType<string | undefined>(this.promise);
4848
expectType<Array<Error>>(this.suppressedErrors);
4949
expectType<string | undefined>(this.testPath);
5050
expectType<MatcherUtils>(this.utils);
@@ -114,7 +114,7 @@ expectError(() => {
114114
});
115115

116116
type ToBeWithinRange = (
117-
this: MatcherState,
117+
this: MatcherContext,
118118
actual: unknown,
119119
floor: number,
120120
ceiling: number,
@@ -133,7 +133,7 @@ const toBeWithinRange: MatcherFunction<[floor: number, ceiling: number]> = (
133133

134134
expectAssignable<ToBeWithinRange>(toBeWithinRange);
135135

136-
type AllowOmittingExpected = (this: MatcherState, actual: unknown) => any;
136+
type AllowOmittingExpected = (this: MatcherContext, actual: unknown) => any;
137137

138138
const allowOmittingExpected: MatcherFunction = (
139139
actual: unknown,
@@ -151,13 +151,13 @@ const allowOmittingExpected: MatcherFunction = (
151151

152152
expectAssignable<AllowOmittingExpected>(allowOmittingExpected);
153153

154-
// MatcherState
154+
// MatcherContext
155155

156156
const toHaveContext: MatcherFunction = function (
157157
actual: unknown,
158158
...expect: Array<unknown>
159159
) {
160-
expectType<MatcherState>(this);
160+
expectType<MatcherContext>(this);
161161

162162
if (expect.length !== 0) {
163163
throw new Error('This matcher does not take any expected argument.');
@@ -169,15 +169,15 @@ const toHaveContext: MatcherFunction = function (
169169
};
170170
};
171171

172-
interface CustomState extends MatcherState {
172+
interface CustomContext extends MatcherContext {
173173
customMethod(): void;
174174
}
175175

176-
const customContext: MatcherFunctionWithState<CustomState> = function (
176+
const customContext: MatcherFunctionWithContext<CustomContext> = function (
177177
actual: unknown,
178178
...expect: Array<unknown>
179179
) {
180-
expectType<CustomState>(this);
180+
expectType<CustomContext>(this);
181181
expectType<void>(this.customMethod());
182182

183183
if (expect.length !== 0) {
@@ -191,16 +191,16 @@ const customContext: MatcherFunctionWithState<CustomState> = function (
191191
};
192192

193193
type CustomStateAndExpected = (
194-
this: CustomState,
194+
this: CustomContext,
195195
actual: unknown,
196196
count: number,
197197
) => any;
198198

199-
const customStateAndExpected: MatcherFunctionWithState<
200-
CustomState,
199+
const customStateAndExpected: MatcherFunctionWithContext<
200+
CustomContext,
201201
[count: number]
202202
> = function (actual: unknown, count: unknown) {
203-
expectType<CustomState>(this);
203+
expectType<CustomContext>(this);
204204
expectType<void>(this.customMethod());
205205

206206
return {

‎packages/expect/src/asymmetricMatchers.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {pluralize} from 'jest-util';
1717
import {getState} from './jestMatchersObject';
1818
import type {
1919
AsymmetricMatcher as AsymmetricMatcherInterface,
20+
MatcherContext,
2021
MatcherState,
2122
} from './types';
2223

@@ -70,9 +71,11 @@ export abstract class AsymmetricMatcher<T>
7071

7172
constructor(protected sample: T, protected inverse = false) {}
7273

73-
protected getMatcherContext(): MatcherState {
74+
protected getMatcherContext(): MatcherContext {
7475
return {
75-
...getState(),
76+
// eslint-disable-next-line @typescript-eslint/no-empty-function
77+
dontThrow: () => {},
78+
...getState<MatcherState>(),
7679
equals,
7780
isNot: this.inverse,
7881
utils,

‎packages/expect/src/index.ts

+18-6
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ import type {
4141
AsyncExpectationResult,
4242
Expect,
4343
ExpectationResult,
44+
MatcherContext,
4445
MatcherState,
46+
MatcherUtils,
4547
MatchersObject,
4648
PromiseMatcherFn,
4749
RawMatcherFn,
@@ -54,9 +56,11 @@ export type {
5456
AsymmetricMatchers,
5557
BaseExpect,
5658
Expect,
59+
MatcherContext,
5760
MatcherFunction,
58-
MatcherFunctionWithState,
61+
MatcherFunctionWithContext,
5962
MatcherState,
63+
MatcherUtils,
6064
Matchers,
6165
} from './types';
6266

@@ -74,7 +78,7 @@ const createToThrowErrorMatchingSnapshotMatcher = function (
7478
matcher: RawMatcherFn,
7579
) {
7680
return function (
77-
this: MatcherState,
81+
this: MatcherContext,
7882
received: any,
7983
testNameOrInlineSnapshot?: string,
8084
) {
@@ -269,21 +273,29 @@ const makeThrowingMatcher = (
269273
): ThrowingMatcherFn =>
270274
function throwingMatcher(...args): any {
271275
let throws = true;
272-
const utils = {...matcherUtils, iterableEquality, subsetEquality};
276+
const utils: MatcherUtils['utils'] = {
277+
...matcherUtils,
278+
iterableEquality,
279+
subsetEquality,
280+
};
273281

274-
const matcherContext: MatcherState = {
282+
const matcherUtilsThing: MatcherUtils = {
275283
// When throws is disabled, the matcher will not throw errors during test
276284
// execution but instead add them to the global matcher state. If a
277285
// matcher throws, test execution is normally stopped immediately. The
278286
// snapshot matcher uses it because we want to log all snapshot
279287
// failures in a test.
280288
dontThrow: () => (throws = false),
281-
...getState(),
282289
equals,
290+
utils,
291+
};
292+
293+
const matcherContext: MatcherContext = {
294+
...getState<MatcherState>(),
295+
...matcherUtilsThing,
283296
error: err,
284297
isNot,
285298
promise,
286-
utils,
287299
};
288300

289301
const processResult = (

‎packages/expect/src/jestMatchersObject.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const JEST_MATCHERS_OBJECT = Symbol.for('$$jest-matchers-object');
2424
export const INTERNAL_MATCHER_FLAG = Symbol.for('$$jest-internal-matcher');
2525

2626
if (!Object.prototype.hasOwnProperty.call(globalThis, JEST_MATCHERS_OBJECT)) {
27-
const defaultState: Partial<MatcherState> = {
27+
const defaultState: MatcherState = {
2828
assertionCalls: 0,
2929
expectedAssertionsNumber: null,
3030
isExpectingAssertions: false,

‎packages/expect/src/print.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const printCloseTo = (
6363
receivedDiff: number,
6464
expectedDiff: number,
6565
precision: number,
66-
isNot: boolean,
66+
isNot: boolean | undefined,
6767
): string => {
6868
const receivedDiffString = stringify(receivedDiff);
6969
const expectedDiffString = receivedDiffString.includes('e')

‎packages/expect/src/types.ts

+25-16
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,21 @@ export type AsyncExpectationResult = Promise<SyncExpectationResult>;
1919

2020
export type ExpectationResult = SyncExpectationResult | AsyncExpectationResult;
2121

22-
export type MatcherFunctionWithState<
23-
State extends MatcherState = MatcherState,
22+
export type MatcherFunctionWithContext<
23+
Context extends MatcherContext = MatcherContext,
2424
Expected extends Array<any> = [] /** TODO should be: extends Array<unknown> = [] */,
25-
> = (this: State, actual: unknown, ...expected: Expected) => ExpectationResult;
25+
> = (
26+
this: Context,
27+
actual: unknown,
28+
...expected: Expected
29+
) => ExpectationResult;
2630

2731
export type MatcherFunction<Expected extends Array<unknown> = []> =
28-
MatcherFunctionWithState<MatcherState, Expected>;
32+
MatcherFunctionWithContext<MatcherContext, Expected>;
2933

3034
// TODO should be replaced with `MatcherFunctionWithContext`
31-
export type RawMatcherFn<State extends MatcherState = MatcherState> = {
32-
(this: State, actual: any, ...expected: Array<any>): ExpectationResult;
35+
export type RawMatcherFn<Context extends MatcherContext = MatcherContext> = {
36+
(this: Context, actual: any, ...expected: Array<any>): ExpectationResult;
3337
/** @internal */
3438
[INTERNAL_MATCHER_FLAG]?: boolean;
3539
};
@@ -41,27 +45,32 @@ export type MatchersObject = {
4145
export type ThrowingMatcherFn = (actual: any) => void;
4246
export type PromiseMatcherFn = (actual: any) => Promise<void>;
4347

48+
export interface MatcherUtils {
49+
dontThrow(): void;
50+
equals: EqualsFunction;
51+
utils: typeof jestMatcherUtils & {
52+
iterableEquality: Tester;
53+
subsetEquality: Tester;
54+
};
55+
}
56+
4457
export interface MatcherState {
4558
assertionCalls: number;
4659
currentTestName?: string;
47-
dontThrow?(): void;
4860
error?: Error;
49-
equals: EqualsFunction;
5061
expand?: boolean;
51-
expectedAssertionsNumber?: number | null;
62+
expectedAssertionsNumber: number | null;
5263
expectedAssertionsNumberError?: Error;
53-
isExpectingAssertions?: boolean;
64+
isExpectingAssertions: boolean;
5465
isExpectingAssertionsError?: Error;
55-
isNot: boolean;
56-
promise: string;
66+
isNot?: boolean;
67+
promise?: string;
5768
suppressedErrors: Array<Error>;
5869
testPath?: string;
59-
utils: typeof jestMatcherUtils & {
60-
iterableEquality: Tester;
61-
subsetEquality: Tester;
62-
};
6370
}
6471

72+
export type MatcherContext = MatcherUtils & Readonly<MatcherState>;
73+
6574
export type AsymmetricMatcher = {
6675
asymmetricMatch(other: unknown): boolean;
6776
toString(): string;

‎packages/jest-expect/src/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ import type {JestExpect} from './types';
1818
export type {
1919
AsymmetricMatchers,
2020
Matchers,
21+
MatcherContext,
2122
MatcherFunction,
22-
MatcherFunctionWithState,
23+
MatcherFunctionWithContext,
2324
MatcherState,
25+
MatcherUtils,
2426
} from 'expect';
2527
export type {JestExpect} from './types';
2628

‎packages/jest-snapshot/src/index.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import * as fs from 'graceful-fs';
99
import type {Config} from '@jest/types';
10-
import type {MatcherFunctionWithState} from 'expect';
10+
import type {MatcherFunctionWithContext} from 'expect';
1111
import type {FS as HasteFS} from 'jest-haste-map';
1212
import {
1313
BOLD_WEIGHT,
@@ -153,7 +153,7 @@ export const cleanup = (
153153
};
154154
};
155155

156-
export const toMatchSnapshot: MatcherFunctionWithState<Context> = function (
156+
export const toMatchSnapshot: MatcherFunctionWithContext<Context> = function (
157157
received: unknown,
158158
propertiesOrHint?: object | string,
159159
hint?: string,
@@ -211,7 +211,7 @@ export const toMatchSnapshot: MatcherFunctionWithState<Context> = function (
211211
});
212212
};
213213

214-
export const toMatchInlineSnapshot: MatcherFunctionWithState<Context> =
214+
export const toMatchInlineSnapshot: MatcherFunctionWithContext<Context> =
215215
function (
216216
received: unknown,
217217
propertiesOrSnapshot?: object | string,
@@ -408,7 +408,7 @@ const _toMatchSnapshot = (config: MatchSnapshotConfig) => {
408408
};
409409
};
410410

411-
export const toThrowErrorMatchingSnapshot: MatcherFunctionWithState<Context> =
411+
export const toThrowErrorMatchingSnapshot: MatcherFunctionWithContext<Context> =
412412
function (received: unknown, hint?: string, fromPromise?: boolean) {
413413
const matcherName = 'toThrowErrorMatchingSnapshot';
414414

@@ -427,7 +427,7 @@ export const toThrowErrorMatchingSnapshot: MatcherFunctionWithState<Context> =
427427
);
428428
};
429429

430-
export const toThrowErrorMatchingInlineSnapshot: MatcherFunctionWithState<Context> =
430+
export const toThrowErrorMatchingInlineSnapshot: MatcherFunctionWithContext<Context> =
431431
function (received: unknown, inlineSnapshot?: string, fromPromise?: boolean) {
432432
const matcherName = 'toThrowErrorMatchingInlineSnapshot';
433433

‎packages/jest-snapshot/src/types.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import type {MatcherState} from 'expect';
8+
import type {MatcherContext} from 'expect';
99
import type SnapshotState from './State';
1010

11-
export interface Context extends MatcherState {
11+
export interface Context extends MatcherContext {
1212
snapshotState: SnapshotState;
1313
}
1414

‎packages/jest-types/__typetests__/expect.test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -361,16 +361,16 @@ expectType<void>(
361361
toBeWithinRange(actual: number, floor: number, ceiling: number) {
362362
expectType<number>(this.assertionCalls);
363363
expectType<string | undefined>(this.currentTestName);
364-
expectType<(() => void) | undefined>(this.dontThrow);
364+
expectType<() => void>(this.dontThrow);
365365
expectType<Error | undefined>(this.error);
366366
expectType<EqualsFunction>(this.equals);
367367
expectType<boolean | undefined>(this.expand);
368-
expectType<number | null | undefined>(this.expectedAssertionsNumber);
368+
expectType<number | null>(this.expectedAssertionsNumber);
369369
expectType<Error | undefined>(this.expectedAssertionsNumberError);
370-
expectType<boolean | undefined>(this.isExpectingAssertions);
370+
expectType<boolean>(this.isExpectingAssertions);
371371
expectType<Error | undefined>(this.isExpectingAssertionsError);
372-
expectType<boolean>(this.isNot);
373-
expectType<string>(this.promise);
372+
expectType<boolean | undefined>(this.isNot);
373+
expectType<string | undefined>(this.promise);
374374
expectType<Array<Error>>(this.suppressedErrors);
375375
expectType<string | undefined>(this.testPath);
376376
expectType<MatcherUtils>(this.utils);

0 commit comments

Comments
 (0)
Please sign in to comment.