Checking children passed to a mock React component

On the eve of the start of the course “JavaScript Test Automation” We continue to publish the translation of a series of useful articles.


This is the third part in a series about testing with React. In the last part, we covered the basic format for mocking React components.

Another thing you can do with mocks is to check if the correct children were passed in. That’s actually what we are now looking at.

All code samples for this article are available in this repository.

dirv / mocking-react-components

Imagine we want to insert a newsletter subscription form inside PostContent… We can do this by passing children to it.

Here is the updated component BlogPage:

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

  const id = getPostIdFromUrl(url)

  const handleSignUp = () => {
    // …
  }

  return (
    <PostContent id={id}>
      <input type="email" placeholder="Sign up to my mailing list!" />
      <button onClick={handleSignUp}>Sign up</button>
    </PostContent>
  )
}

What matters is that our tests BlogPage shouldn’t care what PostContent does with children. They just have to make sure they are passed on to him.

We could check it out by pulling out the props children from the record .mock.calls and then rendering it with render… In other words, treat it like a rendering props.

But there is an easier way – to make the mock component render it children:

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

Now we can write a test that checks if there was button rendered as a child PostContent:

it("renders the mailing list sign up button as a child of PostContent", () => {
  render(<BlogPage url="http://example.com/blog/my-web-page" />)

  const postContentElement = screen.getByTestId("PostContent")

  const button = screen.queryByRole(
    "button", { name: "Sign up" })

  expect(postContentElement).toContainElement(button)
})

The same method can be repeated for the field input

If you run this test, you will notice a problem. Our previous test that checked passed props now doesn’t work. His expectation looked like this:

expect(PostContent).toHaveBeenCalledWith(
    { id: postId },
    expect.anything())

It fails because suddenly we also have a props childrenwhich we did not expect at all in this test.

We’ll fix this with expect.objectContain

Use expect.objectContain to localize your tests

It is often useful to have multiple unit tests for a single mock component call! I usually start with one test with all the props listed. But for any fairly complex props values, it can be much more useful to split them into separate tests with a good description. Props children – just such a case: our test, which verifies that we are passing the correct ID, does not depend on anything related to the displayed content.

We can avoid testing contentusing expect.objectContain in our anticipation:

 expect(PostContent).toHaveBeenCalledWith(
    expect.objectContaining({ id: postId }),
    expect.anything())

Let’s summarize

So what have we learned so far?

  • To test mocked children, change the mock component to `jest.fn (({children}) = {children})

  • Use toContainElement from the matcher package jest-domto check if components are rendered as children of your component mock.

  • Use expect.objectContain for writing unit tests that won’t break when your props change.

  • Use the Jest config option clearMocksto make sure your spies are cleaned up before each test.

In the fourth part we will test multiple rendered instances of the same mock component


We invite you to sign up for free demo lesson on the topic: “Puppeteer Basics”


Read more:

  • Mocky doesn’t bite! Mastering Mocking with the React Testing Library

  • Basic React Component Mocking Format

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *