Hamburger Icon
  • Labs icon Lab
  • Core Tech
Labs

Guided: Testing in React

This lab will provide you with essential skills for writing effective unit tests in React applications. Utilizing Jest as your test runner and React Testing Library for rendering and querying, you'll explore best practices for test structure and Jest's assertion utilities. Additionally, you'll learn to simulate user interactions and validate component behaviors. Ultimately, you'll gain the knowledge and tools to implement a robust unit testing strategy, enhancing the reliability and maintainability of your React codebase.

Labs

Path Info

Level
Clock icon Intermediate
Duration
Clock icon 49m
Published
Clock icon May 21, 2024

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Introduction

    In this React Guided Code Lab, you'll be adding unit tests to a basic application created with Create React App and TypeScript.

    Create React App uses Jest as its test runner and React Testing Library to render React components, and to query and interact with the DOM nodes.

    The guided steps will give you hands-on experience working with Jest and querying the DOM for nodes in a way that is similar to how the user finds elements on the page with React Testing Library.

    Each step will have a set of tasks for you to complete in the files provided in your app. Once you attempt to complete a task, the task can be checked by clicking the Validate button.

    In this lab, clicking the Validate button triggers Code Labs to assess your answer in two ways. Firstly, it runs tests against your code, offering feedback based on your task. Secondly, it executes the tests you've created, displaying messages provided by Jest.

    Upon validating the code you'll be able to see your test output and a custom message under the Feedback/Checks area within your task.

    If you are stuck or would like to compare solutions, a solution directory has been provided for you as well.

    To make the process easier, all the necessary dependencies and application code have already been added to the project. You are only going to focus on writing tests as instructed by each task.

    To see the app in the browser, run npm start in the Terminal tab and then click the following link: {{localhost:3000}}.

    Note that an additional Terminal tab has been provided to you, so you can run the other npm scripts that you'll be writing throughout this lab.

  2. Challenge

    Jest CLI

    In this step, you'll delve into running your tests in the Terminal and utilizing Jest CLI commands alongside React Scripts to enhance the scripts defined in your package.json file.

    When you initiate an app using Create React App, it comes bundled with one key dependency: react-scripts. This npm module streamlines all the requisite configurations to swiftly kickstart app development, allowing you to focus solely on coding. Moreover, the app provides pre-defined scripts that can be executed in your Terminal, including npm test, which runs all tests in watch mode.

    React Scripts employs Jest as its test runner. Initially, it might not be apparent, but when you run npm test in an app that uses React Scripts, you're essentially executing jest --watchAll. Give it a try by typing npm test in your Terminal; each time you change a file, it will automatically re-run the tests.

    While familiarizing yourself with watch mode during the initial run, you'll see instructions about its usage at the bottom of the test output. You can revisit these instructions during subsequent test runs by typing w, or exit watch mode at any time with q.

    Throughout this step, you'll advance through a series of tasks guiding you in creating various test scripts in your package.json file that will allow you to explore a few Jest CLI commands to extend the default npm test provided to you.

    info> When adding your scripts to the package.json file, ensure that there is a comma preceding each script, and that there are no trailing commas if no other script follows. In the first task, you will reduce the noise in the Terminal by modifying the package.json file to not run tests every time you make a change to the file. This configuration ensures that tests are executed without watch mode enabled. Now, execute npm run test:ci in your Terminal to see the output of your newly created script.

    When this option is provided, Jest will assume it is running in a CI environment. Note that unless stated otherwise, Jest will run all tests in your project, including the tests that this Guided Lab is using to give you feedback on your code.

    In the next few tasks, you'll explore how to limit this default behavior in a few different ways:

    • Configuring Jest to ignore specific test files: You can specify certain test files to be ignored using the testPathIgnorePatterns option in your Jest configuration.

    • Exploring --testNamePattern=regex: You can utilize this option to run only tests whose names match a specified regular expression.

    • Guidance on running a single test file: You will be guided to run only one test file by passing the file path as an argument to your test command. Now, try runningnpm run test:ignore in your Terminal . You will see the tests that were previously reported as passing or failing are now reduced to only two tests.

    Test your new script by running npm run test:name:pattern in your Terminal. You'll see that the test named "name pattern correctly", located inside the src/__tests__/jest.cli.spec.tsx file, is correctly executed. In the first task you created a command called jest:test to execute your tests without relying on React Scripts' default mode, which typically operates in watch mode.

    Now, you will explore how to leverage this command to selectively run tests from a single file by providing it as an argument.

    info>When you created the jest:test command, you may have noticed that using -- after npm test enabled you to pass Jest CLI commands directly. The -- addition to the npm test script gives you the flexibility to include a file path as an argument, allowing Jest to execute tests solely for that file.

    Give it a try and run the following command in your Terminal and notice that Jest is only running the file specified after jest:test:

    npm run jest:test src/__tests__/jest-cli.spec.tsx
    
  3. Challenge

    React Testing Library

    In this step, you will explore the basics of React Testing Library while following best practices when querying and testing a React component.

    React Testing Library is a light-weight solution for testing React components. It provides a way to render the DOM nodes of your React components and ways to query those elements so they can be tested.

    The forthcoming tasks will guide you through using this library to test the App component, helping you to get started with testing.

    Throughout this step, Code Labs will conduct two evaluations for each of your tasks.

    info> One evaluation will test your code and provide a custom message alongside the test output, while the other will simply execute the test you've written using npm test and display Jest's output.

    Reminder: You can view the results for the evaluations in the Feedback/Checks section at the bottom of each task. Now that the component is being rendered, you will employ the getByText query to search for the "Learn Best Practices" link. You'll then store it in a constant named linkElement and assert that the link is present in the document.

  4. Challenge

    Guiding Principles

    React Testing Library strives to provide methods and utilities that promote writing tests closely mirroring real-world web page usage. According to its guiding Principles, you should prioritize your test queries to reflect user interactions. When deciding which query to use in your test, follow this order:

    Accessibility Queries: Aim for queries accessible to all users, including those using assistive technology.

    1. getByRole: Use for filtering by accessible name.
    2. getByLabelText: Ideal for form fields, mirroring user navigation.
    3. getByPlaceholderText: Use when only placeholder text is available, though labels are preferred.
    4. getByText: Useful for locating non-interactive elements, like divs or paragraphs.
    5. getByDisplayValue: Handy for accessing current form element values.

    Semantic Queries: Utilize HTML5 and ARIA compliant selectors.

    1. getByAltText: Use for elements supporting alt text.
    2. getByTitle: Use for elements that have a title attribute to provide additional information. Note its support in screen reader is inconsistent.

    For Test IDs, reserve getByTestId for cases where role or text queries are impractical or irrelevant. These adjustments will align your test more closely with actual user interactions and components.

  5. Challenge

    Queries

    In this step, you'll explore the different types of queries available in React Testing Library: 'get,' 'find,' and 'query.' These queries handle scenarios where no element is found by either throwing an error or returning a Promise and attempting again.

    The choice of query depends on your target page content, with certain queries being more suitable for specific contexts.

    info> Each query type offers both single and multiple element options. Single element queries retrieve a singular node matching the query, while multiple element queries handle scenarios where multiple nodes may match.

    Here's a quick overview of the single element queries and their corresponding multiple element options:

    • getBy...: Retrieves the matching node for a query, throwing an error if no elements match or if more than one match is found. Use getAllBy for multiple matches.
    • queryBy...: Fetches the matching node for a query, returning null if no elements match. Useful for asserting an absent element. Throws an error if more than one match is found. Use queryAllBy if acceptable.
    • findBy...: Yields a Promise that resolves when an element matching the query is found. The promise is rejected if no element is found or if more than one is found after a default timeout of 1000ms. Use findAllBy for multiple elements.

    In previous tasks, you've used the getBy query type when selecting the DOM node. Now, you'll explore the queryBy method to test that an element is not in the page. Take the time to familiarize yourself with the two components rendered by this simple app so you can write your next test.

    1. Open your src/app.tsx file and locate the BestPractices component being rendered as a child component.

    2. Now, open your src/best-practices.tsx file and find the logic where an <h2> element renders the text "React Testing Library Best Practices" when the user clicks the See more button in the App component, but not before that.

    Now that you understand there's an element within the BestPractices component that's only displayed under certain conditions, you are ready to do the next task where you'll use the queryBy type to confirm that the <h2> element isn't present. Good job using the queryByText method! Next, you will be working with the findBy query type.

    The findBy methods are good options to use when you expect an element to appear, but the change to the DOM might not happen immediately.

    info> The findBy query, alongside the waitFor and waitForElementToBeRemoved methods, are React Testing Library's utilities provided for dealing with asynchronous code, so be sure to use await or .then when calling them.

    Advance to the next step, where you'll fire a click event in your test and check for the appearance of an element located inside the BestPractices component.

  6. Challenge

    User Interaction and Mocking

    In this step, you'll harness the power of the findBy query and Jest mock to thoroughly test user interaction in your application.

    React Testing Library offers two primary methods for testing user interaction:

    • user-event Library: This companion to Testing Library excels at faithfully replicating user interactions by simulating the events that naturally occur in a browser. It's an invaluable tool for accurately emulating user behavior during tests.

    • fireEvent Utility: Acting as a lightweight wrapper around the browser's dispatchEvent API, fireEvent provides developers with the ability to trigger any event on any element within their tests. This grants flexibility and precise control over simulated interactions.

    For the tasks ahead, you'll have the chance to utilize both libraries in your tests. In the first task, you will write a test that verifies the presence of the <h2> element with the specified text after a button click in your App component. Jest mock functions can be used to test that a component will call its bound callback in response to a particular event.

    It's commonly used in unit tests to mock API calls or external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies.

    In the following task, you will write a simple test to check if the handleClick function is being called when the user clicks the See more button. It's important to keep in mind that Jest does not clear, reset, or restore mocks by default after each test. However, you want to use one of the methods offered by Jest to enforce that your tests are consistent and independent from each other in a way that they don't rely on a previous test to pass or fail.

    To keep your tests clean, you can follow Jest's recommendation and use one of the three methods provided by the library.

    | | clear | reset | restore | -------- | -------- | -------- | ----------| | Clears mock calls, instances, contexts and results | ✅ | ✅ | ✅ | Removes mocked return value or implementation | ❌ | ✅ | ✅ | Restores the original implementation | ❌ | ✅ | ✅

    In this final step, you have covered the essential aspects of writing unit tests for user interactions and utilizing mock functions triggered by DOM interactions.

    Throughout this code lab, you've learned to harness the power of Jest as the test runner and React Testing Library to effectively query DOM elements, ensuring the reliability and maintainability of your code base.

    To continue expanding your expertise, you should explore related courses on Pluralsight, such as Testing in React 18 and JavaScript Unit Testing with Jest. Additionally, investing time in studying the Jest and React Testing Library documentation will provide you with deeper insights and help you stay updated on best practices and advanced techniques. Although this lab has provided a strong foundation, ongoing learning is essential to mastering the art of React testing.

Carolina Powers is a Software Engineer at Pluralsight with a background in teaching and a passion for learning. When she is not working, she enjoys spending time with her family, traveling, going to the beach, being active and teaching her son a new language.

What's a lab?

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.