Running tests against code meant for production has long been a best practice. It provides additional security for the code that's already written, and prevents accidental regressions in the future. Components utilizing
apollo-angular, the Angular implementation of Apollo Client, are no exception.
apollo-angular has a lot going on under the hood, the library provides multiple tools for testing that simplify those abstractions, and allows complete focus on the component logic.
This guide will explain step-by-step how to test
apollo-angular code. The following examples use the Jest testing framework, but most concepts should be reusable with other libraries.
Consider the component below, which makes a basic query, and displays its results:
apollo-angular/testing module exports a
ApolloTestingModule module and
ApolloTestingController service which simplifies the testing of Angular components by mocking calls to the GraphQL endpoint. This allows the tests to be run in isolation and provides consistent results on every run by removing the dependence on remote data.
By using this
ApolloTestingController service, it's possible to specify the exact results that should be returned for a certain query.
Here's an example of a test for the above
Dog component using
ApolloTestingController, which shows how to define the mocked response for
But first, we need to set everything up.
As you can see, it feels a lot like
HttpTestingController, it has pretty much the same API so nothing new for you!
We recommend you to read "Testing HTTP requests" chapter of Angular docs.
In this configuration, we get mock
Apollo service by importing
ApolloTestingModule and we make sure there is no open operations thanks to
ApolloTestingController is similar to
HttpTestingController we won't get into details of unit testing components, we're going to focus mostly on Apollo service and explaining the API of the testing utility service.
Expecting and answering operations
With all that we can write a test that expects an operation to occur and provides a mock response.
When it receives a
GET_DOG_QUERY with matching
variables, it returns the corresponding object that has been flushed.
expectOne should use a function to check the query definitions and return a boolean:
You can do a lot more with
expectOne than showed in the example.
Important thing, it accepts two arguments. First is different for different use cases, the second one stays always the same, it's a string with a description of your assertion. In case of failing assertion, the error is thrown with an error message including the given description.
Let's explore all those possible cases
- you can match an operation by its name, simply by passing a string as a first argument.
- by passing the whole Operation object the expectOne method compares: operation's name, variables, document and extensions.
- the first argument can also be a function that provides an Operation object and expect a boolean in return
- or passing a GraphQL Document
It accepts the same arguments as
expectOne but it's a negation of it.
Search for operations that match the given parameters, without any expectations.
Verify that no unmatched operations are outstanding. If any operations are outstanding, fail with an error message indicating which operations were not handled.
It's an object returned by
TestOperation has three available methods:
flush(result: ExecutionResult | ApolloError): void- it accepts a result object or ApolloError instance
networkError(error: Error): void- to flush an operation with a network error
graphqlErrors(errors: GraphQLError): void- to flush an operation with graphql errors
Using named clients
The process is pretty much the same as using a default client but the setup is a bit different:
Now you're able to test named clients.
If you want to check which client was called to perform a graphql operation:
Using a custom cache
By default, every ApolloCache is created with these options:
If you would like to change it in the default client, do the following:
For named clients:
For the sake of simplicity, we didn't show how to test loading state, errors and so on but it's similar to what we showed above.
Testing UI components isn't a simple issue, but hopefully these tools will create confidence when testing components that are dependent on data.