Test your GraphQL API in Elixir

Sep 3, 2017

While developing a new GraphQL API, I thought about the best way to actually test GraphQL endpoints when using Phoenix. In the end, the test coverage is similar to a controller test. GraphQL APIs have a different structure compared to REST APIs. Therefore, we will build some helpers to have an easy way to test our queries and mutations.

Example Schema

For our example, we’ll assume to have the following GraphQL Schema.

# Type definition of a User type User { id : ID ! name : String ! } # Query to get all users type Query { users : [ User !]! } # Mutation to update a user's name type Mutation { updateUserName ( id : ID !, name : String !): User ! }

We have a User , a query to get all users and a mutation to update a certain users’ name.

How a GraphQL Query looks like

GraphQL APIs work by sending a POST HTTP requests to the GraphQL endpoint (e.g. /api/graphql ) with the query and a variables field in theJSON payload. As a response, it returns an HTTP success status (200) with a data or an error field in the JSON response. Usually, when you use an GraphQL API, all of this gets abstracted by the clients like Apollo or Relay. However, for testing, it’s important to us to know the form of a request.

POST https://domain.com/api/graphql Content-Type: application/json { "query": "users { name }" }

Building the query in our tests

We now know how an HTTP request for a GraphQL query needs to look like, so we can build it in our tests. In this example, we use our users query, to build a GraphQL query in our test suite. Since we don’t need any variables for now, we just need to add the query field to our payload.

test " returns all users" do build_conn () |> post ( " api/graphql" , %{ " query" => """ users { id name } """ }) end

However, we can easily extract this logic to a GraphQL test helper.

Create test helpers

Because most of the time I just want to create a GraphQL query and immediately send it, my idea for the API looked like this:

build_conn () |> graphql_query ( query: @query ) # => Returns result

So I built a GraphQLHelper to do so:

# test/support/graphql_helper.ex defmodule MyApp . GraphqlHelper do use Phoenix . ConnTest # We need to set the default endpoint for ConnTest @endpoint MyApp . Web . Endpoint def graphql_query ( conn , options ) do conn |> post ( " /api/graphql" , build_query ( options [ :query ], options [ :variables ]) ) |> json_response ( 200 ) end defp build_query ( query , variables ) do %{ " query" => query , " variables" => variables } end end

To make this helper accessible per default in your tests you need to import it in ConnCase .

# test/support/conn_case.ex defmodule MyApp . DataCase # ... using do # ... import MyApp . GraphqlHelper end

Authentication

Most of the time, your GraphQL API needs a Token for authenticating a user. So in our example, we use a token-based authentication in our API and also create a AuthenticationHelper that will create a new user session and adds the token to the HTTP Header.

defmodule MyApp . AuthenticationHelper do def authenticate_user ( conn , user ) do token = MyApp . Accounts . create_user_session ( user ) . token conn |> Plug . Conn . put_req_header ( " authorization" , " Session #{ token } " ) end end

We also import this helper in our ConnCase and now can test our GraphQL API.

Building a mutation

With all those helpers, we now can easily test our GraphQL API. Here is an example how to update the name of a user. This is a mutation that requires the user ID and their new name.