Don’t Waste Time While Testing: Level Up With GraphQL and Apollo

Stephen Grable
Broadlume Product Development
6 min readMay 8, 2019

--

“Quality is never an accident; it is always the result of intelligent effort.” — John Ruskin

In this blog post, we will cover an approach to speeding up development cycles and saving you time by streamlining your testing infrastructure using GraphQL and Apollo. We’ll utilize various tools and our GraphQL type schema to remove some of tedious work involved in writing a component test.

The goal here is to make it easy for engineers working on the frontend to quickly test components by using Apollo and GraphQL in an effort to expand test coverage. In doing this, we will improve the overarching quality of our codebase.

A Primer On GraphQL

GraphQL, for those who aren’t familiar, is a fairly new approach to building scalable and maintainable APIs for software applications. There’s a lot of reasons to love GraphQL, such as:

  • A single, flexible endpoint that evolves as your data grows.
  • An infrastructure that allows frontend and backend teams to work independently at scale. Teams don’t need to rely on each other for custom endpoints for each new data requirement (typical in a RESTful application workflow).
  • A Data Graph that describes your queryable data so you can decouple your query layer from your application and service multiple platforms with ease.

As you can tell, GraphQL really focuses on improving the day-to-day software engineering workflow and we, of course, can’t mention workflows without mentioning testing.

At AdHawk, we prioritize testing and strong typing (yes, we use TypeScript) because we believe quality code and expansive test coverage enables our teams to move faster. In our journey implementing GraphQL, we found that testing React components using GraphQL was a tedious task and we started searching for a better process.

How We Used to Test with GraphQL and Apollo

The old way of doing things…

First, let me show you how we used to test these React/GraphQL components:

*Warning: this file is pretty large. Stick around to see how we refactor it in the examples below.

Per the warning before this code snippet, this file is quite large but in reality there is not much going on here. The majority of this test file is just setup to allow us to test our React component. The actual test block we care about is only about 4 lines of code. Before we jump into the refactor, let’s walk through everything this file is doing and why.

At the top, you can see our query for getting “nearby stores”. We won’t be concerned with how the backend implements this functionality, but we will use this query to specify what type of response our Apollo MockedProvider will return.

Continuing down the file, you will see an async function we have defined as mountMockedProvider. This helper function creates a wrapper around your React component and mocks out the ApolloClient for your test environment. This enables you to run tests without a server and creates an isolated environment for you to verify rendering logic.

This mountMockedProvider function is asynchronous because we need to wait for Apollo’s MockedProvider to respond with the data we have mocked out to then populate our component’s state. We also use Enzyme’s update() function to force a re-render because the internal state of our component is reliant on an external source (i.e., Apollo’s MockedProvider).

Now the bulk of our test file lives in the mocks variable assignment. This is one of the most tedious parts of testing GraphQL-reliant React components. The reason for this is that you must write the mock data exactly as you’ve defined it in your query and it must match the typing assignments in your application schema.

Below we will look at ways to automatically generate these mock data objects.

What Our Tests Look Like After Mocking Query Responses

Now here’s a look at what our tests will look like after implementing various tools to have our application schema assist us in generating these mock data objects automatically:

Above we’ve created a neat helper function, called mockedQueryResponse, that will assist us in generating fake data in the correct type and format that our component expects. This new function has cut our test file almost in half and as a result has made our test much more readable to other engineers.

Let’s dig into what that mockQueryResponse function is doing in the background.

We’ll start with the tools being used to make this all possible:

First, we import our generated application data schema, which here we call the ApplicationSchema. We will use this type file, which describes our app’s queryable data, in the imported tools below.

One of the first imports we see is a package called graphql. According to their docs, “this package provides two important capabilities: building a type schema, and serving queries against that type schema.” In this file, we will be using graphql to serve queries against our app’s type schema.

Next up is our various graphql-tools imports. These tools will give us fine-grained control over mocking out our GraphQL API and is the crux of this mocking package we are about to implement below.

Now, the fun part. We take everything we set up above and implement it into our main helper function:

As you can see, this function’s main task is creating the result value in our return object, which will be the data that will populate our component.

This function accepts 3 arguments: the query being mocked, any variables the query requires, and an optional customDataResult. This will override the generated result object to give engineers the ability to write custom responses to test various edge cases.

In this function, we use the existence of variables to determine how to generate our result value because queries accepting variables need to be handled separately from those which do not.

One quick caveat, there are a few advanced cases that this function does not handle, for example the use of fragments within our queries. We will skip that case for simplicity but it is helpful to know that those situations require a more advanced setup than what is implemented here.

Looking back at the file, the last unfamiliar API we see is the use of server.query(). This server variable is defined in our setup by the return value of Apollo’s mockServer. This function is simply a wrapper on top of addMockFunctionsToSchema which, according to the Apollo docs, “adds your mock resolvers to your schema and returns a client that will correctly execute your query with variables.” If our query doesn’t require variable support, we will use the graphql function instead.

The last bit of this mockQueryResponse function is where we return our mock object. We’ve allowed engineers to override the generated response data to test specific edge cases by passing in a customDataReponse. If that variable is present, we will essentially swap out the generated file for the value being passed in.

Great! So now we have a fairly advanced helper function that will handle queries with or without variables. It also allows for custom data mocking if engineers need fine-grained control to test for specific edge cases within their React components.

Conclusion

We just created a mocking package that will assist us in generating fake data to streamline our React component tests and save us a great deal of setup in our frontend test files. We also learned a lot about GraphQL’s type schema and how integral it is to building complex applications with ever-changing data requirements.

These are just some of the many benefits of having a strongly typed application schema for your querying interface and it’s why we love using GraphQL and Apollo in production. GraphQL is a great choice for the modern web application stack and is a technology that has seen very rapid adoption and praise within the web development community. Feel free to post in the comments below about your experience using GraphQL in production environments.

One last thing…

If you liked this article, smash that clap button👏 and you will receive a lifetime of good fortune and testing happiness👊

My name is Stephen and I’m a Software Engineer at AdHawk. We are working on a variety of exciting new technologies and applications and are always looking for talented engineers to join our fast growing team. Take a look at our job board and apply today -> https://www.tryadhawk.com/jobs/

--

--