Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## main

### Features

- `[jest-mock]` Add `mockThrowValue` and `mockThrowValueOnce` methods to `jest.fn()` for synchronous error throwing

## 30.0.5

### Features
Expand Down
70 changes: 70 additions & 0 deletions docs/MockFunctionAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,76 @@ test('async test', async () => {
});
```

### `mockFn.mockThrowValue(value)`

Shorthand for:

```js
jest.fn().mockImplementation(() => {
throw value;
});
```

Useful to create mock functions that will always throw:

```js tab
test('sync test', () => {
const mockFn = jest.fn().mockThrowValue(new Error('Sync error message'));

expect(() => mockFn()).toThrow('Sync error message');
});
```

```ts tab
import {jest, test} from '@jest/globals';

test('sync test', () => {
const mockFn = jest
.fn<() => never>()
.mockThrowValue(new Error('Sync error message'));

expect(() => mockFn()).toThrow('Sync error message');
});
```

### `mockFn.mockThrowValueOnce(value)`

Shorthand for:

```js
jest.fn().mockImplementationOnce(() => {
throw value;
});
```

Useful together with `.mockReturnValueOnce()` or to throw different exceptions over multiple calls:

```js tab
test('sync test', () => {
const mockFn = jest
.fn()
.mockReturnValueOnce('first call')
.mockThrowValueOnce(new Error('Sync error message'));

expect(mockFn()).toBe('first call');
expect(() => mockFn()).toThrow('Sync error message');
});
```

```ts tab
import {jest, test} from '@jest/globals';

test('sync test', () => {
const mockFn = jest
.fn<() => string>()
.mockReturnValueOnce('first call')
.mockThrowValueOnce(new Error('Sync error message'));

expect(mockFn()).toBe('first call');
expect(() => mockFn()).toThrow('Sync error message');
});
```

### `mockFn.withImplementation(fn, callback)`

Accepts a function which should be temporarily used as the implementation of the mock while the callback is being executed.
Expand Down
22 changes: 22 additions & 0 deletions packages/jest-mock/__typetests__/mock-functions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,28 @@ describe('jest.fn()', () => {
).type.not.toBeCallableWith();
});

test('.mockThrowValue()', () => {
expect(
fn(() => 'string').mockThrowValue(new Error('Mock error')),
).type.toBe<Mock<() => string>>();
expect(fn(() => 'string').mockThrowValue('Mock error')).type.toBe<
Mock<() => string>
>();

expect(fn(() => 'string').mockThrowValue).type.not.toBeCallableWith();
});

test('.mockThrowValueOnce()', () => {
expect(
fn(() => 'string').mockThrowValueOnce(new Error('Mock error')),
).type.toBe<Mock<() => string>>();
expect(fn(() => 'string').mockThrowValueOnce('Mock error')).type.toBe<
Mock<() => string>
>();

expect(fn(() => 'string').mockThrowValueOnce).type.not.toBeCallableWith();
});

test('.withImplementation()', () => {
expect(mockFn.withImplementation(mockFnImpl, () => {})).type.toBe<void>();
expect(mockFn.withImplementation(mockFnImpl, async () => {})).type.toBe<
Expand Down
19 changes: 19 additions & 0 deletions packages/jest-mock/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,25 @@ describe('moduleMocker', () => {
]);
});

it('supports mocking functions that throw', () => {
const err = new Error('thrown');
const fn = moduleMocker.fn();
fn.mockThrowValue(err);

expect(() => fn()).toThrow(err);
});

it('supports mocking functions that throw only once', () => {
const defaultErr = new Error('default thrown');
const err = new Error('thrown');
const fn = moduleMocker.fn();
fn.mockThrowValue(defaultErr);
fn.mockThrowValueOnce(err);

expect(() => fn()).toThrow(err);
expect(() => fn()).toThrow(defaultErr);
});

describe('return values', () => {
it('tracks return values', () => {
const fn = moduleMocker.fn(x => x * 2);
Expand Down
12 changes: 12 additions & 0 deletions packages/jest-mock/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ export interface MockInstance<T extends FunctionLike = UnknownFunction>
mockResolvedValueOnce(value: ResolveType<T>): this;
mockRejectedValue(value: RejectType<T>): this;
mockRejectedValueOnce(value: RejectType<T>): this;
mockThrowValue(value: unknown): this;
mockThrowValueOnce(value: unknown): this;
}

export interface Replaced<T = unknown> {
Expand Down Expand Up @@ -791,6 +793,16 @@ export class ModuleMocker {
this._environmentGlobal.Promise.reject(value),
);

f.mockThrowValue = (value: unknown) =>
f.mockImplementation(() => {
throw value;
});

f.mockThrowValueOnce = (value: unknown) =>
f.mockImplementationOnce(() => {
throw value;
});

f.mockImplementationOnce = (fn: T) => {
// next function call will use this mock implementation return value
// or default mock implementation return value
Expand Down
70 changes: 70 additions & 0 deletions website/versioned_docs/version-30.0/MockFunctionAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,76 @@ test('async test', async () => {
});
```

### `mockFn.mockThrowValue(value)`

Shorthand for:

```js
jest.fn().mockImplementation(() => {
throw value;
});
```

Useful to create mock functions that will always throw:

```js tab
test('sync test', () => {
const mockFn = jest.fn().mockThrowValue(new Error('Sync error message'));

expect(() => mockFn()).toThrow('Sync error message');
});
```

```ts tab
import {jest, test} from '@jest/globals';

test('sync test', () => {
const mockFn = jest
.fn<() => never>()
.mockThrowValue(new Error('Sync error message'));

expect(() => mockFn()).toThrow('Sync error message');
});
```

### `mockFn.mockThrowValueOnce(value)`

Shorthand for:

```js
jest.fn().mockImplementationOnce(() => {
throw value;
});
```

Useful together with `.mockReturnValueOnce()` or to throw different exceptions over multiple calls:

```js tab
test('sync test', () => {
const mockFn = jest
.fn()
.mockReturnValueOnce('first call')
.mockThrowValueOnce(new Error('Sync error message'));

expect(mockFn()).toBe('first call');
expect(() => mockFn()).toThrow('Sync error message');
});
```

```ts tab
import {jest, test} from '@jest/globals';

test('sync test', () => {
const mockFn = jest
.fn<() => string>()
.mockReturnValueOnce('first call')
.mockThrowValueOnce(new Error('Sync error message'));

expect(mockFn()).toBe('first call');
expect(() => mockFn()).toThrow('Sync error message');
});
```

### `mockFn.withImplementation(fn, callback)`

Accepts a function which should be temporarily used as the implementation of the mock while the callback is being executed.
Expand Down
Loading