Mocking dependencies with Jest + TypeScript
Tags: typescript, javascript, jest, testing
Published: 2021-01-23 02:49:49

Once I've heard a phrase that was something like 


> _Pure applications can only heat machines_


And well... It that is true. In real life, some parts of our application need to have contact with the external world, to be impure, and testing them might be tricky.

<sub><sup>[wait, what are (im)pure functions and side effects?](https://www.braveclojure.com/functional-programming/#Pure_Functions__What_and_Why)</sup></sub>


<img src="https://media.tenor.com/images/f51320411362b0c51166a3b0932eb73f/tenor.gif">

# Context

One common use is setting up [feature flags](https://launchdarkly.com/features/feature-flags/) for your application. Imagine you have the following function:

```typescript
// file.ts
import { getFlag } from 'some-lib/flags'

export const myInpureFunction = () => {
  const flag = getFlag('flagName') as boolean
  return flag
    ? "this aplication is flagged"
    : "this application is not flagged"
}
```

And you need to test it, after all, you must guarantee your feature flag is behaving as you expected in your project. The problem is: we need to mock this `getFlag` function and what happens when its value changes. 

Well... What is the problem, then?

The usual way of mocking functions/modules are:

```typescript
// file.spec.ts

jest.mock('some-lib/flags', ()=>({
  getFlag: () => true // or false or any other value
})
```

But we have two contexts to cover with tests:

```typescript
// file.spec.ts

describe('when feature flag is on', () => {...})

describe('when feature flag is off', () => {...})
```

And we need to change the `getFlag` mock.

In JavaScript, we can implement solutions like:

```typescript
// file.spec.ts
import { getFlag } from 'some-lib/flags'

jest.mock('some-lib/flags')

describe('when feature flag is on', () => {
  getFlag.mockReturnValue(true)
  //...
})
```

Or using `mockImplementation` but none of these is allowed in TypeScript. 

I've been across similar solutions like 

```typescript
// file.spec.ts
import * as flags from 'some-lib/flags'

jest.mock('some-lib/flags')

describe('when feature flag is on', () => {
  flags.getFlag = jest.fn()
  //...
})
```
But TypeScript won't allow this either.

<img width="60%"  src="https://media.giphy.com/media/xT9DPtspqPm33VRnTa/giphy.gif">

# Solution

There is a way.

_Have you ever head the tragedy of ***Type Assertion*** the wise?_

<img width="60%"  src="https://media.giphy.com/media/l3diT8stVH9qImalO/giphy.gif">

This is not a very intuitive solution, in my opinion, but once you see it, is easy to understand:

```typescript
// file.spec.ts
import { getFlag } from 'some-lib/flags'

jest.mock('some-lib/flags')

describe('when feature flag is on', () => {
  beforeEach(() => {
    (getFlag as jest.Mock).mockReturnValueOnce(true);
  });

  //...
})
```

Asserting our name `getFlag` to `jest.Mock` type will allow us to use jest mock functions like `mockReturnValueOnce`. 

In this case, any test inside this `describe` will use the `true` value from our mock, I think putting it inside a `beforeEach` block gives us more control and readability of what is happening, but you can put it inside an `it` block too. 

Using `mockReturnValueOnce` instead of mocking implementation or return is a good practice because its changes will not affect any other test, be **very careful with tests' side effects**, they can lead you to trouble finding why sometimes your tests' suits pass and sometimes don't.

Well,

I do hope this is useful to you :)

<img width="60%"  src="https://media.giphy.com/media/VZCFpF6sUyoG6l5SrY/giphy.gif">

Be safe, stay home, use masks and use Emacs (_even though this is not an Emacs text haha_)
Xoxo