Partial: how NOT to mock the whole world
Tags: javascript, mocking, testing
Published: 2024-02-08 03:31:12

---
title: Partial: how NOT to mock the whole world
published: true
description: Using "Deep Partial" solutions for mocks with extra powers
tags: js, mocking, testing
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bj49g6l0fv6szd20oyes.jpeg
# Use a ratio of 100:42 for best results.
# published_at: 2024-02-08 02:29 +0000
---

Mocking is a very controversial concept in testing - some thought leaders advocate it as something "bad"😤, while others have to use mocks🙃 one way or another.
No matter what we think about it - mocks are around.

However, mocks can be different 
- they could be `network mocks` (use [msw](https://mswjs.io/))
- or they could be `state mock` injected by `jest.mock` or any other force (I would recommend [magnetic-di](https://github.com/albertogasparin/react-magnetic-di/tree/master))


But in all cases, there is __a hill to die on__ - are you going to __mock the entire universe 🛸__ or just __a little__ bit?


Let's start with the 🪐 entire universe

# Jest.mock
`jest.mock`(or `vi.mock`) is a good example of "everything" - this helper mocks the entire module providing "empty stubs" for the original content.

Imagine a use case
```tsx
// index.ts
import {getConfiguration} from './config';

export const isAdmin = () => getConfiguration().user.isAdmin;
```
```tsx
// index.spec.ts
import {getConfiguration} from './config';
import {isAdmin} from './';

jest.mock('./config');

test('isAdmin', () => {
  // ??? 🤷‍♂️
  expect(isAdmin()).toBe(true); 
});
```

To make this test run you need to specify the correct mock override for `getConfiguration`. Can you do it?

Let's try
```tsx
  jest.mocked(getConfiguration).mockReturnValue({
    // 50 different fields
    user:{
     // 20 other fields,
     isAdmin: true
    }
  });
```

So you can, but you have to specify the "whole world", or typescript will not be happy.

You will not like it as well 🤮

## What about defaults?
A better way to manage mocks is by providing defaults one can "extend" from

For example
```tsx
import {defaultConfiguration} from './configuration-test-utils';
// ...
jest.mocked(getConfiguration).mockReturnValue(
    merge({}, defaultConfiguration, {
       user:{
        isAdmin: true
      }
);
```

That would greatly simplify life and establish an environment easier to maintain.

> However it is still about mocking the whole world, while __you need only one field__ 😭

## Only one!
In out case we dont need to mock everything, it's more about TypeScript being too type-safe. Let's stop this!

```tsx
jest.mocked(getConfiguration).mockReturnValue({
    user:{
     isAdmin: true
    }
} as any/* 😘 */);

// test passes ✅
```

Well, `as any` is not the best idea. Here is where `DeepPartial` helps
> `Partial` is a TypeScript helper making keys of an object non-required. `DeepPartial` is just a recursive helper for it. It has many implementations, [here is one](https://github.com/albertogasparin/react-magnetic-di/blob/master/types/index.d.ts#L10)

This gives us the ability to write code like
```tsx
jest.mocked(getConfiguration).mockReturnValue({
    user:{
     isAdmin: true
    }
} as DeepPartial<ReturnType<typeof getConfiguration>>);

```
Yeah, the last line is 🤮 and one can improve it with utilities like [shoehorn](https://github.com/total-typescript/shoehorn) hiding all complexity underneath.

```tsx
import { fromPartial } from "@total-typescript/shoehorn";
jest.mocked(getConfiguration).mockReturnValue(fromPartial({
    user:{
     isAdmin: true
    }
}));
```
Better? Better!

....

However, what would happen if __we change our code__? You know - code always drifting somewhere...

```tsx
export const isAdmin = () => (
  getConfiguration().user.isAdmin || 
  getConfiguration().user.isSuperAdmin
)
```

No tests will notice the difference, but our _partial_ mock is no longer the correct one for our use case.

We need something better.

> “actually better” is to __refactor the code__ in a way you dont need to mock everything, but we are trying to complete the task without changing the game rules as not everybody can afford refactoring and not everybody want to make their test more testable for the sake or abstract testability (aka _test induced design damage_)

# Something better
Let's change our test a little bit
```tsx
// index.spec.ts
import {partialMock} from 'partial-mock'; // ⬅️⬅️
import {getConfiguration} from './config';
import {isAdmin} from './';

jest.mock('./config');

test('isAdmin', () => {
  // ⬇️⬇️
  jest.mocked(getConfiguration).mockReturnValue(partialMock({
    user:{
     isAdmin: true
    }
  });

  expect(isAdmin()).toBe(true);
  // but instead it will throw 
});
```
Here we used `partialMock` utility to apply `DeepPartial`(but `shoehorn` can do it), but also __break test__ because the provided mock no longer represents the case.

- reproducible example - https://codesandbox.io/p/sandbox/partial-mock-example-8vr77s?file=%2Fsrc%2Findex.ts%3A21%2C20

![Failure example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uf663j7i9f99ac4bs1io.png)

## What about "over mocking"?
Imagine the opposite situation - something complex becomes simpler, but your mocks are still _too much_.

For example, imagine we do define `isSuperAdmin` missing in the example above, but we will no longer use it
```tsx
const mock = partialMock<Data>({
  isAdmin: true,
  isSuperAdmin: true,
});
expectNoUnusedKeys(mock);
```
Sandbox - https://codesandbox.io/p/sandbox/overmocking-partial-mock-example-z8qd5w?file=%2Fsrc%2Findex.ts%3A22%2C1

![unused keys](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rpwfu84yxgvv12vv5i1x.png)



# That's it, folks
That's it - [partial mock](https://github.com/theKashey/partial-mock) helps with the _"over-mocking"_, situations where you mock too much, and it also solves problems with the _"under-mocking"_ where you missing some important pieces.

Pretty sure you never though about under-mocking. Until now.

Link to follow:
- https://github.com/theKashey/partial-mock
- https://github.com/total-typescript/shoehorn
- https://github.com/albertogasparin/react-magnetic-di