• 12 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 3/3/22

Take Testing Further

Both Jest and React Testing Library are very powerful tools: they let you simulate just about anything you want.

Most of the content for the Shiny app comes from data that you get from an API (as we will be getting our content from a CMS). API calls are no exception to the rule. The data can be simulated in tests known as mocks. This means you can also test other components. 🚀

Test Your Components That Make API Calls

Install msw  to Mock Your API Calls 

You will need to do some configuration to be able to simulate API calls. Don't worry if you're not a fan of config, it won’t take long!

React Testing Library recommends using an external library: MSW (Mock Service Worker) to make mocks. It's hosted in GitHub. Start by installing the library:

yarn add msw --dev

The  msw  library will intercept the API calls that your components make during tests and mocking out what would have been returned without your app ever knowing what’s going on. Believe me, it’s 🔥.

Create Your Mocks

To do this, you need to configure a “server” that will handle the interception of API calls in each of your test files. Start by testing a component on the   Freelancers/index.jsx  page. Then create a file in  /pages/Freelancers and call it  index.test.js  .

You’re going to need  rest  from  msw , so do the following:

import { rest } from 'msw'
import { setupServer } from 'msw/node'
import { render, waitFor, screen } from '@testing-library/react'

import Freelancers from './'

const server = setupServer(
   // Specify the url that we want to "intercept"
   rest.get('http://localhost:8000/freelances', (req, res, ctx) => {
      // Here we can pass the mocked data into what is returned in json
         return res(ctx.json({}))
   })
)

// Activate the API mock before the tests from server
beforeAll(() => server.listen())
// Reset anything we might have added in terms of duration for our tests before each test
afterEach(() => server.resetHandlers())
// Close the API mock once tests are over
afterAll(() => server.close())

And that’s all the configuration you need! ✨

Where’s the data that we return?!

Well spotted! It's not in there yet. You need a format that matches what the API returns. If you do a  console.log  of whathttp://localhost:8000/freelances  returns, you’ll see that it’s a list of objects. So create a list of objects for your mock: 

const freelancersMockedData = [
   {
      name: 'Harry Potter',
      job: 'Frontend wizard',
      picture: '',
   },
   {
      name: 'Hermione Granger',
      job: 'Fullstack witch',
      picture: '',
   },
]

 It returns the following in your mock:

const server = setupServer(
   // Specify the url that we want to "intercept"
   rest.get('http://localhost:8000/freelances', (req, res, ctx) => {
      // Here we can pass the mocked data into what is returned in json
      return res(ctx.json({ freelancersList: freelancersMockedData }))
   })
)

You’re all set, so now it’s time to use it! 🔥

Use Your Mocks

Now that the configuration is complete, let's use it to test  pages/Freelancers/index.jsx  .

But before testing, consider your testing strategy. The component displays a loader while it makes the API request, then displays the data in the  Cards  components. So to start with, you can check that: 

1- The loader displays correctly during the call.

2- The first card  correctly displays the elements fetched in the call with the first element. 

Start with the first stage. You know that  isLoading  is set to  true  , so you can check that the  Loader  appears as it should.

How? The  Loader  is a simple styled  div and doesn’t contain any text!

The time has come to use data-testid(remember from the last chapter?). To use it, specify this in  Freelancers/index.jsx  :

<Loader theme={theme} data-testid="loader" />
```
And in our test, we get it with :
```
test('Should render without crash', async () => {
   render(
      <ThemeProvider>
         <Freelancers />
      </ThemeProvider>
)
   expect(screen.getByTestId('loader')).toBeTruthy()
})

 Your test is running. It works. ✅

How do I know that my test isn’t always right? That it'll just work whatever happens?

Try changing the  id  to check that it breaks properly:

expect(screen.getByTestId('thisIdDoesNotMatchAnything')).toBeTruthy()

And the test fails.

To test with your data, you’ll need  waitFor  , which you already imported from '  @testing-library/react  ' . This method manages asynchronous code, like with an API call, for example. 😉 Don’t forget to also add  an async before the test callback. 

