So you want to know what you should test when using React?

So you have been using React now for some time, and you want to know what you have to test, and If you have seen one of Brian Holt’s videos on FrontEndMaster on Introduction React and Redux. In this video, Brian says that at Netflix they do not have unit tests for their React components because they change so often. The problem with this statement is a new guy, or an inexperienced team might take this out context to say that if Netflix does not write unit tests for their React components why should we. My problem with this is these people can use this as an excuse. Also, we have to look at the capabilities here, Brian Holt is a super talented developer, and at Netflix, He is surrounded by the best of the best, so for them, it works because they are operating on another level (rockstar level lol 🎸🌟).

I come from Angular 1.5 where it was straightforward what needed to be unit tested. We wrote unit tests for controllers, components, services, directives and custom modules. The view was tested with e2e tests using protractor plus. With these you could get very impressive test coverage, one project I worked on we had 100% test code coverage. However, that was Angular 1.5 days, and we have since moved on from that to React. Like I had with Angular 1.5, I want all my React applications to have excellent test coverage.

With all the React applications I have built thus far I have focused a lot on testing, and within each app, I have been tinkering with different approaches. Moreover, I think I have found a good approach which works well for most applications including enterprise.

3 Step RCV (Redux, Container, View) Testing Approach

To demonstrate this RCV testing approach, I will be using my react-tunes-player repo. Also, for Redux I use the ducks modular pattern.

Step 1: Test Redux (RCV)

  • Redux: Test all your reducers and actions. In fact, my suggestion would be to use TDD (Test Driven Development) for this. Testing your reducers and actions has nothing to do with React, at this stage. If you are coming from Angular 1.5, you can think of this as testing some custom modules which had nothing to with Angular.
  • Note: If you are building a React application my suggestion is always to use Redux for State management. React + Redux are made for each other.

Testing an action & reducer
Note: This test below is making sure that when the setTunes() action is dispatched to the reducer, the expected state should have the tunes array set with the tunes received from setTunes().

View on GitHub: react-tunes-player-reducer.spec.js

//file-name: react-tunes-player-reducer.spec.js

  describe("set tunes", () => {
    it("should return state with tunes set when setTunes action is dispatched", function() {
      const action = setTunes(tunes());

      const actual = ReactTunesPlayerReducer(stateBefore(), action);

      const expected = {
        ...stateBefore(),
        tunes: [...tunes()]
      };

      expect(actual).toEqual(expected);
    });
});

Step 2: Test the Container (RCV)

  • Test your container. You should still use TDD (Test Driven Development) for this. Here you are testing your connected component, basically testing the glue between Redux and Your React Component. The key functions are mapStateToProps and mapDispatchToProps.

Testing mapStateToProps
Note: These tests below make sure that we have mapped state with the props we want to pass down into our view.

View on GitHub: react-tunes-player-container.spec.js

//file-name: react-tunes-player-container.spec.js
it("should mapStateToProp tunes to _tunes", function() {
    expect(wrapper.node.props._tunes).toEqual(
      initialState.reactTunesPlayerReducer.tunes
    );
  });

  it("should mapStateToProp current to _current", function() {
    expect(wrapper.node.props._current).toEqual(
      initialState.reactTunesPlayerReducer.current
    );
  });

  it("should mapStateToProp player to _player", function() {
    expect(wrapper.node.props._player).toEqual(
      initialState.reactTunesPlayerReducer.player
    );
});

Testing mapDispatchToProps
Note: These tests below make sure that we have mapped our actions to the props we want to pass down into our view.

View on GitHub: react-tunes-player-container.spec.js

//file-name: react-tunes-player-container.spec.js

