From 100b033dba977f518f95b25b7f3b19e3a3031b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Sun, 10 Feb 2019 12:46:09 +0100 Subject: [PATCH] chore: migrate jest-mock to TypeScript (#7847) --- .eslintrc.js | 1 + CHANGELOG.md | 1 + packages/jest-mock/package.json | 4 + .../{jest_mock.test.js => index.test.ts} | 5 +- packages/jest-mock/src/{index.js => index.ts} | 396 +++++++++++++----- packages/jest-mock/tsconfig.json | 8 + packages/jest-types/src/Mocks.ts | 31 ++ packages/jest-types/src/index.ts | 3 +- packages/jest-util/src/FakeTimers.ts | 10 +- .../src/__tests__/fakeTimers.test.ts | 5 +- packages/jest-util/tsconfig.json | 2 +- 11 files changed, 339 insertions(+), 127 deletions(-) rename packages/jest-mock/src/__tests__/{jest_mock.test.js => index.test.ts} (99%) rename packages/jest-mock/src/{index.js => index.ts} (70%) create mode 100644 packages/jest-mock/tsconfig.json create mode 100644 packages/jest-types/src/Mocks.ts diff --git a/.eslintrc.js b/.eslintrc.js index d7ed999831eb..db8aa1b063a8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -25,6 +25,7 @@ module.exports = { {argsIgnorePattern: '^_'}, ], 'import/order': 'error', + 'no-dupe-class-members': 'off', 'no-unused-vars': 'off', }, }, diff --git a/CHANGELOG.md b/CHANGELOG.md index f0a5fbc41f6e..566573f13318 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - `[@jest/types]`: New package to handle shared types ([#7834](https://github.com/facebook/jest/pull/7834)) - `[jest-util]`: Migrate to TypeScript ([#7844](https://github.com/facebook/jest/pull/7844)) - `[jest-watcher]`: Migrate to TypeScript ([#7843](https://github.com/facebook/jest/pull/7843)) +- `[jest-mock]`: Migrate to TypeScript ([#7847](https://github.com/facebook/jest/pull/7847)) ### Performance diff --git a/packages/jest-mock/package.json b/packages/jest-mock/package.json index 9f10c2f9a30f..3dfe72868f3b 100644 --- a/packages/jest-mock/package.json +++ b/packages/jest-mock/package.json @@ -9,8 +9,12 @@ "engines": { "node": ">= 6" }, + "dependencies": { + "@jest/types": "^24.1.0" + }, "license": "MIT", "main": "build/index.js", + "types": "build/index.d.ts", "browser": "build-es5/index.js", "gitHead": "634e5a54f46b2a62d1dc81a170562e6f4e55ad60" } diff --git a/packages/jest-mock/src/__tests__/jest_mock.test.js b/packages/jest-mock/src/__tests__/index.test.ts similarity index 99% rename from packages/jest-mock/src/__tests__/jest_mock.test.js rename to packages/jest-mock/src/__tests__/index.test.ts index bd38cb281806..31cee40614c8 100644 --- a/packages/jest-mock/src/__tests__/jest_mock.test.js +++ b/packages/jest-mock/src/__tests__/index.test.ts @@ -6,9 +6,7 @@ * */ -'use strict'; - -const vm = require('vm'); +import vm from 'vm'; describe('moduleMocker', () => { let moduleMocker; @@ -182,6 +180,7 @@ describe('moduleMocker', () => { it('mocks ES2015 non-enumerable static properties and methods', () => { class ClassFoo { static foo() {} + static fooProp: Function; } ClassFoo.fooProp = () => {}; diff --git a/packages/jest-mock/src/index.js b/packages/jest-mock/src/index.ts similarity index 70% rename from packages/jest-mock/src/index.js rename to packages/jest-mock/src/index.ts index 9a95f5d9f2e1..9e6450e093ba 100644 --- a/packages/jest-mock/src/index.js +++ b/packages/jest-mock/src/index.ts @@ -3,23 +3,11 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {Global} from 'types/Global'; - -type Mock = any; -export type MockFunctionMetadata = { - ref?: any, - members?: {[key: string]: MockFunctionMetadata}, - mockImpl?: () => any, - name?: string, - refID?: string | number, - type?: string, - value?: any, - length?: number, -}; +import {Mocks} from '@jest/types'; + +type Global = NodeJS.Global; // | Window – add once TS improves typings; /** * Possible types of a MockFunctionResult. @@ -38,33 +26,65 @@ type MockFunctionResult = { /** * Indicates how the call completed. */ - type: MockFunctionResultType, + type: MockFunctionResultType; /** * The value that was either thrown or returned by the function. * Undefined when type === 'incomplete'. */ - value: any, + value: unknown; }; -type MockFunctionState = { - instances: Array, - calls: Array>, +type MockFunctionState = { + calls: Array; + instances: Array; + invocationCallOrder: Array; /** * List of results of calls to the mock function. */ - results: Array, - invocationCallOrder: Array, + results: Array; }; type MockFunctionConfig = { - isReturnValueLastSet: boolean, - defaultReturnValue: any, - mockImpl: any, - mockName: string, - specificReturnValues: Array, - specificMockImpls: Array, + isReturnValueLastSet: boolean; + defaultReturnValue: unknown; + mockImpl: Function | undefined; + mockName: string; + specificReturnValues: Array; + specificMockImpls: Array; }; +interface Mock + extends Function, + MockInstance { + new (...args: Y): T; + (...args: Y): T; +} + +interface SpyInstance extends MockInstance {} + +interface MockInstance { + _isMockFunction: boolean; + _protoImpl: Function; + getMockName(): string; + getMockImplementation(): Function | undefined; + mock: MockFunctionState; + mockClear(): this; + mockReset(): this; + mockRestore(): void; + mockImplementation(fn: (...args: Y) => T): this; + mockImplementation(fn: () => Promise): this; + mockImplementationOnce(fn: (...args: Y) => T): this; + mockImplementationOnce(fn: () => Promise): this; + mockName(name: string): this; + mockReturnThis(): this; + mockReturnValue(value: T): this; + mockReturnValueOnce(value: T): this; + mockResolvedValue(value: T): this; + mockResolvedValueOnce(value: T): this; + mockRejectedValue(value: T): this; + mockRejectedValueOnce(value: T): this; +} + const MOCK_CONSTRUCTOR_NAME = 'mockConstructor'; const FUNCTION_NAME_RESERVED_PATTERN = /[\s!-\/:-@\[-`{-~]/; @@ -124,57 +144,113 @@ const RESERVED_KEYWORDS = new Set([ 'yield', ]); -function matchArity(fn: any, length: number): any { +function matchArity(fn: Function, length: number): Function { let mockConstructor; switch (length) { case 1: - mockConstructor = function(a) { + mockConstructor = function(this: unknown, _a: unknown) { return fn.apply(this, arguments); }; break; case 2: - mockConstructor = function(a, b) { + mockConstructor = function(this: unknown, _a: unknown, _b: unknown) { return fn.apply(this, arguments); }; break; case 3: - mockConstructor = function(a, b, c) { + mockConstructor = function( + this: unknown, + _a: unknown, + _b: unknown, + _c: unknown, + ) { return fn.apply(this, arguments); }; break; case 4: - mockConstructor = function(a, b, c, d) { + mockConstructor = function( + this: unknown, + _a: unknown, + _b: unknown, + _c: unknown, + _d: unknown, + ) { return fn.apply(this, arguments); }; break; case 5: - mockConstructor = function(a, b, c, d, e) { + mockConstructor = function( + this: unknown, + _a: unknown, + _b: unknown, + _c: unknown, + _d: unknown, + _e: unknown, + ) { return fn.apply(this, arguments); }; break; case 6: - mockConstructor = function(a, b, c, d, e, f) { + mockConstructor = function( + this: unknown, + _a: unknown, + _b: unknown, + _c: unknown, + _d: unknown, + _e: unknown, + _f: unknown, + ) { return fn.apply(this, arguments); }; break; case 7: - mockConstructor = function(a, b, c, d, e, f, g) { + mockConstructor = function( + this: unknown, + _a: unknown, + _b: unknown, + _c: unknown, + _d: unknown, + _e: unknown, + _f: unknown, + _g: unknown, + ) { return fn.apply(this, arguments); }; break; case 8: - mockConstructor = function(a, b, c, d, e, f, g, h) { + mockConstructor = function( + this: unknown, + _a: unknown, + _b: unknown, + _c: unknown, + _d: unknown, + _e: unknown, + _f: unknown, + _g: unknown, + _h: unknown, + ) { return fn.apply(this, arguments); }; break; case 9: - mockConstructor = function(a, b, c, d, e, f, g, h, i) { + mockConstructor = function( + this: unknown, + _a: unknown, + _b: unknown, + _c: unknown, + _d: unknown, + _e: unknown, + _f: unknown, + _g: unknown, + _h: unknown, + _i: unknown, + ) { return fn.apply(this, arguments); }; break; default: - mockConstructor = function() { + mockConstructor = function(this: unknown) { return fn.apply(this, arguments); }; break; @@ -183,11 +259,11 @@ function matchArity(fn: any, length: number): any { return mockConstructor; } -function getObjectType(value: any): string { +function getObjectType(value: unknown): string { return Object.prototype.toString.apply(value).slice(8, -1); } -function getType(ref?: any): string | null { +function getType(ref?: unknown): Mocks.MockFunctionMetadataType | null { const typeName = getObjectType(ref); if ( typeName === 'Function' || @@ -253,10 +329,10 @@ function isReadonlyProp(object: any, prop: string): boolean { class ModuleMockerClass { _environmentGlobal: Global; - _mockState: WeakMap; + _mockState: WeakMap, MockFunctionState>; _mockConfigRegistry: WeakMap; _spyState: Set<() => void>; - ModuleMocker: Class; + ModuleMocker: typeof ModuleMockerClass; _invocationCallCounter: number; /** @@ -307,7 +383,7 @@ class ModuleMockerClass { if (!isReadonlyProp(object, prop)) { const propDesc = Object.getOwnPropertyDescriptor(object, prop); - + // @ts-ignore Object.__esModule if ((propDesc !== undefined && !propDesc.get) || object.__esModule) { slots.add(prop); } @@ -320,7 +396,7 @@ class ModuleMockerClass { return Array.from(slots); } - _ensureMockConfig(f: Mock): MockFunctionConfig { + _ensureMockConfig(f: Mock): MockFunctionConfig { let config = this._mockConfigRegistry.get(f); if (!config) { config = this._defaultMockConfig(); @@ -329,7 +405,9 @@ class ModuleMockerClass { return config; } - _ensureMockState(f: Mock): MockFunctionState { + _ensureMockState( + f: Mock, + ): MockFunctionState { let state = this._mockState.get(f); if (!state) { state = this._defaultMockState(); @@ -349,7 +427,7 @@ class ModuleMockerClass { }; } - _defaultMockState(): MockFunctionState { + _defaultMockState(): MockFunctionState { return { calls: [], instances: [], @@ -358,7 +436,34 @@ class ModuleMockerClass { }; } - _makeComponent(metadata: MockFunctionMetadata, restore?: () => void): Mock { + _makeComponent( + metadata: Mocks.MockFunctionMetadata, + restore?: () => void, + ): Object; + _makeComponent( + metadata: Mocks.MockFunctionMetadata, + restore?: () => void, + ): Array; + _makeComponent( + metadata: Mocks.MockFunctionMetadata, + restore?: () => void, + ): RegExp; + _makeComponent( + metadata: Mocks.MockFunctionMetadata< + T, + Y, + 'constant' | 'collection' | 'null' | 'undefined' + >, + restore?: () => void, + ): T; + _makeComponent( + metadata: Mocks.MockFunctionMetadata, + restore?: () => void, + ): Mock; + _makeComponent( + metadata: Mocks.MockFunctionMetadata, + restore?: () => void, + ): Object | Array | RegExp | T | undefined | Mock { if (metadata.type === 'object') { return new this._environmentGlobal.Object(); } else if (metadata.type === 'array') { @@ -373,10 +478,6 @@ class ModuleMockerClass { ) { return metadata.value; } else if (metadata.type === 'function') { - /* eslint-disable prefer-const */ - let f; - /* eslint-enable prefer-const */ - const prototype = (metadata.members && metadata.members.prototype && @@ -384,17 +485,17 @@ class ModuleMockerClass { {}; const prototypeSlots = this._getSlots(prototype); const mocker = this; - const mockConstructor = matchArity(function() { + const mockConstructor = matchArity(function(this: T, ...args: Y) { const mockState = mocker._ensureMockState(f); const mockConfig = mocker._ensureMockConfig(f); mockState.instances.push(this); - mockState.calls.push(Array.prototype.slice.call(arguments)); + mockState.calls.push(args); // Create and record an "incomplete" mock result immediately upon // calling rather than waiting for the mock to return. This avoids // issues caused by recursion where results can be recorded in the // wrong order. const mockResult = { - type: 'incomplete', + type: ('incomplete' as unknown) as MockFunctionResultType, value: undefined, }; mockState.results.push(mockResult); @@ -422,8 +523,11 @@ class ModuleMockerClass { // it easier to interact with mock instance call and // return values if (prototype[slot].type === 'function') { + // @ts-ignore no index signature const protoImpl = this[slot]; + // @ts-ignore no index signature this[slot] = mocker.generateFromMetadata(prototype[slot]); + // @ts-ignore no index signature this[slot]._protoImpl = protoImpl; } }); @@ -487,7 +591,10 @@ class ModuleMockerClass { return finalReturnValue; }, metadata.length || 0); - f = this._createMockFunction(metadata, mockConstructor); + const f = (this._createMockFunction( + metadata, + mockConstructor, + ) as unknown) as Mock; f._isMockFunction = true; f.getMockImplementation = () => this._ensureMockConfig(f).mockImpl; @@ -495,10 +602,9 @@ class ModuleMockerClass { this._spyState.add(restore); } - this._mockState.set(f, this._defaultMockState()); + this._mockState.set(f, this._defaultMockState()); this._mockConfigRegistry.set(f, this._defaultMockConfig()); - // $FlowFixMe - defineProperty getters not supported Object.defineProperty(f, 'mock', { configurable: false, enumerable: true, @@ -522,20 +628,20 @@ class ModuleMockerClass { return restore ? restore() : undefined; }; - f.mockReturnValueOnce = value => { + f.mockReturnValueOnce = (value: T) => { // next function call will return this value or default return value const mockConfig = this._ensureMockConfig(f); mockConfig.specificReturnValues.push(value); return f; }; - f.mockResolvedValueOnce = value => + f.mockResolvedValueOnce = (value: T) => f.mockImplementationOnce(() => Promise.resolve(value)); - f.mockRejectedValueOnce = value => + f.mockRejectedValueOnce = (value: T) => f.mockImplementationOnce(() => Promise.reject(value)); - f.mockReturnValue = value => { + f.mockReturnValue = (value: T) => { // next function call will return specified return value or this one const mockConfig = this._ensureMockConfig(f); mockConfig.isReturnValueLastSet = true; @@ -543,13 +649,15 @@ class ModuleMockerClass { return f; }; - f.mockResolvedValue = value => + f.mockResolvedValue = (value: T) => f.mockImplementation(() => Promise.resolve(value)); - f.mockRejectedValue = value => + f.mockRejectedValue = (value: T) => f.mockImplementation(() => Promise.reject(value)); - f.mockImplementationOnce = fn => { + f.mockImplementationOnce = ( + fn: ((...args: Y) => T) | (() => Promise), + ): Mock => { // next function call will use this mock implementation return value // or default mock implementation return value const mockConfig = this._ensureMockConfig(f); @@ -558,7 +666,9 @@ class ModuleMockerClass { return f; }; - f.mockImplementation = fn => { + f.mockImplementation = ( + fn: ((...args: Y) => T) | (() => Promise), + ): Mock => { // next function call will use mock implementation return value const mockConfig = this._ensureMockConfig(f); mockConfig.isReturnValueLastSet = false; @@ -568,11 +678,11 @@ class ModuleMockerClass { }; f.mockReturnThis = () => - f.mockImplementation(function() { + f.mockImplementation(function(this: T) { return this; }); - f.mockName = name => { + f.mockName = (name: string) => { if (name) { const mockConfig = this._ensureMockConfig(f); mockConfig.mockName = name; @@ -596,10 +706,10 @@ class ModuleMockerClass { } } - _createMockFunction( - metadata: MockFunctionMetadata, - mockConstructor: () => any, - ): any { + _createMockFunction( + metadata: Mocks.MockFunctionMetadata, + mockConstructor: Function, + ): Function { let name = metadata.name; if (!name) { return mockConstructor; @@ -656,11 +766,22 @@ class ModuleMockerClass { return createConstructor(mockConstructor); } - _generateMock( - metadata: MockFunctionMetadata, - callbacks: Array<() => any>, - refs: Object, - ): Mock { + _generateMock( + metadata: Mocks.MockFunctionMetadata, + callbacks: Array, + refs: { + [key: string]: + | Object + | Array + | RegExp + | T + | undefined + | Mock; + }, + ): Mock { + // metadata not compatible but it's the same type, maybe problem with + // overloading of _makeComponent and not _generateMock? + // @ts-ignore const mock = this._makeComponent(metadata); if (metadata.refID != null) { refs[metadata.refID] = mock; @@ -669,7 +790,11 @@ class ModuleMockerClass { this._getSlots(metadata.members).forEach(slot => { const slotMetadata = (metadata.members && metadata.members[slot]) || {}; if (slotMetadata.ref != null) { - callbacks.push(() => (mock[slot] = refs[slotMetadata.ref])); + callbacks.push( + (function(ref) { + return () => (mock[slot] = refs[ref]); + })(slotMetadata.ref), + ); } else { mock[slot] = this._generateMock(slotMetadata, callbacks, refs); } @@ -691,8 +816,10 @@ class ModuleMockerClass { * @param _metadata Metadata for the mock in the schema returned by the * getMetadata method of this module. */ - generateFromMetadata(_metadata: MockFunctionMetadata): Mock { - const callbacks = []; + generateFromMetadata( + _metadata: Mocks.MockFunctionMetadata, + ): Mock { + const callbacks: Function[] = []; const refs = {}; const mock = this._generateMock(_metadata, callbacks, refs); callbacks.forEach(setter => setter()); @@ -703,8 +830,11 @@ class ModuleMockerClass { * @see README.md * @param component The component for which to retrieve metadata. */ - getMetadata(component: any, _refs?: Map): ?MockFunctionMetadata { - const refs = _refs || new Map(); + getMetadata( + component: T, + _refs?: Map, + ): Mocks.MockFunctionMetadata | null { + const refs = _refs || new Map(); const ref = refs.get(component); if (ref != null) { return {ref}; @@ -715,7 +845,7 @@ class ModuleMockerClass { return null; } - const metadata: MockFunctionMetadata = {type}; + const metadata: Mocks.MockFunctionMetadata = {type}; if ( type === 'constant' || type === 'collection' || @@ -725,8 +855,11 @@ class ModuleMockerClass { metadata.value = component; return metadata; } else if (type === 'function') { + // @ts-ignore this is a function so it has a name metadata.name = component.name; + // @ts-ignore may be a mock if (component._isMockFunction === true) { + // @ts-ignore may be a mock metadata.mockImpl = component.getMockImplementation(); } } @@ -734,28 +867,29 @@ class ModuleMockerClass { metadata.refID = refs.size; refs.set(component, metadata.refID); - let members = null; + let members: { + [key: string]: Mocks.MockFunctionMetadata; + } | null = null; // Leave arrays alone if (type !== 'array') { - if (type !== 'undefined') { - this._getSlots(component).forEach(slot => { - if ( - type === 'function' && - component._isMockFunction === true && - slot.match(/^mock/) - ) { - return; - } - - const slotMetadata = this.getMetadata(component[slot], refs); - if (slotMetadata) { - if (!members) { - members = {}; - } - members[slot] = slotMetadata; + this._getSlots(component).forEach(slot => { + if ( + type === 'function' && + // @ts-ignore may be a mock + component._isMockFunction === true && + slot.match(/^mock/) + ) { + return; + } + // @ts-ignore no index signature + const slotMetadata = this.getMetadata(component[slot], refs); + if (slotMetadata) { + if (!members) { + members = {}; } - }); - } + members[slot] = slotMetadata; + } + }); } if (members) { @@ -769,16 +903,39 @@ class ModuleMockerClass { return !!fn && fn._isMockFunction === true; } - fn(implementation?: any): any { + fn(implementation?: (...args: Y) => T): Mock { const length = implementation ? implementation.length : 0; - const fn = this._makeComponent({length, type: 'function'}); + const fn = this._makeComponent({length, type: 'function'}); if (implementation) { fn.mockImplementation(implementation); } return fn; } - spyOn(object: any, methodName: any, accessType?: string): any { + spyOn( + object: T, + methodName: M, + accessType: 'get', + ): SpyInstance; + + spyOn( + object: T, + methodName: M, + accessType: 'set', + ): SpyInstance; + + spyOn( + object: T, + methodName: M, + ): T[M] extends (...args: any[]) => any + ? SpyInstance, ArgsType> + : never; + + spyOn( + object: T, + methodName: M, + accessType?: 'get' | 'set', + ) { if (accessType) { return this._spyOnProperty(object, methodName, accessType); } @@ -802,11 +959,13 @@ class ModuleMockerClass { ); } + // @ts-ignore overriding original method with a Mock object[methodName] = this._makeComponent({type: 'function'}, () => { object[methodName] = original; }); - object[methodName].mockImplementation(function() { + // @ts-ignore original method is now a Mock + object[methodName].mockImplementation(function(this: unknown) { return original.apply(this, arguments); }); } @@ -814,7 +973,11 @@ class ModuleMockerClass { return object[methodName]; } - _spyOnProperty(obj: any, propertyName: any, accessType: string = 'get'): any { + _spyOnProperty( + obj: T, + propertyName: M, + accessType: 'get' | 'set' = 'get', + ): Mock { if (typeof obj !== 'object' && typeof obj !== 'function') { throw new Error( 'Cannot spyOn on a primitive value; ' + this._typeOf(obj) + ' given', @@ -867,19 +1030,20 @@ class ModuleMockerClass { } descriptor[accessType] = this._makeComponent({type: 'function'}, () => { - // $FlowFixMe - descriptor[accessType] = original; - // $FlowFixMe - Object.defineProperty(obj, propertyName, descriptor); + descriptor![accessType] = original; + Object.defineProperty(obj, propertyName, descriptor!); }); - descriptor[accessType].mockImplementation(function() { + (descriptor[accessType] as Mock).mockImplementation(function( + this: unknown, + ) { + // @ts-ignore return original.apply(this, arguments); }); } Object.defineProperty(obj, propertyName, descriptor); - return descriptor[accessType]; + return descriptor[accessType] as Mock; } clearAllMocks() { @@ -901,5 +1065,7 @@ class ModuleMockerClass { } } -export type ModuleMocker = ModuleMockerClass; -module.exports = new ModuleMockerClass(global); +// TODO: bring this type export back once done with TS migration +// export type ModuleMocker = ModuleMockerClass; + +export = new ModuleMockerClass(global); diff --git a/packages/jest-mock/tsconfig.json b/packages/jest-mock/tsconfig.json new file mode 100644 index 000000000000..3046cb6b9b6a --- /dev/null +++ b/packages/jest-mock/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + }, + "references": [{"path": "../jest-types"}] +} diff --git a/packages/jest-types/src/Mocks.ts b/packages/jest-types/src/Mocks.ts new file mode 100644 index 000000000000..36e28a49ca01 --- /dev/null +++ b/packages/jest-types/src/Mocks.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +export type MockFunctionMetadataType = + | 'object' + | 'array' + | 'regexp' + | 'function' + | 'constant' + | 'collection' + | 'null' + | 'undefined'; + +export type MockFunctionMetadata< + T, + Y extends unknown[], + Type = MockFunctionMetadataType +> = { + ref?: number; + members?: {[key: string]: MockFunctionMetadata}; + mockImpl?: (...args: Y) => T; + name?: string; + refID?: number; + type?: Type; + value?: T; + length?: number; +}; diff --git a/packages/jest-types/src/index.ts b/packages/jest-types/src/index.ts index 61dfddbf9407..2c9054b64270 100644 --- a/packages/jest-types/src/index.ts +++ b/packages/jest-types/src/index.ts @@ -9,5 +9,6 @@ import * as Config from './Config'; import * as Console from './Console'; import * as SourceMaps from './SourceMaps'; import * as TestResult from './TestResult'; +import * as Mocks from './Mocks'; -export {Config, Console, SourceMaps, TestResult}; +export {Config, Console, SourceMaps, TestResult, Mocks}; diff --git a/packages/jest-util/src/FakeTimers.ts b/packages/jest-util/src/FakeTimers.ts index d8cfac38d266..a4abbeb78268 100644 --- a/packages/jest-util/src/FakeTimers.ts +++ b/packages/jest-util/src/FakeTimers.ts @@ -5,14 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -// not yet migrated to TS -// import {ModuleMocker} from 'jest-mock'; - -type ModuleMocker = any; - +import mock from 'jest-mock'; import {formatStackTrace, StackTraceConfig} from 'jest-message-util'; import setGlobal from './setGlobal'; +type ModuleMocker = typeof mock; + /** * We don't know the type of arguments for a callback ahead of time which is why * we are disabling the flowtype/no-weak-types rule here. @@ -356,8 +354,10 @@ export default class FakeTimers { _createMocks() { const fn = (impl: Function) => + // @ts-ignore TODO: figure out better typings here this._moduleMocker.fn().mockImplementation(impl); + // TODO: add better typings; these are mocks, but typed as regular timers this._fakeTimerAPIs = { clearImmediate: fn(this._fakeClearImmediate.bind(this)), clearInterval: fn(this._fakeClearTimer.bind(this)), diff --git a/packages/jest-util/src/__tests__/fakeTimers.test.ts b/packages/jest-util/src/__tests__/fakeTimers.test.ts index 3a14fed27b93..7d53b0c91e51 100644 --- a/packages/jest-util/src/__tests__/fakeTimers.test.ts +++ b/packages/jest-util/src/__tests__/fakeTimers.test.ts @@ -6,9 +6,10 @@ */ import vm from 'vm'; -// @ts-ignore: not yet migrated -import mock, {ModuleMocker} from 'jest-mock'; +import mock from 'jest-mock'; import FakeTimers from '../FakeTimers'; +// TODO: import this type directly from jest-mock once TS migration is done +type ModuleMocker = typeof mock; const timerConfig = { idToRef: (id: number) => id, diff --git a/packages/jest-util/tsconfig.json b/packages/jest-util/tsconfig.json index 931ea0e1de53..e6221a0ea3e6 100644 --- a/packages/jest-util/tsconfig.json +++ b/packages/jest-util/tsconfig.json @@ -4,5 +4,5 @@ "rootDir": "src", "outDir": "build" }, - "references": [{"path": "../jest-types"}] + "references": [{"path": "../jest-types"}, {"path": "../jest-mock"}] }