React testing with shallow rendering and skin-deep

Earlier I wrote an article on React testing with Mocha where we used jsdom to provide a mocked DOM and proxyquire to mock our dependencies. This was all well and good at the time, but the mocked DOM, just like Jest tests, slows down testing after a while.

In React 0.13, shallow rendering was introduced. It does not render nor instantiate child components AND it does not require a DOM. Seems perfect!

After playing with it I found that we could now longer use React's test utilities to find elements. This is where skin-deep comes in. The documentation is nonexistent, but the tests are good and descriptive so it is easy to get started with.

If you want to follow along, grab the code.

If you want to get started in your own project, start by installing skin-deep

npm install skin-deep --save-dev

If we create an example with a list of Posts it could look something like this

var React = require('react');  
var Post = require('./Post');

var Posts = React.createClass({  
  _createPost: function () {
    return 'Post created';
  },

  _renderPosts: function () {
    var posts = [
      {
        title: 'Testing'
      },
      {
        title: 'Some'
      },
      {
        title: 1234
      }
    ];

    return posts.map((x, i) => {
      return (
        <Post
          {...post}
          key={'post' + i} />
      );
    })
  },

  render: function() {
    return (
      <div className="posts">
        <h1 className="posts__title">Post title</h1>
        {this._renderPosts()}
      </div>
    );
  }

});

module.exports = Posts;  

Now lets dive into some testing using skin-deep! First we have to set up the shallow rendering of our component.

var vdom, instance, tree;

beforeEach(function () {  
  tree = sd.shallowRender(
    <Posts />
  );

  instance = tree.getMountedInstance();
  vdom = tree.getRenderOutput();
});

Here vdom is the shallow rendered component and instance is where we access any functions and state of our component.

To test if the component rendered with a correct class name we write

it('should render with a correct class name', function () {  
  expect(vdom.props.className).to.eql('posts');
});

This is still very much like shallow rendering from React and not digging into the power of skin-deep. So what if we wanted to get the text of the H1?

it('should have a list title', function () {  
  expect(tree.textIn('.posts__title')).to.eql('Post title');
});

It is that easy.

If we want to test the _createPost function we use the instance

it('should return that a post has been created', function () {  
  expect(instance._createPost()).to.eql('Post created');
});

This is just a basic start to shallow rendering and I'll refer to the skin-deep tests for further details of the API. The feature is still experimental, but it is the recommended way and will probably be expanded in the future.

After writing some more tests we can see that it is super fast. 11 ms for four tests compared to 54 ms for two tests with the previous way using jsdom. When this gets scaled to a few hundred tests, the difference will be substantial.

mocha run

comments powered by Disqus