Skip to content

Commit be2703c

Browse files
Alcedo Nathaniel De Guzman JrSimenB
authored andcommitted
Migrate expect to typescript (#7919)
1 parent b8a9a71 commit be2703c

File tree

17 files changed

+421
-248
lines changed

17 files changed

+421
-248
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
- `[@jest/transform]`: Migrate to TypeScript ([#7918](https://github.com/facebook/jest/pull/7918))
5050
- `[docs]` Add missing import to docs ([#7928](https://github.com/facebook/jest/pull/7928))
5151
- `[jest-resolve-dependencies]`: Migrate to TypeScript ([#7922](https://github.com/facebook/jest/pull/7922))
52+
- `[expect]`: Migrate to TypeScript ([#7919](https://github.com/facebook/jest/pull/7919))
5253

5354
### Performance
5455

packages/expect/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
},
99
"license": "MIT",
1010
"main": "build/index.js",
11+
"types": "build/index.d.ts",
1112
"browser": "build-es5/index.js",
1213
"dependencies": {
14+
"@jest/types": "^24.1.0",
1315
"ansi-styles": "^3.2.0",
1416
"jest-get-type": "^24.0.0",
1517
"jest-matcher-utils": "^24.0.0",

packages/expect/src/asymmetricMatchers.js renamed to packages/expect/src/asymmetricMatchers.ts

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,35 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @flow
87
*/
98

109
import {equals, fnNameFor, hasProperty, isA, isUndefined} from './jasmineUtils';
1110

1211
import {emptyObject} from './utils';
1312

14-
export class AsymmetricMatcher {
13+
export class AsymmetricMatcher<T> {
14+
protected sample: T;
1515
$$typeof: Symbol;
16-
inverse: boolean;
16+
inverse?: boolean;
1717

18-
constructor() {
18+
constructor(sample: T) {
1919
this.$$typeof = Symbol.for('jest.asymmetricMatcher');
20+
this.sample = sample;
2021
}
2122
}
2223

23-
class Any extends AsymmetricMatcher {
24-
sample: any;
25-
26-
constructor(sample: any) {
27-
super();
24+
class Any extends AsymmetricMatcher<any> {
25+
constructor(sample: unknown) {
2826
if (typeof sample === 'undefined') {
2927
throw new TypeError(
3028
'any() expects to be passed a constructor function. ' +
3129
'Please pass one or use anything() to match any object.',
3230
);
3331
}
34-
this.sample = sample;
32+
super(sample);
3533
}
3634

37-
asymmetricMatch(other: any) {
35+
asymmetricMatch(other: unknown) {
3836
if (this.sample == String) {
3937
return typeof other == 'string' || other instanceof String;
4038
}
@@ -91,8 +89,8 @@ class Any extends AsymmetricMatcher {
9189
}
9290
}
9391

94-
class Anything extends AsymmetricMatcher {
95-
asymmetricMatch(other: any) {
92+
class Anything extends AsymmetricMatcher<void> {
93+
asymmetricMatch(other: unknown) {
9694
return !isUndefined(other) && other !== null;
9795
}
9896

@@ -107,16 +105,13 @@ class Anything extends AsymmetricMatcher {
107105
}
108106
}
109107

110-
class ArrayContaining extends AsymmetricMatcher {
111-
sample: Array<any>;
112-
113-
constructor(sample: Array<any>, inverse: boolean = false) {
114-
super();
115-
this.sample = sample;
108+
class ArrayContaining extends AsymmetricMatcher<Array<unknown>> {
109+
constructor(sample: Array<unknown>, inverse: boolean = false) {
110+
super(sample);
116111
this.inverse = inverse;
117112
}
118113

119-
asymmetricMatch(other: Array<any>) {
114+
asymmetricMatch(other: Array<unknown>) {
120115
if (!Array.isArray(this.sample)) {
121116
throw new Error(
122117
`You must provide an array to ${this.toString()}, not '` +
@@ -144,16 +139,13 @@ class ArrayContaining extends AsymmetricMatcher {
144139
}
145140
}
146141

147-
class ObjectContaining extends AsymmetricMatcher {
148-
sample: Object;
149-
142+
class ObjectContaining extends AsymmetricMatcher<Object> {
150143
constructor(sample: Object, inverse: boolean = false) {
151-
super();
152-
this.sample = sample;
144+
super(sample);
153145
this.inverse = inverse;
154146
}
155147

156-
asymmetricMatch(other: Object) {
148+
asymmetricMatch(other: any) {
157149
if (typeof this.sample !== 'object') {
158150
throw new Error(
159151
`You must provide an object to ${this.toString()}, not '` +
@@ -166,8 +158,8 @@ class ObjectContaining extends AsymmetricMatcher {
166158
for (const property in this.sample) {
167159
if (
168160
hasProperty(other, property) &&
169-
equals(this.sample[property], other[property]) &&
170-
!emptyObject(this.sample[property]) &&
161+
equals((this.sample as any)[property], other[property]) &&
162+
!emptyObject((this.sample as any)[property]) &&
171163
!emptyObject(other[property])
172164
) {
173165
return false;
@@ -179,7 +171,7 @@ class ObjectContaining extends AsymmetricMatcher {
179171
for (const property in this.sample) {
180172
if (
181173
!hasProperty(other, property) ||
182-
!equals(this.sample[property], other[property])
174+
!equals((this.sample as any)[property], other[property])
183175
) {
184176
return false;
185177
}
@@ -198,19 +190,16 @@ class ObjectContaining extends AsymmetricMatcher {
198190
}
199191
}
200192

201-
class StringContaining extends AsymmetricMatcher {
202-
sample: string;
203-
193+
class StringContaining extends AsymmetricMatcher<string> {
204194
constructor(sample: string, inverse: boolean = false) {
205-
super();
206195
if (!isA('String', sample)) {
207196
throw new Error('Expected is not a string');
208197
}
209-
this.sample = sample;
198+
super(sample);
210199
this.inverse = inverse;
211200
}
212201

213-
asymmetricMatch(other: any) {
202+
asymmetricMatch(other: string) {
214203
const result = isA('String', other) && other.includes(this.sample);
215204

216205
return this.inverse ? !result : result;
@@ -225,20 +214,17 @@ class StringContaining extends AsymmetricMatcher {
225214
}
226215
}
227216

228-
class StringMatching extends AsymmetricMatcher {
229-
sample: RegExp;
230-
217+
class StringMatching extends AsymmetricMatcher<RegExp> {
231218
constructor(sample: string | RegExp, inverse: boolean = false) {
232-
super();
233219
if (!isA('String', sample) && !isA('RegExp', sample)) {
234220
throw new Error('Expected is not a String or a RegExp');
235221
}
222+
super(new RegExp(sample));
236223

237-
this.sample = new RegExp(sample);
238224
this.inverse = inverse;
239225
}
240226

241-
asymmetricMatch(other: any) {
227+
asymmetricMatch(other: string) {
242228
const result = isA('String', other) && this.sample.test(other);
243229

244230
return this.inverse ? !result : result;
@@ -255,9 +241,9 @@ class StringMatching extends AsymmetricMatcher {
255241

256242
export const any = (expectedObject: any) => new Any(expectedObject);
257243
export const anything = () => new Anything();
258-
export const arrayContaining = (sample: Array<any>) =>
244+
export const arrayContaining = (sample: Array<unknown>) =>
259245
new ArrayContaining(sample);
260-
export const arrayNotContaining = (sample: Array<any>) =>
246+
export const arrayNotContaining = (sample: Array<unknown>) =>
261247
new ArrayContaining(sample, true);
262248
export const objectContaining = (sample: Object) =>
263249
new ObjectContaining(sample);

packages/expect/src/extractExpectedAssertionsErrors.js renamed to packages/expect/src/extractExpectedAssertionsErrors.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @flow
87
*/
98

109
import {

packages/expect/src/fakeChalk.js renamed to packages/expect/src/fakeChalk.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
*
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
6-
* @flow
76
*/
87

98
import ansiStyles from 'ansi-styles';
109

11-
const returnInput = str => str;
10+
const returnInput = (str: string) => str;
1211

1312
const allColorsAsFunc = Object.keys(ansiStyles)
1413
.map(style => ({[style]: returnInput}))
@@ -21,4 +20,4 @@ Object.keys(allColorsAsFunc)
2120
Object.assign(returnInput, style);
2221
});
2322

24-
module.exports = allColorsAsFunc;
23+
export = allColorsAsFunc;

packages/expect/src/index.js renamed to packages/expect/src/index.ts

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @flow
87
*/
98

10-
import type {
11-
Expect,
12-
ExpectationObject,
9+
import * as matcherUtils from 'jest-matcher-utils';
10+
import {
1311
AsyncExpectationResult,
1412
SyncExpectationResult,
1513
ExpectationResult,
@@ -18,9 +16,10 @@ import type {
1816
RawMatcherFn,
1917
ThrowingMatcherFn,
2018
PromiseMatcherFn,
21-
} from 'types/Matchers';
19+
ExpectationObject,
20+
Expect,
21+
} from './types';
2222

23-
import * as matcherUtils from 'jest-matcher-utils';
2423
import {iterableEquality, subsetEquality} from './utils';
2524
import matchers from './matchers';
2625
import spyMatchers from './spyMatchers';
@@ -50,21 +49,27 @@ import {
5049
import extractExpectedAssertionsErrors from './extractExpectedAssertionsErrors';
5150

5251
class JestAssertionError extends Error {
53-
matcherResult: any;
52+
matcherResult?: SyncExpectationResult;
5453
}
5554

56-
const isPromise = obj =>
55+
const isPromise = <T extends any>(obj: any): obj is PromiseLike<T> =>
5756
!!obj &&
5857
(typeof obj === 'object' || typeof obj === 'function') &&
5958
typeof obj.then === 'function';
6059

61-
const createToThrowErrorMatchingSnapshotMatcher = function(matcher) {
62-
return function(received: any, testNameOrInlineSnapshot?: string) {
60+
const createToThrowErrorMatchingSnapshotMatcher = function(
61+
matcher: RawMatcherFn,
62+
) {
63+
return function(
64+
this: MatcherState,
65+
received: any,
66+
testNameOrInlineSnapshot?: string,
67+
) {
6368
return matcher.apply(this, [received, testNameOrInlineSnapshot, true]);
6469
};
6570
};
6671

67-
const getPromiseMatcher = (name, matcher) => {
72+
const getPromiseMatcher = (name: string, matcher: any) => {
6873
if (name === 'toThrow' || name === 'toThrowError') {
6974
return createThrowMatcher(name, true);
7075
} else if (
@@ -77,13 +82,13 @@ const getPromiseMatcher = (name, matcher) => {
7782
return null;
7883
};
7984

80-
const expect = (actual: any, ...rest): ExpectationObject => {
85+
const expect: any = (actual: any, ...rest: Array<any>): ExpectationObject => {
8186
if (rest.length !== 0) {
8287
throw new Error('Expect takes at most one argument.');
8388
}
8489

8590
const allMatchers = getMatchers();
86-
const expectation = {
91+
const expectation: any = {
8792
not: {},
8893
rejects: {not: {}},
8994
resolves: {not: {}},
@@ -131,7 +136,7 @@ const expect = (actual: any, ...rest): ExpectationObject => {
131136
return expectation;
132137
};
133138

134-
const getMessage = message =>
139+
const getMessage = (message?: () => string) =>
135140
(message && message()) ||
136141
matcherUtils.RECEIVED_COLOR('No message was specified for this matcher.');
137142

@@ -294,7 +299,7 @@ const makeThrowingMatcher = (
294299

295300
const handlError = (error: Error) => {
296301
if (
297-
matcher[INTERNAL_MATCHER_FLAG] === true &&
302+
(matcher as any)[INTERNAL_MATCHER_FLAG] === true &&
298303
!(error instanceof JestAssertionError) &&
299304
error.name !== 'PrettyFormatPluginError' &&
300305
// Guard for some environments (browsers) that do not support this feature.
@@ -309,10 +314,13 @@ const makeThrowingMatcher = (
309314
let potentialResult: ExpectationResult;
310315

311316
try {
312-
potentialResult = matcher.apply(matcherContext, [actual].concat(args));
317+
potentialResult = matcher.apply(
318+
matcherContext,
319+
([actual] as any).concat(args),
320+
);
313321

314-
if (isPromise((potentialResult: any))) {
315-
const asyncResult = ((potentialResult: any): AsyncExpectationResult);
322+
if (isPromise(potentialResult)) {
323+
const asyncResult = potentialResult as AsyncExpectationResult;
316324
const asyncError = new JestAssertionError();
317325
if (Error.captureStackTrace) {
318326
Error.captureStackTrace(asyncError, throwingMatcher);
@@ -322,7 +330,7 @@ const makeThrowingMatcher = (
322330
.then(aResult => processResult(aResult, asyncError))
323331
.catch(error => handlError(error));
324332
} else {
325-
const syncResult = ((potentialResult: any): SyncExpectationResult);
333+
const syncResult = potentialResult as SyncExpectationResult;
326334

327335
return processResult(syncResult);
328336
}
@@ -332,7 +340,7 @@ const makeThrowingMatcher = (
332340
};
333341

334342
expect.extend = (matchers: MatchersObject): void =>
335-
setMatchers(matchers, false, expect);
343+
setMatchers(matchers, false, expect as any);
336344

337345
expect.anything = anything;
338346
expect.any = any;
@@ -349,7 +357,7 @@ expect.arrayContaining = arrayContaining;
349357
expect.stringContaining = stringContaining;
350358
expect.stringMatching = stringMatching;
351359

352-
const _validateResult = result => {
360+
const _validateResult = (result: any) => {
353361
if (
354362
typeof result !== 'object' ||
355363
typeof result.pass !== 'boolean' ||
@@ -376,7 +384,7 @@ function assertions(expected: number) {
376384
getState().expectedAssertionsNumber = expected;
377385
getState().expectedAssertionsNumberError = error;
378386
}
379-
function hasAssertions(...args) {
387+
function hasAssertions(...args: Array<any>) {
380388
const error = new Error();
381389
if (Error.captureStackTrace) {
382390
Error.captureStackTrace(error, hasAssertions);
@@ -388,9 +396,9 @@ function hasAssertions(...args) {
388396
}
389397

390398
// add default jest matchers
391-
setMatchers(matchers, true, expect);
392-
setMatchers(spyMatchers, true, expect);
393-
setMatchers(toThrowMatchers, true, expect);
399+
setMatchers(matchers, true, expect as Expect);
400+
setMatchers(spyMatchers, true, expect as Expect);
401+
setMatchers(toThrowMatchers, true, expect as Expect);
394402

395403
expect.addSnapshotSerializer = () => void 0;
396404
expect.assertions = assertions;
@@ -399,4 +407,4 @@ expect.getState = getState;
399407
expect.setState = setState;
400408
expect.extractExpectedAssertionsErrors = extractExpectedAssertionsErrors;
401409

402-
module.exports = (expect: Expect);
410+
export = expect as Expect;

0 commit comments

Comments
 (0)