How to test a React app using capybara-webkit

I have been using the capybara-webkit gem for a while now since I first tried it out after making the switch from Capybara + Selenium.

Using capybara-webkit speeds up my Selenium tests due to its headless nature, and it's very straightforward. However, I had some trouble testing a Rails based React app.

In this post, I will explain how I worked around the issues that came up when trying to use capybara-webkit with React.

capybara-webkit depends on Qt, which you can install on OSX using Homebrew. When running the tests using capybara-webkit with Qt 4.8, I noticed nothing was getting rendered. To debug this problem, I used capybara-webkit's debug mode, which spits out problems you would usually see in the Chrome console. To enable it:

Capybara::Webkit.configure do |config|
  # Enable debug mode. Prints a log of everything the driver is doing.
  config.debug = true

When the test runs, you'll get a log of every request/response and JS errors that occurred during the test. One of the errors I got was:

ReferenceError: Can't find variable: React

After some googling, I found this issue. Because I was using Qt 4.8, I needed es5-shim on my vendor/assets/javascripts directory, and include it on the manifest before including React, like so:

//= require jquery
//= require jquery_ujs
//= require es5-shim
//= require react
//= require react_ujs

This happens because Qt 4.8's QtWebKit doesn't support most of the ES5 standard. As an alternative to es5-shim, you can upgrade to a newer version of Qt, like 5.5, which does support some of the newer Javascript features.

After upgrading to Qt 5.5 and re-installing capybara-webkit, you can try getting rid of es5-shim from your pipeline, and your tests should pass.

If you are using any of the ES6 features, you'll notice that your tests will fail even using Qt 5.5, because ES6 is not yet supported by Qt 5.5.

When using Object.assign for merging objects to pass to my React state, I was getting this error:

TypeError: undefined is not a constructor (evaluating 'Object.assign(...)') ...

To fix it, I used the polyfill provided by Mozilla in their MDN documentation for Object.assign. But if you prefer, you can include the whole es6-shim library and not worry about including each individual polyfill.

After all this, my tests finally passed!

Disclaimer: I used the react-rails gem. If you are already using Webpack in your Rails app, using babel-loader or similar plugins to allow transpiling of ES6 would make these problems go away.

Have you had any problems getting your React integration tests running? Let me know in the comments section below.