Returning values from mocks (Jest mocking + React part 3)
Tags: jest, mocking, react
Published: 2022-09-08 14:57:31

In this third part we are going to talk about returning values from mocks. `jest.mock()` is a method that mocks a module. It takes the module and replaces it with a mocking function, `jest.fn()`. When we talk about returning values from a mock, we mean that we return values from a mocking function, `jest.fn()`. We already saw how to return values from mocks in [part 1](https://dev.to/peterlidee/introduction-to-jest-mocking-jest-mocking-react-part-1-29e). 

```javascript
// 1. call jest.fn() with a mock implementation parameter
jest.fn(() => 'Hello')
jest.fn((value) => 'Hello ' + value)
// 2. use jest.fn() methods
jest.fn().mockReturnValue('Hello')
jest.fn().mockImplementation((value) => 'Hello ' + value)
```

But, how does this work for mocking modules with `jest.mock()`? We will look at using:

1. The methods of `jest.fn()`
2. Passing the mock implementation parameter in `jest.fn()`.
3. Using manual mocks.

*The examples I use in this article are available on [github](https://github.com/peterlidee/mocking-app) ([src/part3](https://github.com/peterlidee/mocking-app/tree/main/src/part3)). These files a build upon create-react-app so you can run them using `npm run start` or run the tests using `npm run test`.*

## 1. Using mocking function (jest.fn) methods

We are going to start of with the easiest one, using the methods `Jest` provides us on mocking functions. To illustrate this, we will be using a new example using the children props pattern:

```jsx
// part3/example1/WrapperComponent.js
function WrapperComponent(props){
  return(
    <div className="WrapperComponent">
      <div>Wrapper Component</div>
      {props.children}
    </div>
  )
}
export default WrapperComponent
```
```jsx
// part3/example1/ParentComponent.js
import WrapperComponent from './WrapperComponent'

function ParentComponent(){
  return(
    <div className="ParentComponent">
      <div>Parent Component</div>
      <WrapperComponent>
        <div>Textblock 1.</div>
        <div>Textblock 2.</div>
      </WrapperComponent>
      <WrapperComponent>
        <div>Textblock 3.</div>
        <div>Textblock 4.</div>
      </WrapperComponent>
    </div>
  )
}
export default ParentComponent
```
Take a close look at these components and think how you would test the parent. Let us try to use `.toHaveBeenCalledWith` on an automatic mock:

```javascript
// part3/example1/__tests__/test1.js
import { screen, render } from '@testing-library/react'
import ParentComponent from '../ParentComponent'
import WrapperComponent from '../WrapperComponent'

jest.mock('../WrapperComponent')

test('ParentComponent renders correctly', () => {
  render(<ParentComponent />)
  expect(screen.getByText(/Parent Component/i)).toBeInTheDocument()
})

// fails cause [] euhhhh
test('Wrapper mock was called with the correct arguments', () => {
  render(<ParentComponent />)
  expect(WrapperComponent).toHaveBeenCalledTimes(2)
  expect(WrapperComponent).toHaveBeenNthCalledWith(1,
    expect.objectContaining({
      children: [] // euh
    }),
    expect.anything()
  )
})
```

We run into a problem when we try to test the children prop of the wrapper components. How do we describe these children? We can actually do it:

```html
<div>Textblock 1.</div>
<div>Textblock 2.</div>
```
becomes
```javascript
expect.objectContaining({
  children: [<div>Textblock 1</div>, <div>Textblock 2</div>]
}),
```

But it is messy. Also remember that we are using simple examples. What would you do when there is more text or even another component in there? How would we test this then?

The solution is to return the children from the mock. The basic function of the wrapper is to receive *something* (children), wrap this *something* in some html and then return that:

```javascript
// component receives
prop.children
// component returns
<somehtml>props.children</somehtml>
```

The plan is to mock the wrapper and then just return the children from this mock:

```javascript
// mock receives (get called with)
prop.children
// mock returns
props.children
```

The mock passes on what it receives without any alterations. When rendering the parent this would happen:

Test receives:

```jsx
<WrapperComponent>
  <div>Textblock 1.</div>
  <div>Textblock 2.</div>
</WrapperComponent>
```
The test renders:

```html
  <div>Textblock 1.</div>
  <div>Textblock 2.</div>
```

And this we can test:

```javascript
expect(screen.getByTest(/Texblock 1/)).toBeInTheDocument()
expect(screen.getByTest(/Texblock 2/)).toBeInTheDocument()
```

What would our mock look like?

```javascript
// mock the module
jest.mock('../WrapperComponent')
// add return value
WrapperComponent.mockImplementation(
  props => <>{props.children}</>
)
```
First, we mock the module, then we use the `Jest` method `.mockImplementation()` to add a return value to the `WrapperComponent` mock. What is this implementation? We just return the children: `props => <>{props.children}</>`.

Let's go over this again. We establised that it was too complex to map out the children for testing in a `expect.objectContaining()` statement. So we needed another method.

The wrapper takes the children and then returns them wrapped in some html. So, if we let our mock return the children without altering or wrapping them, then:
- Our mock doesn't to anything anymore which is great because it won't pollute the parent test.
- We still have access to our children, because they get rendered which is great because this means we can test them.

To make our mock return the children, we used the method `.mockImplementation()`.

The full test here:

```javascript
// part3/example1/__tests__/test2.js
import { screen, render } from '@testing-library/react'
import ParentComponent from '../ParentComponent'
import WrapperComponent from '../WrapperComponent'

jest.mock('../WrapperComponent')

beforeEach(() => {
  // eslint-disable-next-line testing-library/no-node-access
  WrapperComponent.mockImplementation(props => <>{props.children}</>)
})

test('ParentComponent renders correctly', () => {
  render(<ParentComponent />)
  expect(screen.getByText(/Parent Component/i)).toBeInTheDocument()
})

// you wouldn't write this test in a real app, but it makes sense here
test('WrapperComponent is mocked and not rendered', () => {
  render(<ParentComponent />)
  expect(screen.queryAllByText(/Wrapper Component/i)).toHaveLength(0)
})

test('Wrapper mock was called correctly', () => {
  jest.clearAllMocks()
  render(<ParentComponent />)
  expect(WrapperComponent).toHaveBeenCalledTimes(2)
})

test('Wrapper children got rendered', () => {
  render(<ParentComponent />)
  expect(screen.getAllByText(/Textblock/)).toHaveLength(4)
})
```
This should all make sense now. A couple of remarks:

1. `Eslint` doesn't like it when you call props.children directly inside `Jest`: "Avoid direct node access". But I wouldn't know how to test this without calling props.children, so I added an `eslint-disable-next-line` rule.
2. These 2 lines are equivalent:
    ```javascript
    WrapperComponent.mockImplementation(props => <>{props.children}</>)
    WrapperComponent.mockImplementation(props => props.children)
    ```
    I prefer the first because it makes it more clear that you are returing `jsx`. You can use either at your own discretion.

This concludes our first method of returning a value from a mock, using methods on mocking functions like `.mockImplementation()`.

___

## 2. Passing a mock implementation parameter into the jest.fn()

It's a bit of a mouthfull but basically just looks like this: 

```javascript
jest.fn((value) => 'Hello ' + value)
``` 

We return a value by simply passing in an implementation (a function). This function we pass in, replaces the component we are mocking.

But, where is the `jest.fn()` when we use automatic mocking?

```javascript
jest.mock('path')
``` 
`Jest` has hidden it from us and we can't access it. How then do we do this? We will manually write the mocking function for `jest.mock`. (Carefull, this is something different from manual mocking which we will see later.)

Up until now, we've been using automatic mocks. Calling `jest.mock(path)` sets up a mock for us. But, `jest.mock()` can take a second parameter: `jest.mock(path, moduleFactory)`. `Jest` calls this the [module factory parameter](https://jestjs.io/docs/es6-class-mocks#calling-jestmock-with-the-module-factory-parameter):

> `jest.mock(path, moduleFactory)` takes a module factory argument. **A module factory is a function that returns the mock**.

So we need to write a moduleFactory: a function that returns a mock. Reusing the previous example, it looks like this:

```javascript
jest.mock('../WrapperComponent', () => {
  return jest.fn()
})
// alternative syntax
jest.mock('../WrapperComponent', () => jest.fn())
```
*I prefer the first version with the explicit return as I find it more readable. But it is your choice.*

Why do we use this moduleFactory? Because we needed access to `jest.fn()`. Why do we need access to `jest.fn()`? Because we want to pass a mock implemetation parameter into it. What would this implementation be? The same thing we returned in our previous example:

```javascript
// previous
WrapperComponent.mockImplementation(props => <>{props.children}</>)
// now
jest.fn((props) => <>{props.children}</>)
```

And we're done. Here is the full test. It's the same as the previous example except how we return a value from `jest.mock`.

```javascript
// part3/example1/__test__/test3.js
import { screen, render } from '@testing-library/react'
import ParentComponent from '../ParentComponent'
import WrapperComponent from '../WrapperComponent'

jest.mock('../WrapperComponent', () => {
  // eslint-disable-next-line testing-library/no-node-access
  return jest.fn((props) => <>{props.children}</>)
})

test('ParentComponent renders correctly', () => {
  render(<ParentComponent />)
  expect(screen.getByText(/Parent Component/i)).toBeInTheDocument()
})

// you wouldn't write this test in a real app, but it makes sense here
test('WrapperComponent is mocked and not rendered', () => {
  render(<ParentComponent />)
  expect(screen.queryAllByText(/Wrapper Component/i)).toHaveLength(0)
})

test('Wrapper mock was called correctly', () => {
  jest.clearAllMocks()
  render(<ParentComponent />)
  expect(WrapperComponent).toHaveBeenCalledTimes(2)
})

test('Wrapper children got rendered', () => {
  render(<ParentComponent />)
  expect(screen.getAllByText(/Textblock/)).toHaveLength(4)
})
```
Let me go over the mock once again:

```javascript
// theory
jest.mock(path, moduleFactory)
jest.fn(implementation)

// practice
jest.mock('../WrapperComponent', () => {
  return jest.fn((props) => <>{props.children}</>)
})
```
We pass a second argument to `jest.mock()` called the module factory. This is just a function that returns a mocking function. 

Inside our `jest.fn()`, we pass a mock implementation parameter. This is where we add a return value to the mock.

Remarks:
 1. Again eslint yells at us from using props.children.
 2. `jest.mock` gets called at the root level of a file. We set up a return value from the mock at the root. So every test render will get this return. If you need different behaviour, turn to  `.mockImplementation` or `.mockImplementationOnce`.

___

## Intermediate section: default and named imports

There is another issue with using the moduleFactory parameter. Until now, we've always worked with default exported modules. But what to do with named exports? We make a small adjustment to the previous example:

```jsx
// part3/example2/WrapperComponent.js
function WrapperComponent(props){
  return(
    <div className="WrapperComponent">
      <div>Wrapper Component</div>
      {props.children}
    </div>
  )
}

function ExtraComponent(){
  return(
    <div className="ExtraComponent">
      Extra Component
    </div>
  )
}

export default WrapperComponent
export { ExtraComponent }
```

```jsx
// part3/example2/ParentComponent
import WrapperComponent, { ExtraComponent } from './WrapperComponent'

function ParentComponent(){
  return(
    <div className="ParentComponent">
      <div>Parent Component</div>
      <WrapperComponent>
        <div>Textblock 1</div>
        <div>Textblock 2</div>
      </WrapperComponent>
      <ExtraComponent />
    </div>
  )
}

export default ParentComponent
```

We added a component `ExtraComponent` to the WrapperComponent.js file. The extra component is a named export. In the parent we just call the extra component. Let's now show the difference in mocking named versus default exports.

### Default export only

We already saw how to mock a default export:

```javascript
jest.mock('../WrapperComponent', () => {
  return jest.fn(props => <>{props.children}</>)
})
```
Note that this will not mock `ExtraComponent`. I am just showing what to do when mocking a default export.

### Named export only

```javascript
jest.mock('../WrapperComponent', () => {
  return {
    ExtraComponent: jest.fn()
  }
})
```

So, `jest.mock()` takes the path and then the moduleFactory function. That is still the same. What is new is that moduleFactory now returns an object. This object has the named export `ExtraComponent` as a property with `jest.fn()` as it's value. That is how you mock the named export. (This does not mock the default export!)

### Named + default export

```javascript
jest.mock('../WrapperComponent', () => {
  return{
    __esModule: true,
    default: jest.fn((props) => <>{props.children}</>),
    ExtraComponent: jest.fn()
  }
})
```
First argument is the path, second is a moduleFactory function that returns an object. The ExtraComponent property also remained the same. The default prop on our object corresponds to `export default`. So default corresponds to the `WrapperComponent`. What do we return for the wrapper? A mocking function with props.children as return value.

The final property `__esModule` (mind the double underscore) is required to make the default prop work: [`Jest` documentation](https://jestjs.io/docs/jest-object#jestmockmodulename-factory-options).

Here is the final test:

```javascript
// part3/example2/__tests__/test1.js
import { screen, render } from '@testing-library/react'
import ParentComponent from '../ParentComponent'
import WrapperComponent, { ExtraComponent } from '../WrapperComponent'

beforeEach(() => {
  jest.clearAllMocks()
})

jest.mock('../WrapperComponent', () => ({
  __esModule: true,
  // eslint-disable-next-line testing-library/no-node-access
  default: jest.fn((props) => <>{props.children}</>),
  ExtraComponent: jest.fn()
}))

test('ParentComponent renders correctly', () => {
  render(<ParentComponent />)
  expect(screen.getByText(/Parent Component/i)).toBeInTheDocument()
})

test('WrapperComponent was mocked correctly', () => {
  render(<ParentComponent />)
  expect(WrapperComponent).toHaveBeenCalledTimes(1)
})

test('WrapperComponent children rendered correctly', () => {
  render(<ParentComponent />)
  expect(screen.getAllByText(/TextBlock/i)).toHaveLength(2)
})

test('ExtraComponent was mocked correctly', () => {
  render(<ParentComponent />)
  expect(ExtraComponent).toHaveBeenCalledTimes(1)
})
```
A final sidenote: automatic mocks work just fine on default and named exports. `Jest` is pretty clever. Of course this will no longer return any values from the mocks.

```javascript
// part3/example2/__tests__/test2.js
import { screen, render } from '@testing-library/react'
import ParentComponent from '../ParentComponent'
import WrapperComponent, { ExtraComponent } from '../WrapperComponent'

jest.mock('../WrapperComponent')

test('Auto mock worked', () => {
  render(<ParentComponent />)
  expect(screen.getByText(/Parent Component/i)).toBeInTheDocument()
  // mocking default export works
  expect(WrapperComponent).toHaveBeenCalledTimes(1)
  // mocking named export works
  expect(ExtraComponent).toHaveBeenCalledTimes(1)
})
```
___

## 3. Manual mocks

Thusfar we've looked at 2 methods to add a return value to a mock. Using the methods on `jest.fn()` and passing a mock implementation function into `jest.fn()`. The third method is what `Jest` calls manual mocks. 

We will continue working with our previous example. So, we have a parent component and then a file with a wrapper and an extra component. To create a manual mock for this file WrapperComponent.js we add a folder "\_\_mocks\_\_" at the same level of the file. Inside this map, we add a new file WrapperComponent.js:

```jsx
// part3/example3/__mocks__/WrapperComponent.js
const WrapperComponent = jest.fn().mockImplementation((props) => <>{props.children}</>)
const ExtraComponent = jest.fn()

export default WrapperComponent
export { ExtraComponent }
```
We return mocking functions for each component. For the wrapper component we added the return value to the mock. Next, in our test we just add an automatic mock:

```javascript
jest.fn('../WrapperComponent')
```

When we render the test, `Jest` will check if there's a manual mock in the reserved folder and use that. And that's all. We created a manual mock. The test:

```javascript
// part3/example3/__tests__/test1.js
import { screen, render } from '@testing-library/react'
import ParentComponent from '../ParentComponent'
import WrapperComponent, { ExtraComponent } from '../WrapperComponent'

beforeEach(() => {
  jest.clearAllMocks()
})

jest.mock('../WrapperComponent')

test('ParentComponent renders correctly', () => {
  render(<ParentComponent />)
  expect(screen.getByText(/Parent Component/i)).toBeInTheDocument()
})

test('WrapperComponent was mocked correctly', () => {
  render(<ParentComponent />)
  expect(WrapperComponent).toHaveBeenCalledTimes(1)
})

test('WrapperComponent children rendered correctly', () => {
  render(<ParentComponent />)
  expect(screen.getAllByText(/TextBlock/i)).toHaveLength(2)
})

test('ExtraComponent was mocked correctly', () => {
  render(<ParentComponent />)
  expect(ExtraComponent).toHaveBeenCalledTimes(1)
})
```

This is a simple example to show how manual mocks work. In a real testing environment, manual mocks are used to mock complex components, especially components that fetch and then return data.

___

## Intermediate section: moking external modules (node-packages)

On a sidenote: mocking node-packages works exactly the same as mocking internal modules. You can either use an automatic mock:

```javascript
jest.mock('package-name')
```
Or use the moduleFactory parameter:

```javascript
jest.mock('package-name', () => {
  __esModule: true,
  default: jest.fn(),
  'someFunction': jest.fn()
})
```

Returning values from mocked node modules is also identical.
___

## Summary

In this article, I showed how to return data from mocks:

1. Using `jest.fn()` methods.
2. Using `jest.fn()` with a mock implementation.
3. Using manual mocks.

We tested a `React` component with children props to illustrate this and we also took a look at the difference between mocking a named versus mocking a default export.

In the [next and last part](https://dev.to/peterlidee/setting-up-tests-with-mocks-and-more-mocking-examples-jest-mocking-react-part-4-337g) of this series we will look at some caveats of using mocks in `Jest` tests and we will wrap up this series with some more examples of testing `React` coding patterns.