The basic form for React component mocks
Tags: javascript, react, testing
Published: 2020-09-07 20:20:36

---
title: The basic form for React component mocks
published: true
description: All React component mocks should have a consistent form
tags: javascript, react, testing
series: Mocking React components with Testing Library
---

In [the first part of this series](https://dev.to/d_ir/mocks-aren-t-evil-better-mocking-with-react-testing-library-3hii) I looked at why mocking is useful.

In this part I’ll cover the basic format of React mock components.

---

_All the code samples for this post are available at the following repo._

{% github dirv/mocking-react-components %}

---

Let’s look again at the components we’re working with: `BlogPage` and `PostContent`.

Here’s `BlogPage`:

```javascript
const getPostIdFromUrl = url =>
  url.substr(url.lastIndexOf("/") + 1)

export const BlogPage = ({ url }) => {

  const id = getPostIdFromUrl(url)

  return (
    <PostContent id={id} />
  )
}
```

`BlogPage` doesn’t do much other than show a `PostContent`. But it does have a little piece of functionality that we’re interested in, which is parsing the `url` prop value to pull out the required post `id`.

`PostContent` is a little more complicated: it calls the browser’s in-built `fetch` function to retrieve the text of a blog post at the URL `/post?id=${id}`, where `id` is a prop passed to it.

```javascript
export const PostContent = ({ id }) => {
  const [ text, setText ] = useState("")

  useEffect(() => {
    fetchPostContent(id)
  }, [id])

  const fetchPostContent = async () => {
    const result = await fetch(`/post?id=${id}`)
    if (result.ok) {
      setText(await result.text())
    }
  }

  return <p>{text}</p>
}
```

Actually, what `PostContent` does isn’t important because we’re not going to look at it again!

We’re going to write some tests for `BlogPage` in our test file `BlogPage.test.js`. To do that, we’ll mock out `PostContent` so that we won’t have to worry about its implementation.

**The important point is that we stub out `PostContent` so that our `BlogPage.test.js` test suite is shielded from whatever it is that `PostContent` does.**

Here’s the mock for `PostContent`:

```javascript
import { PostContent } from "../src/PostContent"

jest.mock("../src/PostContent", () => ({
  PostContent: jest.fn(() => (
    <div data-testid="PostContent" />
  ))
}))
```

Let’s break this down.

 * The mock is defined with `jest.mock`. This must mirror the corresponding import. The call is hoisted so that the `import` can be replaced. Jest replaces the entire module with your newly defined module. So in this case, we’re mocking out the entire `../src/PostContent` file.
 * Since mocks are at the module level, any component you’re mocking will need to be in its own module.
 * The call to `jest.fn` produces a **spy**: an object that records when it is called and with what parameters. We can then test calls using the `toHaveBeenCalled` and `toHaveBeenCalledWith` matchers.
 * The parameter to `jest.fn` defines a **stub** value which is returned when the function is called (when the component is rendered).
 * Stub implementations **should always be as simple as you can make them**. For React components, that means a `div`—which is arguably the HTML element with the least amount of meaning!
 * It _does_ have an attribute of `data-testid` that we’ll use to get hold of this specific element in the DOM.
 * React Testing Library argues against using `data-testid` where possible, because it wants you to treat your testing as if the test runner was a real person using your software. But for mocks I ignore that guidance, because mocks are by definition a technical concern.
 * The `data-testid` value matches the name of component. In this case that means it’s `PostContent`. This is a standard convention that I follow for all my mocks.

This is the basic form of React component mocks. 90% (or more) of my mocks look this. The other 10% have some small additions that we’ll look at in later posts.

With that mock in place, let’s write some tests for `BlogPage`.

## Verifying that the mocked component is rendered in the DOM

```javascript
describe("BlogPage", () => {
  it("renders a PostContent", () => {
    render(<BlogPage url="http://example.com/blog/my-web-page" />)
    expect(screen.queryByTestId("PostContent"))
      .toBeInTheDocument()
  })
})
```

This test is the first of **two** tests that are _always_ required when you use component mocks. The `screen.queryByTestId` searches in the current DOM  for a component with a `data-testid` value of `PostContent`.

In other words, it checks that we did in fact render the `PostContent` component.

###The responsible use of `queryByTestId`

Notice that I’ve used `queryByTestId`. React Testing Library tries to push you away from this function on two accounts: first, it wants you to use `getBy` in favour of `queryBy`, and second, as I’ve already mentioned above, it doesn’t want you to search by test ID.

In fact, testing mocks is about the only time I use `queryByTestId`. I can’t think of a time that I’ve not managed to avoid using `TestId` variants for non-mocked components.  But for mocks, its perfect: because it’s exactly that technical detail that we want to check. The user will never see this component, it’s purely there for our tests.

What we gain is the ability to have a consistent way of building mock objects: `<div data-testid="ComponentName" />` is the standard pattern we can use for all mock objects.

###`getBy*` vs `queryBy*`

`getBy` variants raise exceptions if they can’t match an element. In my opinion, this is only appropriate when the calls are _not_ part of an expectation.

So if you had:

```javascript
expect(screen.getByTestId("PostContent"))
  .toBeInTheDocument()
```

If you hadn’t rendered `<PostContent />` this test would blow up with an exception from `getByTestId`. The expectation is never run at all!

Given the choice between an expectation failing and an exception being raised, I’ll choose the expectation any day, since it’s more meaningful to the test runner.

> Unit tests, and in particular when TDD style tests, are very often about the presence of elements. For these tests I find the `queryBy` much more to my liking.

## Verifying that the mock is passed the correct props

The second test we need checks that the right props were passed to `PostContent`.

```javascript
it("constructs a PostContent with an id prop created from the url", () => {
  const postId = "my-amazing-post"
  render(<BlogPage url={`http://example.com/blog/${postId}`} />)
  expect(PostContent).toHaveBeenCalledWith(
    { id: postId },
    expect.anything())
})
```

This uses the standard Jest matchers, `toHaveBeenCalledWith` to ensure that the `PostContent` function was called with the parameters we’re expecting.

---

_When React instantiates your component, it’s simply calling the defined function with props as an object as the first parameter, and a ref as the second parameter. The second parameter is usually unimportant._

---

The JSX statement `<PostContent id="my-amazing-post" />` results in the function call `PostContent({ id: "my-amazing-post" })`.

However, it also includes a phantom second parameter that is never useful to us, so we have to account for that.

###Using `expect.anything` for the second parameter to `toHaveBeenCalledWith`

The second parameter that React passes to your component is an instance ref. It’s usually unimportant to our tests, so you’ll always want to pass `expect.anything()` to signify that you aren’t interested in its value.

_If you wanted to get rid of the `expect.anything()` call, you could write your own Jest matcher that passes it for you._

###If you’re passing no props, just use `toHaveBeenCalled`

On rare occasions the component you’ve mocked will take no parameters. You can use `toHaveBeenCalled` as a simpler version of `toHaveBeenCalledWith`.

##Understanding the basic rules of component mocks

We’ve written two tests and one mock. Here’s the important lessons that we’ve uncovered so far:

* Your mock should be a **spy** using `jest.fn` and have a **stub** return value of the simplest component you can possibly have, which is `<div />`
* You should also set a `data-testid` attribute so you can directly pinpoint this element in the DOM.
* The value of this attribute is, by convention, the name of the mocked component. So for the `PostContent` component, its stubbed value is `<div data-testid="PostContent" />`.
* Every mock requires at least two tests: the first checks that it is present in the DOM, and the second tests that it was called with the correct props.

##Why two tests?

I’ve mentioned a couple of times that we need at least two tests. But why is this?

If you didn't have the first test, to check for presence in the DOM, then you could make the second test pass by using a simple function call:

```javascript
export const BlogPost = () => {
  PostContent({ id: "my-awesome-post" })
  return null
}
```

Why you would want to do this is a subject of a whole other blog post, but here’s the short version: generally we consider a function call to be _simpler_ than a JSX statement. When you’re using _strict_ test principles you should _always_ write the simplest code to make your test pass.

Now what about if you had the first test, but not the second?

You could make it pass like this:

```javascript
export const BlogPost = () => (
  <PostContent />
)
```

Again, this is the simplest production code to make the test pass.

In order to get to the actual solution, you need both tests.

This is an important difference between end-to-end tests and unit tests: unit tests are defensive in a way that end-to-end tests tend not to be.

---

_**Key point**: Always write the simplest production code to make your tests pass. Doing so will help you write a test suite which covers all scenarios._

---

That covers the basics of mock components. In the next part, we’ll look at [testing child components that are passed to your mocks](https://dev.to/d_ir/verifying-children-passed-to-react-mock-components-2mf9).