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

Test-Driving Redux

Redux is a predictable state container. To the uninitiated, these words mean very little. Thankfully, TDD can help us understand how to think about and implement our Redux application architecture. The tests in the chapter will help you see how Redux can be integrated into any application.

The headline benefit of Redux is the ability to share state between components in a way that provides data consistency when operating in an asynchronous browser environment. The big drawback is that you must introduce a whole bunch of plumbing and complexity into your application.

Here be dragons

For many applications, the complexity of Redux outweighs the benefits. Just because this chapter exists in this book does not mean you should be rushing out to use Redux. In fact, I hope that the code samples contained herein serve as warning enough for the complexity you will be introducing.

In this chapter, we’ll build a reducer and a saga to manage the submission...

Technical requirements

Up-front design for a reducer and a saga

In this section, we’ll do the usual thing of mapping out a rough plan of what we’re going to build.

Let’s start by looking at what the actual technical change is going to be and discuss why we’re going to do it.

We’re going to move the logic for submitting a customer—the doSave function in CustomerForm—out of the React component and into Redux. We’ll use a Redux reducer to manage the status of the operation: whether it’s currently submitting, finished, or had a validation error. We’ll use a Redux saga to perform the asynchronous operation.

Why Redux?

Given the current feature set of the application, there’s really no reason to use Redux. However, imagine that in the future, we’d like to support these features:

  • After adding a new customer, the AppointmentForm component shows the customer information just before submitting it, without having...

Test-driving a reducer

In this section, we’ll test-drive a new reducer function, and then pull out some repeated code.

A reducer is a simple function that takes an action and the current store state as input and returns a new state object as output. Let’s build that now, as follows:

  1. Create a new file (in a new directory) named test/reducers/customer.test.js. Add the following first test, which checks that if the reducer is invoked with an unknown action, our reducer should return a default state for our object. This is standard behavior for Redux reducers, so you should always start with a test like this:
    import { reducer } from "../../src/reducers/customer";
    describe("customer reducer", () => {
      it("returns a default state for an undefined existing state", () => {
        expect(reducer(undefined, {})).toEqual({
          customer: {},
          ...

Test-driving a saga

A saga is a special bit of code that uses JavaScript generator functions to manage asynchronous operations to the Redux store. Because it’s super complex, we won’t actually test the saga itself; instead, we’ll dispatch an action to the store and observe the results.

Before we get started on the saga tests, we need a new test helper function named renderWithStore.

Adding the renderWithStore test extension

Proceed as follows:

  1. At the top of test/reactTestExtensions.js, add the following new import statements:
    import { Provider } from "react-redux";
    import { storeSpy } from "expect-redux";
    import { configureStore } from "../src/store";

The expect-redux package

For that, we’ll use the expect-redux package from NPM, which has already been included in the package.json file for you—make sure to run npm install before you begin.

  1. Add a new variable, store, and initialize it...

Switching component state for Redux state

The saga and reducer are now complete and ready to be used in the CustomerForm React component. In this section, we’ll replace the use of doSave, and then as a final flourish, we’ll push our React Router navigation into the saga, removing the onSave callback from App.

Submitting a React form by dispatching a Redux action

At the start of the chapter, we looked at how the purpose of this change was essentially a transplant of CustomerForm’s doSave function into a Redux action.

With our new Redux setup, we used component state to display a submitting indicator and show any validation errors. That information is now stored within the Redux store, not component state. So, in addition to dispatching an action to replace doSave, the component also needs to read state from the store. The component state variables can be deleted.

This has a knock-on effect on our tests. Since the saga tests the failure modes, our component...

Summary

This has been a whirlwind tour of Redux and how to refactor your application to it, using TDD.

As warned in the introduction of this chapter, Redux is a complex library that introduces a lot of extra plumbing into your application. Thankfully, the testing approach is straightforward.

In the next chapter, we’ll add yet another library: Relay, the GraphQL client.

Exercise

  • Modify the customer reducer to ensure that error is reset to false when the ADD_CUSTOMER_SUCCESSFUL action occurs.

Further reading

For more information, have a look at the following sources:

  • MDN documentation on generator functions:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function*

  • Home page for the expect-redux package:

https://github.com/rradczewski/expect-redux

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