Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/moeriki/jestdouble

jestdouble is an alternative mock/spy for jest.
https://github.com/moeriki/jestdouble

Last synced: 7 days ago
JSON representation

jestdouble is an alternative mock/spy for jest.

Awesome Lists containing this project

README

        


jestdouble


jestdouble is an alternative mock/spy for jest.




npm version


Build Status


Coverage Status


Known Vulnerabilities

* [Installation](#installation)
* [Why](#why)
* [Quick start](#quick-start)
* [Mocking results](#mocking-results)
* [Conditionally mocking results](#conditionally-mocking-results)
* [Verifying calls](#verifying-calls)
* [Conditionally verifying calls](#conditionally-verifying-calls)
* [Matching](#matching)
* [Notes](#notes)
* [Credit](#credit)


## Installation

```
$ npm install --save-dev jestdouble
```


## Why

I wanted a mock/spy function that:

* could conditionally [mock results](#conditionally-mocking-results) / [verify calls](#conditionally-verifying-calls)
* had [smart value matching](#matching) enabled by default
* was [compatible with jasmine assertions](#verifying-calls)
* had an awesome API


## Quick start

All references to `expect` are [jest.expect](https://facebook.github.io/jest/docs/expect.html#content).

```javascript
const jd = require('jestdouble');

const func = jd(); // create a jest double

func.returns(1, { times: 1 });
func.returns(2);

func(); // 1
func(); // 2
func(); // 2

expect(func).toHaveBeenCalledTimes(3);
```


## Mocking results

### Invoking a function

```javascript
function sum(num1, num2) {
return num1 + num2;
}
const mockedSum = jd(sum);
mockedSum(1, 2); // 3
```

```javascript
const func = jd();
func.invokes(() => 1));
func(); // 1
```

### Returning values

**returning value**

```javascript
const func = jd();
func.returns(1);
func(); // 1
```

**returning this**

```javascript
const object = {
func: td()
};
object.func.returnsThis();
object.func(); // object
```

**returning rejected error**

```javascript
const func = jd();
func.rejects(new Error('nope'));
func().catch((err) => {/* Error */});
```

**returning resolved value**

```javascript
const func = jd();
func.resolves(1);
func().then((value) => {/* 1 */});
```

**throwing value**

```javascript
const func = jd();
func.throws(new Error('nope'));
func(); // throws Error
```

**calling back error**

```javascript
const func = jd();
func.callbacks(new Error('nope'));
func((err) => {/* Error */});
```

**calling back value**

```javascript
const func = jd();
func.callbacks(null, 1);
func((err, value) => {/* null, 1 */});
```


## Conditionally mocking results

**calledWith**

```javascript
const func = jd();
func.calledWith('one').returns(1);
func(); // undefined
func('one'); // 1
func('one', 'two'); // undefined
```

**calledStartingWith**

```javascript
const func = jd();
func.calledStartingWith('one').returns(1);
func(); // undefined
func('one'); // 1
func('one', 'two'); // 1
```

## Mocking options

### times

```javascript
const func = jd();
func.calledWith('one').returns(1, { times: 1 });
func.returns(2, { times: 1 });
func.returns(3);

func('one'); // 1
func(); // 2
func('one'); // 3
func(); // 3
```


## Verifying calls

`jestdouble` is compatible with jasmine assertions.

```javascript
const func = jd();
func('one');
func('two');
func('three');
expect(func).toHaveBeenCalled();
expect(func).toHaveBeenCalledTimes(3);
expect(func).toHaveBeenCalledWith('one');
```


## Conditionally verifying calls

**with**

```javascript
const func = jd();
func('one', 'two');
expect(func.with('one')).not.toHaveBeenCalled();
expect(func.with('one', 'two')).toHaveBeenCalled();
```

**startingWith**

```javascript
const func = jd();
func('one', 'two');
expect(func.startingWith('one')).toHaveBeenCalled();
expect(func.startingWith('one', 'two')).toHaveBeenCalled();
```


## Matching

Both mocking results and verifying calls support smart value matching.

```javascript
const func = jd();
func.calledWith((str) => str === 'one').returns(1);
func.calledWith(Number).returns(2);
func('one'); // 1
func(2); // 2
```

```javascript
const func = jd();
func('two');
func('three');
expect(func.with(/^t/)).toHaveBeenCalledTimes(2);
```

Check the [API of matchr](https://github.com/Moeriki/node-matchr) to learn all the possibilities.

### Matching options

There are three matching options.

```javascript
const td = require('testdouble');

td.setMatchingOptions({
matchPartialObjects: true, // default: false
matchPartialArrays: true, // default: false
matchOutOfOrderArrays: true, // default: false
});

const func = td();

func.calledWith([{ c: 3 }, { a: 1 }]).returns('OK');

func([{ a: 1, z: 26 }, { b: 2 }, { c: 3 }]); // 'OK'
```

`setMatchingOptions` delegates to `matchr.setDefaultOptions`.

## API

**Mock**

`jestdouble.invokes( arg:function [, options:object] )`

`jestdouble.returns( arg:* [, options:object] )`

`jestdouble.returnsThis( [options:object] )`

`jestdouble.resolves( arg:* [, options:object] )`

`jestdouble.rejects( arg:* [, options:object] )`

`jestdouble.callsback( arg:* [, options:object] ) // aliased as callbacks`

`jestdouble.throws( arg:* [, options:object] )`

**Conditional mock**

`jestdouble.calledWith( ...args:* ).invokes( arg:function [, options:object] )`

`jestdouble.calledWith( ...args:* ).returns( arg:* [, options:object] )`

`jestdouble.calledWith( ...args:* ).returnsThis( [options:object] )`

`jestdouble.calledWith( ...args:* ).resolves( arg:* [, options:object] )`

`jestdouble.calledWith( ...args:* ).rejects( arg:* [, options:object] )`

`jestdouble.calledWith( ...args:* ).callsback( arg:* [, options:object] ) // aliased as callbacks`

`jestdouble.calledWith( ...args:* ).throws( arg:* [, options:object] )`

`jestdouble.calledStartingWith( ...args:* ).invokes( arg:function [, options:object] )`

`jestdouble.calledStartingWith( ...args:* ) .returns( arg:* [, options:object] )`

`jestdouble.calledStartingWith( ...args:* ) .returnsThis( [options:object] )`

`jestdouble.calledStartingWith( ...args:* ) .resolves( arg:* [, options:object] )`

`jestdouble.calledStartingWith( ...args:* ) .rejects( arg:* [, options:object] )`

`jestdouble.calledStartingWith( ...args:* ) .callsback( arg:* [, options:object] ) // aliased as callbacks`

`jestdouble.calledStartingWith( ...args:* ) .throws( arg:* [, options:object] )`

**Mock options**

* **times** mock result _N_ times

**Verify**

`expect( jestdouble ).toHaveBeenCalled();`

`expect( jestdouble.with( ...args:* ) ).toHaveBeenCalled();`

`expect( jestdouble.startingWith( ...args:* ) ).toHaveBeenCalled();`

## Notes

**Results order**

Conditionally mocked results will always be returned in favour of mocked results without conditional arguments.

```javascript
const func = td();
func.returns(Infinity);
func.calledWith('one').returns(1);
func(); // Infinity
func('one'); // 1
```

```javascript
const func = td(() => 1);
func.calledWith('two').returns(2);
func(); // 1
func('two'); // 2
```

## Credit

The name is inspired by [jest](https://github.com/facebook/jest) and [testdouble.js](https://github.com/testdouble/testdouble.js). API design is inspired by [testdouble.js](https://github.com/testdouble/testdouble.js).