it("should mapDispatchToProps setTunes", function() {
    expect(wrapper.node.props.setNextTune()).toEqual(setNextTune());
  });

  it("should mapDispatchToProps setPreviousTune", function() {
    expect(wrapper.node.props.setPreviousTune()).toEqual(setPreviousTune());
  });

  it("should mapDispatchToProps setTunes", function() {
    expect(wrapper.node.props.setTunes()).toEqual(setTunes());
  });

  it("should mapDispatchToProps setCurrentTune", function() {
    expect(wrapper.node.props.setCurrentTune()).toEqual(setCurrentTune());
  });

  it("should mapDispatchToProps playCurrentTune", function() {
    expect(wrapper.node.props.playCurrentTune()).toEqual(playCurrentTune());
  });

  it("should mapDispatchToProps pauseCurrentTune", function() {
    expect(wrapper.node.props.pauseCurrentTune()).toEqual(pauseCurrentTune());
});

Step 3: Testing the View (RCV)
Test your view. This is the controversial part which guys like Brian Holt and many others have said not to waste your time testing this is because the view always changes. My suggestion is the following:

  • Newbie – New to React: Test everything in your view
  • Inexperienced Team – New to React: Test everything in your view
  • Everyone else: Depending what your component does:
    • Test all component methods like componentDidMount, componentWillReceiveProps and etc..
    • If your component renders differently according to state, test those different render states

Testing different render states, plus componentDidMount and componentWillReceiveProps

View on GitHub: react-tunes-player-view.spec.js

//file-name: react-tunes-player-view.spec.js

describe("when not rendered with tunes", () => {
    beforeEach(function() {
      wrapper = shallow();
    });

    it("should render React Tune Player View with warning message displayed", function() {
      expect(wrapper.contains("Warning! No tunes loaded in player.")).toBe(
        true
      );
    });

    describe("componentDidMount", () => {
      it("should NOT add event listener when tunes props is supplied", function() {
        spyOn(
          ReactTunesPlayerView.prototype,
          "componentDidMount"
        ).and.callThrough();

        wrapper = mount();

        expect(
          ReactTunesPlayerView.prototype.componentDidMount
        ).toHaveBeenCalledTimes(1);
        expect(wrapper.find(".warning-wrapper").length).toEqual(1);
      });
    });

    describe("componentWillReceiveProps", () => {
      it("should NOT call playCurrentTune when isPlaying is true", function() {
        wrapper = mount(
          
        );

        wrapper
          .instance()
          .componentWillReceiveProps({ _player: { isPlaying: true } });
        expect(playCurrentTuneMockFunc).toHaveBeenCalledTimes(0);
      });

      it("should NOT call pauseCurrentTuneMockFunc when isPlaying is false", function() {
        wrapper = mount(
          
        );

        wrapper
          .instance()
          .componentWillReceiveProps({ _player: { isPlaying: false } });
        expect(pauseCurrentTuneMockFunc).toHaveBeenCalledTimes(0);
      });
    });
});

So if you are a Newbie or Inexperienced Team just test everything you will learn a lot about react, redux, enzyme, jest, shallow rendering and jsdom. However if you are NOT going to write tests for your view, the minimum you may check is if the React component still renders after making changes, and this can be done with enzyme using shallow rendering.

Minimum view tests – check if component renders without crashing

import React from 'react';
import { shallow } from 'enzyme';
import App from './App';

it('renders without crashing', () => {
  shallow(<App />);
});

Just like you, I am also always learning and getting better, so the above is my take at this moment in time. I will continue to tweak, experiment and improve. If there’s anything that you come across or a better method, please will you kindly share it? I am open to improvements.

@Brian Holt, thanks man for everything, it is because of you that I know React and Redux, thank you 🙂
Also shout-out to FrontEndMaster,
Also shout-out Anthony Accomazzo, Ari Lerner, Clay Allsopp, David Guttman, Tyler McGinnis, and Nate Murray these are guys that wrote Full Stack React.
Also shout-out to the creators of these excellent tools we use react, redux, enzyme, jest, create-react-app and many more.
Also shout-out to the guys that have written articles on testing React:

Alfa Romeo Reliability Myth Has Been BUSTED!

