This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

React Testing: Reusing test boilerplate

2:21 React lesson by

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.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

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.

Avatar
Andreas
function renderLikeCounter(isActive) {
      const renderer = TestUtils.createRenderer();
      renderer.render(<LikeCounter count={5} isActive={isActive} />);
      return renderer.getRenderOutput().props.className.includes('LikeCounter--active');
    }

I am wondering about how this code actually works: we have a function param = isActive and a prop name isActive. How does it figure that out? In Java this would only work with this.isActive = isActive.

Avatar
Trevor

Hi Andreas,

In this lesson, we are using the JSX syntax for our component, which is an XML-like syntax supported by React. JSX "...lets you create JavaScript objects using HTML syntax", so when we use isActive={isActive} on our <LikeCounter /> JSX component, under the hood it is just passing a JavaScript object that looks like {isActive: true}.

To learn more about how JSX works under the hood, the React JSX docs may be helpful: https://facebook.github.io/react/docs/displaying-data.html

Additionally, the following article might be helpful to better explain how React converts JSX into component instances: https://facebook.github.io/react/blog/2015/12/18/react-components-elements-and-instances.html

In reply to Andreas
Avatar
Jernej

Just personal preference (or suggestion): I returned className property from function and for class name inclusion I use expect(<list>).toInclude(<item>) (or toExclude). :)

Avatar
Zachary Klein

This video mostly makes up for what was lacking in the first one. :) But I think that this video would stand well on it's own, even without the preceding one. Just my two credits.

Avatar
Qualitype GmbH

@trevordmiller
I'm interested in seeing how would I test a stateless component that just receives methods? Would I have to recreate those methods to be able to instantiate the component?

Sorry, new to the testing. Thanks in the advance :)

import React from 'react';

const TodoAddNew = ({value, handleNewTodoInputChange}) => {
    return (
        <footer className="content-container">
            <label htmlFor="newTodo">So what's next?:</label>

            <input id="newTodo" type="text"
                   name="newTodoInput"
                   autoComplete="off"
                   spellCheck="false"
                   className="form-control"
                   placeholder="take out the trash 😢"
                   value={ value }
                   onChange={ handleNewTodoInputChange }/>

            <button className="btn btn-submit" type="submit">Submit</button>
        </footer>
    );
};

TodoAddNew.propTypes = {
    value: React.PropTypes.string,
    appendField: React.PropTypes.func.isRequired,
    handleNewTodoInputChange: React.PropTypes.func.isRequired
};

export default TodoAddNew;

Here we have two tests created with the shallow renderer, and we can see that there's a lot of duplication between the two. The only two unique pieces are that the prop type changes here from true to false, and the expected value changes from true to false here.

There are a few different ways we could go about cleaning up these tests, but what I'm going to do is go up above the test and create a new describe block that will wrap both of them. I'll call this group "is active" since we're testing the activity of this like counter component.

So I will indent my two tests, and then I will go down and close off my describe block. It's not necessary to wrap your test like this, but I find that it's helpful, especially when we're going to be creating a function to share functionality between tests, to group them together inside of their own describe block.

Now I'm going to remove all of this duplicate content from the second test so that all we have is the assertion at the bottom. Next I'm going to cut this duplicate piece from the first test. We'll place that in its own factory function. So I'm going to say, "function render light counter," and inside of this we'll paste our contents that we cut from the test.

Now let's make this function usable by both tests. What I'll do is we need to have a parameter for the "is active" state, so I'm going to pass in "is active." Then I'm going to use that argument. Now I'm going to remove line 14, because we don't need this assertion piece anymore. We'll do that inside of our test.

Now instead of creating this actual variable, I'm going to return the [inaudible 1:44] here. Now I can use this function inside of my test, so I'm going to replace this actual value with "render light counter," and we'll pass in true as our "is active" prop. Now our expected value is also going to be true.

Let's do the same thing with our second test. I'm going to change my actual value to be "render like counter," and this time we'll pass in false. When we do that, we're going to expect to get false back.

As I mentioned, there are many different ways that you can do this. The main idea, the principle behind it, is to take pieces that are repetitive in your test and to pull them out into reusable parts.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?