In order for us to deliver a reliable framework for others to depend on, we needed bulletproof test coverage for Searchkit. Our upcoming release, Version 0.4, now has 99% unit test coverage. We needed to make sure every release that was shipped was without regressions. Along the way, we learnt a few tricks we would like to share.

Our testing setup uses Karma, Webpack, Jasmine and a few testing utilities like Enzyme and React Test Utils. Our code and tests are written in typescript, therefore we depend on webpack’s ts-loader for typescript to ES5 transpilation. We use webpack’s null-loader for styles and file asset dependencies that our code may have.

Component Testing

Traditionally, component tests have been quite daunting and often left to the very end.

Fortunately, we have the virtual dom and great libraries such as Airbnb’s Enzyme framework to help us along. We also created a couple of small test utilities to complement Enzyme in component testing.

Sometimes we just want to assert the full output of a component in a readable way, JSX naturally helps us describe this in our app code, so why not also use it in our test code.

React provides this cool renderToStaticMarkup method which takes in JSX markup and returns static html. We use this method in our tests to verify the component’s output. We also use a printPrettyHtml so we don’t need to write the test JSX code ourselves, we just paste the output from the terminal.

We use Eyzyme’s simulate and query api to test user interaction, which allows us to cover both the read + action phases of our components.

Unit testing

The main tips on writing unit tests are not the unit test themselves, but making the code easy to test. We try to make Classes and functions follow the single responsibility principle and try to use Immutable Data structures wherever possible.

Searchkit’s Query + State data structures are fully immutable, and this greatly simplifies our code, we naturally converge towards pure functions with predictable input / output behaviour our unit test suite can follow suit and test input and output scenarios without worrying about side effects in our application.

E2E / Functional Testing

Unit tests are great but alone, they cannot tell us our components work on a live web browser, this is where end to end tests come in.

Our setup uses Protractor, Xenon and Jasmine. Our e2e tests are written in typescript and we use ts-node to transpile our typescript to ES5 for protractor.

For fixtures we seed an Elasticsearch instance with our example IMDB data and run the E2E specs against a small app with the example Searchkit demo.

We use Xenon, which is a page object framework for Protractor. With Xenon, there is a clean separation between test code and component specific code. We can create component operation methods on Xenon page objects to reduce duplicating code on specs. Developers can use Xenon’s page object elements without needing to have element locators in their E2E specs.

Below is an example of query E2E test using Xenon and Protractor.

Searchbox xenon component

One important step when using Protractor is to set ignoreSynchronization to true for non angular apps. Protractor synchronization waits for Angular to fully digest before proceeding and therefore tests will fail for a non-Angular page. This can be set within the Protractor config file.

Continuous Integration

Now that we have written our tests, we need to make sure that Searchkit continues with this progress and having a CI server can help manage this.

Circle CI really appealed to us, due to its quick integration in Github and with our project setup. It took a few minutes for us to configure Circle CI for Searchkit and Circle CI will run build, test and deploy every time we push new changes. Circle CI provides a page for anyone to see progress on our builds.

We use Coveralls to keep a watchful eye on our test coverage. Another free service for open source projects, Coveralls will analyse the test coverage report created by Istanbul and provide a page for anyone to see the coverage stats.

Written by Joseph McElroy and Siavash Etemadieh.