This is a photo of my Alfa Romeo Giulietta Quadrifoglio (QV), I bought this car brand new in June 2011. It had zero kilometres on the clock, plus I was and will always be the single owner. My Alfa Romeo Giulietta Quadrifoglio (QV) has just reached 200 000KM on the clock. Furthermore, it will be my QV’s 8th birthday. You might look at kilometres driven and remark at how many kilometres I have raked up in 8 years, moreover they were eight incredible years of driving. Every opportunity I got to drive, I did. I have been all over the Gauteng province, including to KwaZulu Natal the land of my Zulu people. What I love about my Alfa Romeo Giulietta Quadrifoglio is that every kilometre that has been driven has always been exciting there has never been a dull moment or a time when I had enough.

My Alfa Romeo Giulietta Quadrifoglio
My Alfa Romeo Giulietta Quadrifoglio

My Alfa Romeo Giulietta Quadrifoglio (QV) still surprises me with every acceleration. Moreover, the handling has always been exciting. I am not sure what the Italians do when they create these fantastic sports cars. You can feel the passion and love that has been transferred to all their sports cars. This is my 1st Alfa Romeo, and I love it.

Before my Alfa Romeo, I had an Audi A4 B8 2TDi the car was good, well built, plus had an excellent sound system. After three years with it, I had enough. I was looking for something else, I was ready for another car. When I had the Audi, there was not much excitement after one year of owning it. The novelty had worn off. There are only two things I missed about the Audi, the sound system and after-sales service received after buying the car. One other thing which was unique about Audi South Africa was they sent me a gift after purchasing my Audi. I’m not sure about other countries, but I think this is where Alfa Romeo South Africa can learn a thing or two about after-sales service from other luxury brands. Or though I don’t want to dive too deep into this, also let me make it clear, I’m referring to the craftsmanship regarding servicing their cars, and I am relating to my experience on how well they managed the perception and their communication with their clients. Don’t get me wrong Audi’s are not perfect, they do break. Also, they’re after-sales people also do make mistakes. I can account two experiences that I had which backs this statement up:

  1. My Audi service representative told me that my Audi had break sensors; therefore, it will indicate to me when the breaks needed changing; however, this was not case plus this ended up damaging the brake disks.
  2. My Audi broke down in traffic, luckily I was still able to drive.
    However, these two experiences above were managed very well by Audi when the car was booked in for service.

Anyway, I digress from the topic, coming to back to the primary subject which is my Alfa Romeo Giulietta QV has made it to 200 000KM, therefore crushing the fears of “reliability”. Everyone who knew I had an Alfa Romeo, would congratulate me on my Italian car, then crack some clever joke like “at least your car will look pretty on the side of the road after it breaks down”. Now you can imagine the confidence this gave me in the start, knowing that someday I might be stuck on the side of the road with a broken car. At first, I brushed it off by saying it’s okay it’s still under warranty therefore if I do get stuck, the warranty will cover it. Moreover, do remember that this is my first Alfa Romeo. So it’s like these people (Alfa Romeo haters) were saying I’d never make it past 100 000KM. The fact that I have made it to 200 000KM proves to me that Alfa Romeo Reliability myth has been BUSTED.

My Alfa Romeo Giulietta Quadrifoglio
My Alfa Romeo Giulietta Quadrifoglio

To summarise, this is my first Alfa Romeo that I have owned. Moreover, I have been pleased with what my Alfa Romeo has been able to achieve. Yes, there were ups and downs, however, I can call recall more fantastic moments though. Every morning I am greeted with this beautiful car. Furthermore, it is at that moment I know I am about to have fun driving to work. Bellissimo, Forza Alfa Romeo.

Technical Details:
Name: Alfa Romeo Giulietta Quadrifoglio
Vehicle Mechanical Warranty: 5 years / 150 000KM
Service Plan: 6 years / 105 000KM
Year: 2011
Power: 173kW / 232Bhp