The definition of "legacy code" can be described simply as "code that doesn't have tests." Code you just wrote, 5 minutes ago? Legacy code. Code that can't be refactored, but only changed.
How do we prevent the mountain of legacy code that most projects become?
A solid testing strategy.
React apps are no different, and can be tested simply if you know some core principles.
In this course we will take a look at testing React applications. From getting setup and running tests, all the way through testing Redux enabled React applications.
To write tests for our React code, we need to first install some libraries for running tests and writing assertions. In this lesson we walk through setting up Mocha as our test runner and
expect as our assertion library. We will also set up some React and JSX specific test tools (React Test Utils) to make writing our tests easier.
NOTE: There are many alternatives to Mocha, expect, and the other test tools we use in this course. Although we use these specific tools and libraries, the testing principles apply to all other tools.
In this lesson, we walk through how to setup our tests and run them. We write a quick empty first test and assertion, so we can run the tests. Using Mocha, we can do this manually each time with the Mocha CLI. We can also automate this using task runner features from tools like Grunt, Gulp, Webpack, or npm scripts. In this course, we will use the common
When writing tests for our React code, it is helpful to pull out any functionality that doesn't have to do with our UI components into separate modules, so that they can be tested separately. In this lesson, we will take a look at a React component and how we can pull out some of its generic utility logic into a separate module. We will then write some tests for that module.
In this lesson, we walk through how to use one of React's Test Utilities (from the
react-addons-test-utils package) called "Shallow Rendering". This lets us render our React component one level deep - without a DOM - so that we can write tests for it. It works kind of like ReactDOM.render, where the shallow renderer is a temporary place to "hold" your rendered component so that you can assert things about its output. Tests written using the shallow renderer are great for stateless or "dumb" components that simply have their props passed to them from a parent container or "smart" component. These shallow renderer tests work especially well with stateless function components. They also work well for "unit" tests where you want to make sure your code works in isolation.
NOTE: The React team has recommended composing the majority of your apps using these stateless "dumb" components, so the majority of lessons in this course will focus on writing simple unit tests for these stateless components using Shallow Rendering. If you also want to write tests for the stateful components that are tied to different components and state and can't be tested in isolation, you may want to look at using a DOM (with something like Karma or jsdom) and React's other test utilities like renderIntoDocument and Simulate. However, I've found that it is helpful to try to compose most of your project with simple, isolated, stateless or "pure" components that can be unit tested with Shallow Rendering, and then wrap these components with a few stateful or "impure" components that you can either not worry about testing (what I do most of the time because it is difficult to test stateful components), or write separate integration and functional tests for them using different tools.
When writing React component tests, it can be hard to decipher the error diffs of broken tests, since they are just the final objects that React uses under the hood. There are some nice libraries that let you extend your assertion library to show JSX diffs; in this lesson we will wire up one of these libraries to show how to debug JSX error diffs from your React tests. We will also show how narrowing down what you are testing helps to make the test error diffs easier to deal with.
NOTE: This lesson uses the
expect-jsx package, but there are other options available for both expect and other assertion libraries.
When you render a component with the Shallow Renderer, you have access to the underlying object. We can write lots of useful tests to check that our components are working as expected. In this lesson, we will use the
type property on the shallow rendered component to make sure that the root element is what we expect it to be.
The React Shallow Renderer test utility lets us inspect the output of a component one level deep. In this lesson, we will examine the rendered output of props, specifically the
className prop. We will then use the ES2015
String.includes() method to check that our rendered className includes what we expect.
Setting up a shallow renderer for each test can be redundant, especially when trying to write similar tests that have slight tweaks. In this lesson, we go over how you can reduce some of the overlapping code so that each test only contains the unique pieces of the test.
When testing React components, we often want to make sure the rendered output of the component matches what we expect. With the React Shallow Renderer, we can check the entire rendered output of a component, the
children prop, or a subset of the
children prop. We can also use 3rd party libraries to check that this element tree includes a specific piece. In this lesson we will walk through examples of each.
When using Redux, we can test that our application state changes are working by testing that dispatching actions to the store creates our expected output. In this lesson we will run a few realistic actions back to back (as if the user is using the app) and then test that the state tree looks as we expect it to. These types of tests that ensure all of your redux logic is working as expected give you a lot of value for not too much effort (they test your entire app's state in one big swoop). You may also find it useful to add more granular/individual tests for your reducers and/or actions, which we will cover in other lessons in this course.
NOTE: This lesson assumes you have used Redux. If you are new to Redux, it is recommended that you first watch the Getting Started With Redux course.