Testing React Apollo components with Intern & enzyme

The new version of react-apollo 2.1 introduces <Query/>, <Mutation/> & <Subscription/>components, with which we can move away from using HOC to connect data.

Testing Limitations of the new Query /Mutation Components

Despite react-apollo 2.1 being widely adapted, their not much documentation available on testing except the official guide , and that too has examples using jest framework.

The guide does a decent job in explaining the concepts , so here in the article I will go over my upon testing Query & Mutation components using MockedProvider using intern testing framework and enzyme.

Attempts to write test case

Consider the below example code component for explanation purpose

For testing the above code we will go ahead and write a unit test something like below :-

On running the above test we see that it fails. But why did it fail ?

As the MockedProvider mimics the ApolloProvider it first renders with a loading state and in the next event loop(nextTick) it returns the final state with data ( To understand more in detail refer this link).

When we run the test, intern test runner executes mount of MockedProvider and moves ahead to expect (assert) without waiting for MockedProvider to render with final state, therefore failing the test case.

Test Failure for Attempt 1

Intern and MockedProvider Incompatibility

All tests in intern have an async method, after calling this method, Intern will assume the test is asynchronous . More details on async method can be found here.

Using this.async the test case can be written as below.

As MockedProvider does not return a Promise, we implement a dummy function executeAsyncTestCase which returns a Promise and resolves an empty object.

this.async#callback (function) then wraps over the Promise and resolves the Deferred automatically, and we start seeing the test case is passing.

The Problem starts when we change the test case to below

expect(wrapper.find(".movie-details").length).to.equal(0);

expectation is that the test would fail, but after running the test we see that the test still passes, and we don’t see errors in the console. The test case passes because in case this.async callback throws an error we need to implement a this.async#reject function. On implementing the reject method still it was not able to catch errors which seemed to be an issue with intern test runner

Attempt 2 — Test cases passes even if it fails

Final Attempt & this worked !

Next steps to correct the test case would be to remove the this.async implementation.

Post that the test case would look something like below

In the above test case implementation to let intern know that the test case is an async we use Promise pattern . The test case gives expected results for both positive and negative test cases.

Explaining helper functions -

  1. wait function — this is a helper function which returns a promise that resolves after how many milliseconds you pass it.
  2. executeMockProviderTestCase function — this is a helper function which takes the mounted component and executes wait and post that updates the mounted component.