Golden Way to Traverse React Components on Shallow Rendering Approach

On my last post, I’ve talked about shallow rendering to test React components. This post is the sequel of that post since I’ll also talk about testing React components. The shallow rendering that I’ve done on the last post is using the help from createRenderer function from React Addons Test Utils. Unfortunately, (until now) there are no function for traversing React element trees neatly just by using the help from React Addons Test Utils. If you want to check an element somewhere deep in the component tree, you will end up in a long chaining of props.children.props.children… which it also happened to me and I think it’s not elegant.

Quoted from this page,

Airbnb has released a testing utility called Enzyme, which makes it easy to assert, manipulate, and traverse your React Components’ output. If you’re deciding on a unit testing utility to use together with Jest, or any other test runner, it’s worth checking out: http://airbnb.io/enzyme/

Actually I ever read that note before but I didn’t really understand how Enzyme can make it easy. Therefore, I decided to not use Enzyme since I didn’t feel any need to use it. Then I faced a problem which I solved it by using shallow rendering. But, by using shallow rendering I faced a new problem (actually), which was the ugly chaining of props.children.props.children… I thought could I write this shallow rendering test in a more elegant way?

First let me tell you the structure of React component that I want to test,

<div className="card">
  <div className="row">
    <div className="col col--9">
      <h2>{this.props.name}</h2>
      <p className="card__text">
        Start: {this.props.start_date}
      </p>
      <p className="card__text">
        End: {this.props.end_date}
      </p>
      <p className="card__list-link">
        <a href={this.props.phabricator_url} target="_blank" rel="noopener noreferrer">
          Phabricator
        </a>
      </p>
    </div>
    <div className="col col--3 u__valign--middle u__position--relative">
      <Doughnut data={data} options={options} width={120} height={120} />
      <div className="doughnut__legend">
        {completedPercentage}%
      </div>
    </div>
  </div>
</div>

Then this is the block code to test the displayed percentage that I wrote before,

test('renders a percentage project correctly', () => {
  const shallowRenderer = TestUtils.createRenderer();
  shallowRenderer.render(React.createElement(ProjectCard, project2));
  const projectCard = shallowRenderer.getRenderOutput();
  const row = projectCard.props.children;
  const secondCol = row.props.children[1];
  const percentage = secondCol.props.children[1];

  expect(percentage.props.children[0]).toEqual(project2.percentage.toFixed(2));
});

Did you just see a chaining of props.children which I repeated more than once? Yep, I did that since I didn’t know how to avoid it before. I want to access an element which contains percentage text, but since it’s located deep inside I have to access the children of parent elements layer by layer. I really wanted to avoid writing that chaining, but I didn’t came with any solution before. But now, I don’t have to be worry anymore. I’ll show you how to avoid the ugly chaining of props.children.props.children… with the help from Enzyme! I refactored the code then it becomes like this:

test('renders a percentage project correctly', () => {
  const projectCard = shallow(<ProjectCard
    name={project2.name}
    start_date={project2.start_date}
    end_date={project2.end_date}
    percentage={project2.percentage}
  />);
  expect(projectCard.find('.doughnut__legend').text()).toEqual(`${project2.percentage.toFixed(2)}%`);
});

Don’t forget to import the shallow from Enzyme in the top of file,

import { shallow } from 'enzyme';

Now, Do you see any chaining of props.children? Yep, instead of accessing the element layer by layer, Enzyme allows you to access a deep inside element using selector. From the documentation, it said that you can access the element using this four valid selectors, which are:

  • Class syntax, .foo, .foo-bar, etc.
  • Tag syntax, input, div, span, etc.
  • Id syntax, #foo, #foo-bar, etc.
  • Prop syntax, [htmlFor="foo"], [bar], [baz=1], etc.

For further explanation about the selector you can check on the documentation. On my code above, I used class syntax for the selector which is .doughnut__legend.

Few Thing about Enzyme

I found an article which explains clearly about Enzyme. From that article it said that:

Enzyme is a library that wraps packages like React TestUtils, JSDOM and CheerIO to create a simpler interface for writing unit tests. React TestUtils has methods to render a react component into a document and simulate an event. JSDOM is a JavaScript implementation of the DOM (Document object model). DOM represents the tree structure of UI components. CheerIO implements a subset of jQuery core and is used to query the DOM. Enzyme wraps these libraries and provides a simple and intuitive API for unit testing.

So, actually when I use Enzyme, I also use React TestUtils which I used before resulting the ugly chaining. But Enzyme wraps those functions, so I can use them in neatly ways.

Yep, I think this is enough for this time. Now, I can write the test using shallow rendering approach elegantly by following this golden way haha. See you in the next post!

Side Note

Maybe this is not really a golden way, but I think this is the best solution to traverse React components until this far.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s