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.
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 children
which 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 content
using 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 packagejest-dom
to 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
clearMocks
to 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