Testing React and React Native

Unit testing

We use Mocha for testing React apps, Chai for assertions and Sinon.js for mocking.

All services and utilities should be tested. They are straight forward to test with mocha because they are functions most of the time.

It’s important to test Redux reducers and async actions creators. Simple action creators are usually tested when testing reducers.

Component testing

In order to make component testing easier, we use Enzyme. Enzyme is a JavaScript Testing utility for React that makes it easier to assert, manipulate, and traverse React Components. Enzyme provides shallow rendering functionality which allows rendering only the component under test. Dependent components are not rendered.

Automated acceptance testing

Acceptance tests that run on a browser, a simulator or a real device are slow and brittle. For these reasons, we tend to keep them to the minimum. We only test the main flows of the app.

Web

See Rails Feature tests or Node.js Feature tests depending on which environment is used for back-end.

Mobile

We use Calabash for React Native apps testing. Main points over other testing frameworks are that it’s actively maintained, works without issues on both Android and iOS.

Calabash setup

Calabash setup is not trivial, but there are lots of resources that help to make it work:

  • Check x-platform-example for information about how to reuse cucumber features for Android and iOS runtimes.
  • Check iOS and Android links about setting up Calabash.
  • React Native does not allow easily adding new configurations for iOS. See this tutorial.

Writing Calabash tests

Calabash uses Cucumber framework for defining features:

Feature: TODO-app
  Scenario: Add-TODO
    Given I'm in TODO-app
    And I click Add TODO
    Then I fill title with "My first TODO"
    And I fill text with "My first TODO description"
    And I click Save
    Then I should see "My first TODO"

Structure

Unit and component tests

To make it easier to find relevant tests and make imports shorter, we co-locate test files with the code being tested. We add *.spec.js to the filename and place test files in spec directory in the same folder as the code which is being tested.

app/
└── components
    ├── MessageInput.js
    └── spec
        └── MessageInput.spec.js

Automated acceptance tests

We place tests into features directory in app root. features directory also contains iOS and Android support files, common helpers and step definitions:

features/
├── android
│   ├── step_definitions
│   │   └── steps.rb
│   └── support
├── helpers
│   └── steps.rb
├── ios
│   ├── step_definitions
│   │   └── steps.rb
│   └── support
├── first.feature
├── second.feature
└── step_definitions
    └── media_editor.rb