Reader small image

You're reading from  Mastering React Test-Driven Development - Second Edition

Product typeBook
Published inSep 2022
Reading LevelIntermediate
PublisherPackt
ISBN-139781803247120
Edition2nd Edition
Languages
Tools
Right arrow
Author (1)
Daniel Irvine
Daniel Irvine
author image
Daniel Irvine

Daniel Irvine is a UK-based software consultant. He helps businesses simplify their existing codebases and assists dev teams in improving the quality of their software using eXtreme programming (XP) practices. He has been coaching developers for many years and co-founded the Queer Code London meetup.
Read more about Daniel Irvine

Right arrow

Testing useEffect and Mocking Components

In the previous chapter, you saw how test doubles can be used to verify network requests that occur upon user actions, such as clicking a submit button. We can also use them to verify side effects when our components mount, like when we're fetching data from the server that the component needs to function. In addition, test doubles can be used to verify the rendering of child components. Both use cases often occur together with container components, which are responsible for simply loading data and passing it to another component for display.

In this chapter, we’ll build a new component, AppointmentsDayViewLoader, that loads the day’s appointments from the server and passes them to the AppointmentsDayView component that we implemented in Chapter 2, Rendering Lists and Detail Views. By doing so, the user can view a list of appointments occurring today.

In this chapter, we will cover the following topics:

  • Mocking...

Technical requirements

Mocking child components

In this section, we’re going to use the jest.mock test helper to replace the child component with a dummy implementation. Then, we’ll write expectations that check whether we passed the right props to the child component and that it is correctly rendered on the screen.

But first, let’s take a detailed look at how mocked components work.

How to mock components, and why?

The component we’re going to build in this chapter has the following shape:

export const AppointmentsDayViewLoader = ({ today }) => {
  const [appointments, setAppointments] = useState([]);
  useEffect(() => {
    // fetch data from the server
    const result = await global.fetch(...);
    // populate the appointments array:
    setAppointments(await result.json());
  }, [today]);
  return (
    <AppointmentsDayView...

Fetching data on mount with useEffect

The appointment data we’ll load comes from an endpoint that takes start and end dates. These values filter the result to a specific time range:

GET /appointments/<from>-<to>

Our new component is passed a today prop that is a Date object with the value of the current time. We will calculate the from and to dates from the today prop and construct a URL to pass to global.fetch.

To get there, first, we’ll cover a bit of theory on testing the useEffect hook. Then, we’ll implement a new renderAndWait function, which we’ll need because we’re invoking a promise when the component is mounted. Finally, we’ll use that function in our new tests, building out the complete useEffect implementation.

Understanding the useEffect hook

The useEffect hook is React’s way of running side effects. The idea is that you provide a function that will run each time any of the hook’s dependencies...

Building matchers for component mocks

In this section, we’ll introduce a new matcher, toBeRenderedWithProps, that simplifies the expectations for our mock spy object.

Recall that our expectations look like this:

expect(AppointmentsDayView).toBeCalledWith(
  { appointments },
  expect.anything()
);

Imagine if you were working on a team that had tests like this. Would a new joiner understand what that second argument, expect.anything(), is doing? Will you understand what this is doing if you don’t go away for a while and forget how component mocks work?

Let’s wrap that into a matcher that allows us to hide the second property.

We need two matchers to cover the common use cases. The first, toBeRenderedWithProps, is the one we’ll work through in this chapter. The second, toBeFirstRenderedWithProps, is left as an exercise for you.

The matcher, toBeRenderedWithProps, will pass if the component is currently rendered with the...

Variants of the jest.mock call

Before we finish up this chapter, let’s take a look at some variations on the jest.mock call that you may end up using.

The key thing to remember is to keep your mocks as simple as possible. If you start to feel like your mocks need to become more complex, you should treat that as a sign that your components are overloaded and should be broken apart in some way.

That being said, there are cases where you must use different forms of the basic component mock.

Removing the spy function

To begin with, you can simplify your jest.mock calls by not using jest.fn:

jest.mock("../src/AppointmentsDayView", () => ({
  AppointmentsDayView: () => (
    <div id="AppointmentsDayView" />
  ),
}));

With this form, you’ve set a stub return value, but you won’t be able to spy on any props. This is sometimes useful if, for example, you’ve got multiple files...

Summary

This chapter covered the most complex form of mocking: setting up component mocks with jest.mock.

Since mocking is a complex art form, it’s best to stick with a small set of established patterns, which I’ve shown in this chapter. You can also refer to the code in Chapter 11, Test-Driving React Router, for examples that show some of the variations that have been described in this chapter.

You also learned how to test-drive a useEffect hook before writing another matcher.

You should now feel confident with testing child components by using component mocks, Including loading data into those components through useEffect actions.

In the next chapter, we’ll extend this technique further by pulling out callback props from mock components and invoking them within our tests.

Exercises

The following are some exercises for you to try out:

  1. Complete the message property tests on the toBeRenderedWithProps matcher.
  2. Add the toBeFirstRenderedWithProps matcher and update your test suite to use this matcher. Since this matcher is very similar to toBeRenderedWithProps, you can add it to the same module file that contains the toBeRenderedWithProps matcher. You can also try to factor out any shared code into its own function that both matchers can use.
  3. Add a toBeRendered matcher that checks if a component was rendered without checking its props.
  4. Complete the matchers you’ve written so that they throw an exception if the passed argument is not a Jest mock.
  5. Create a new component, AppointmentFormLoader, that calls the GET /availableTimeSlots endpoint when mounted. It should render an AppointmentForm component with its appointments prop set to the data returned from the server.

Further reading

To learn how to mock components without relying on jest.mock, please check out https://reacttdd.com/alternatives-to-module-mocks.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Mastering React Test-Driven Development - Second Edition
Published in: Sep 2022Publisher: PacktISBN-13: 9781803247120
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Daniel Irvine

Daniel Irvine is a UK-based software consultant. He helps businesses simplify their existing codebases and assists dev teams in improving the quality of their software using eXtreme programming (XP) practices. He has been coaching developers for many years and co-founded the Queer Code London meetup.
Read more about Daniel Irvine