Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[jest-environment] adding mocked in jest object #12133

Merged
merged 5 commits into from Dec 10, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/jest-environment/src/index.ts
Expand Up @@ -10,6 +10,7 @@ import type {LegacyFakeTimers, ModernFakeTimers} from '@jest/fake-timers';
import type {Circus, Config, Global} from '@jest/types';
import type {
fn as JestMockFn,
mocked as JestMockMocked,
spyOn as JestMockSpyOn,
ModuleMocker,
} from 'jest-mock';
Expand Down Expand Up @@ -191,6 +192,7 @@ export interface Jest {
* jest.spyOn; other mocks will require you to manually restore them.
*/
restoreAllMocks(): Jest;
mocked: typeof JestMockMocked;
/**
* Runs failed tests n-times until they pass or until the max number of
* retries is exhausted. This only works with `jest-circus`!
Expand Down
23 changes: 10 additions & 13 deletions packages/jest-runtime/src/index.ts
Expand Up @@ -1924,6 +1924,7 @@ export default class Runtime {
};
const fn = this._moduleMocker.fn.bind(this._moduleMocker);
const spyOn = this._moduleMocker.spyOn.bind(this._moduleMocker);
const mocked = this._moduleMocker.mocked.bind(this._moduleMocker);

const setTimeout = (timeout: number) => {
if (this._environment.global.jasmine) {
Expand All @@ -1942,32 +1943,28 @@ export default class Runtime {
};

const jestObject: Jest = {
advanceTimersByTime: (msToRun: number) =>
_getFakeTimers().advanceTimersByTime(msToRun),
advanceTimersToNextTimer: (steps?: number) =>
_getFakeTimers().advanceTimersToNextTimer(steps),
advanceTimersByTime: (msToRun: number) => _getFakeTimers().advanceTimersByTime(msToRun),
advanceTimersToNextTimer: (steps?: number) => _getFakeTimers().advanceTimersToNextTimer(steps),
autoMockOff: disableAutomock,
autoMockOn: enableAutomock,
clearAllMocks,
clearAllTimers: () => _getFakeTimers().clearAllTimers(),
createMockFromModule: (moduleName: string) =>
this._generateMock(from, moduleName),
createMockFromModule: (moduleName: string) => this._generateMock(from, moduleName),
deepUnmock,
disableAutomock,
doMock: mock,
dontMock: unmock,
enableAutomock,
fn,
genMockFromModule: (moduleName: string) =>
this._generateMock(from, moduleName),
genMockFromModule: (moduleName: string) => this._generateMock(from, moduleName),
getRealSystemTime: () => {
const fakeTimers = _getFakeTimers();

if (fakeTimers === this._environment.fakeTimersModern) {
return fakeTimers.getRealSystemTime();
} else {
throw new TypeError(
'getRealSystemTime is not available when not using modern timers',
'getRealSystemTime is not available when not using modern timers'
);
}
},
Expand All @@ -1988,23 +1985,22 @@ export default class Runtime {
fakeTimers.runAllImmediates();
} else {
throw new TypeError(
'runAllImmediates is not available when using modern timers',
'runAllImmediates is not available when using modern timers'
);
}
},
runAllTicks: () => _getFakeTimers().runAllTicks(),
runAllTimers: () => _getFakeTimers().runAllTimers(),
runOnlyPendingTimers: () => _getFakeTimers().runOnlyPendingTimers(),
setMock: (moduleName: string, mock: unknown) =>
setMockFactory(moduleName, () => mock),
setMock: (moduleName: string, mock: unknown) => setMockFactory(moduleName, () => mock),
setSystemTime: (now?: number | Date) => {
const fakeTimers = _getFakeTimers();

if (fakeTimers === this._environment.fakeTimersModern) {
fakeTimers.setSystemTime(now);
} else {
throw new TypeError(
'setSystemTime is not available when not using modern timers',
'setSystemTime is not available when not using modern timers'
);
}
},
Expand All @@ -2014,6 +2010,7 @@ export default class Runtime {
unstable_mockModule: mockModule,
useFakeTimers,
useRealTimers,
mocked,
};
return jestObject;
}
Expand Down
41 changes: 41 additions & 0 deletions website/versioned_docs/version-27.2/JestObjectAPI.md
Expand Up @@ -578,6 +578,47 @@ Returns the `jest` object for chaining.

Restores all mocks back to their original value. Equivalent to calling [`.mockRestore()`](MockFunctionAPI.md#mockfnmockrestore) on every mocked function. Beware that `jest.restoreAllMocks()` only works when the mock was created with `jest.spyOn`; other mocks will require you to manually restore them.

### `jest.mocked<T>(item: T, deep = false)`
SimenB marked this conversation as resolved.
Show resolved Hide resolved

The `mocked` test helper provides typings on your mocked modules and even their deep methods, based on the typing of its source. It makes use of the latest TypeScript feature, so you even have argument types completion in the IDE (as opposed to `jest.MockInstance`).

_Note: while it needs to be a function so that input type is changed, the helper itself does nothing else than returning the given input value._

Example:

```ts
// foo.ts
export const foo = {
a: {
b: {
c: {
hello: (name: string) => `Hello, ${name}`,
},
},
},
name: () => 'foo',
};
```

```ts
// foo.spec.ts
import {foo} from './foo';
jest.mock('./foo');
// here the whole foo var is mocked deeply
const mockedFoo = jest.mocked(foo, true);
test('deep', () => {
// there will be no TS error here, and you'll have completion in modern IDEs
mockedFoo.a.b.c.hello('me');
// same here
expect(mockedFoo.a.b.c.hello.mock.calls).toHaveLength(1);
});
test('direct', () => {
foo.name();
// here only foo.name is mocked (or its methods if it's an object)
expect(mocked(foo.name).mock.calls).toHaveLength(1);
});
```

## Mock Timers

### `jest.useFakeTimers(implementation?: 'modern' | 'legacy')`
Expand Down