To check that the code correctly displays the names Harry Potter and Hermione Granger, you have:

it('Should display freelancers names', async () => {
   render(
      <ThemeProvider>
         <Freelancers />
      </ThemeProvider>
   )
   expect(screen.getByTestId('loader')).toBeTruthy()
   await waitFor(() => {
      expect(screen.getByText('Harry Potter')).toBeTruthy()
      expect(screen.getByText('Hermione Granger')).toBeTruthy()
   })
})

Once again, you can change the text, like this: 

expect(screen.getByText('Harry PotOfButter')).toBeTruthy()

And the test fails! 🔥

You can see another example of mocks and a testing strategies in the screencast below 👇:

Customize Your render

So far, you've used your  Theme  directly in your tests. That’s not very clean, especially if you’re testing other components like   Home  when you’ll also have to wrap it in the router.

But that’s no problem because the render function from React Testing Library can take a wrapper as a parameter.

Declare a new React component ,Wrapper, in the previous test.

function Wrapper({ children }) {
   return <ThemeProvider>{children}</ThemeProvider>
}

And reuse it by passing it as a parameter of your render:

render(<Freelancers />, { wrapper: Wrapper })

Ta-da! 🎉

You can even turn this into a tool that you reuse in all your tests. 

To do this, create a  /test  folder in  /utils  , and put an  index.js  file where you will put the tool.

Which gives you:

import { render as rtlRender } from '@testing-library/react'
import { ThemeProvider } from '../../utils/context'

function Wrapper({ children }) {
   return <ThemeProvider>{children}</ThemeProvider>
}

export function render(ui) {
   rtlRender(ui, { wrapper: Wrapper })
}

And now all you need to do is import your new  render  in your  /pages/Freelancers/index.test.js  , and delete render  from imports with '  @testing-library/react  '  .

It works perfectly! 🎉

While we’re here, let's deal with the  Router  and  SurveyProvider . If you want to explore alternative options (and if you need to run tests that have access to your   history  ), look at the React Testing Library  documentation.

In our case, we just want the tests to work even when there’s a  Link  in the components. To do so, transform your file to add the  Router  and   SurveyProvider  :

import { render as rtlRender } from '@testing-library/react'
import { ThemeProvider, SurveyProvider } from '../../utils/context'
import { MemoryRouter } from 'react-router-dom'

function Wrapper({ children }) {
   return (
      <MemoryRouter>
         <ThemeProvider>
            <SurveyProvider>{children}</SurveyProvider>
         </ThemeProvider>
      </MemoryRouter>
   )
}

export function render(ui) {
   rtlRender(ui, { wrapper: Wrapper })
}

The test works! ✨

Discover Other Types of Tests

You’ve learned how to create unit tests with Jest and test your components with React Testing Library. Then you tested your interactions and mocked API calls. But remember that testing is a huge topic. There are many different tools and approaches. 

In the screencast below, you’ll see a demo of another approach that you haven’t seen. 👇

As mentioned, end-to-end testing is another powerful tool. To learn more, use the Cypress Testing Library.

Like with everything else in JavaScript, test tools are constantly evolving. So always watch for new ones and then read their documentation.  

Give It a Go!

It’s time to put what you’ve learned in this part into practice. You’re going to create tests for Results/index.jsx . You’ll also have to mock the data, like you’ve seen in this chapter. 

As usual, the code for getting started is on branch P3C3-begin with the solution on P3C3-solution.

Let’s Recap!

  • The  msw  library helps with mocking API calls from tests, letting you configure a  server  that returns the desired mocked data. 

  • React Testing Library contains tools such as  waitFor  , allowing you to test your components after API calls. 

  • It is possible to customize the  render  to include the  Router  and the  Providers  from context.

  • Other types of tests exist, such as end-to-end testing.

Well done! You’ve finished the part of this course on React that deals with testing. 💪 It’s now time to test your knowledge with a quiz. Good luck, and see you soon for the fourth and final part of this course!  

Example of certificate of achievement
Example of certificate of achievement