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.
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.
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
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
Final Attempt & this worked !
Next steps to correct the test case would be to remove the
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 -
wait function— this is a helper function which returns a promise that resolves after how many milliseconds you pass it.
executeMockProviderTestCase function— this is a helper function which takes the mounted component and executes wait and post that updates the mounted component.