Testing Hasura GraphQL APIs with Karate
Tags: graphql, graphqltesting
Published: 2021-04-27 07:22:14

---
title: Testing Hasura GraphQL APIs with Karate
published: true
date: 2021-04-26 14:07:29 UTC
tags: GraphQL,GraphQLtesting
canonical_url: https://hasura.io/blog/testing-hasura-graphql-apis-with-karate/
---

![Testing Hasura GraphQL APIs with Karate](https://hasura.io/blog/content/images/2021/04/karate_graphql-1-.png)

So you've created your new [GraphQL API](https://hasura.io/graphql/) with Hasura - what's next?

It'd be a great idea to write some unit tests against your expected queries to make sure everything keeps working in your application as you make changes to your GraphQL API.

There are a few differences between how to test your GraphQL endpoint vs a set of REST endpoints.

The first is what you're querying against.

REST endpoints will most often times be broken up against a set of endpoints which will return the responses for their equivalent resources.

In GraphQL, you'll be looking at hitting one endpoint (in Hasura's case [http://yourapplication.com/v1/graphql](http://yourapplication.com/v1/graphql)) - using a query which will request your selected resources.

This is super-powerful since being able to select resources (especially joined / relationship-based) on the fly increases the speed of development, though also increases the need for unit tests in development and production.

The second change is the response itself.

In querying REST endpoints a response will usually yield `200 (ok)` response to signify that a request was successful. A lot of the time REST-based tooling will rely on this response specifically.

In contrast, in GraphQL it is possible to have a partial success returning some information, while also return an error other parts. These would be returned as a response of `200` with an `errors` object in the GraphQL JSON response.

While this can be good for granular error logging - it does bring up a few corner cases in testing GraphQL APIs if they are relying too heavily on the REST-like `200 (ok)` response paradigm.

## Karate

In this quick tutorial we're going to be taking a look at using Karate ([https://github.com/intuit/karate](https://github.com/intuit/karate)) which is an open-source test automation suite by Intuit to test our Hasura GraphQL API.

Karate has a ton of features from browser automation for UI testing, to parallel testing, to OCR - we're going to be taking a look at some of the more basic API request / response features, as well as the ability to create some nice Cucumber HTML test reporting.

## Getting Started

To get started, you download the repo from this location:  
[https://github.com/martin-hasura/testing-hasura-api-karate](https://github.com/martin-hasura/testing-hasura-api-karate)

Running this command from the directory will bring up your GraphQL API with a sample schema and some dummy data:

```
docker-compose up hasura db
```

## Testing with Karate

We're using the implementation of Docker-izing Karate from Quentin Barlas here: [https://github.com/qbarlas/karate-dsl](https://github.com/qbarlas/karate-dsl) - which is a little more lightweight than the official Karate containers which contain scaffolding for doing browser-based testing in Chrome.

You'll be able to find the main test file we'll be using at: `./karate/tests/testCases.feature` (tip: if you're using VSCode there's actually a Karate extension which will give you some nice code formatting).

### Your First Karate Feature

Once we're in the file you'll notice a number of test cases with commented with descriptions of what each area does in Karate syntax.

```
Feature: Test Hasura Blog Engine GraphQL API

Background:
* url 'http://host.docker.internal:8080/v1/graphql'
```

This will define the name of the Feature we're testing along with the endpoint we'll be testing. For this example we'll just be creating one Feature and will be running five tests.

### Queries and Variables

```
Given def query = read('getPosts.gql')
```

Karate has the ability to read GraphQL requests from files (these are files are found relative to your `.feature` file you're running).

```
And request { query: '#(query)' }

// or

And request { query: '#(query)', variables: '#(variables)' }
```

You can then pass your query object with your request - as well as create variable object(s) to use in your GraphQL requests.

Queries can also be written inline as well, and can use '```' for linebreaks and increased legibility (an example is in the `testCases.feature`).

### Headers

In the examples we'll be passing your headers like the following:

```
And header x-hasura-admin-secret = 'admin_secret_for_testing'
And header x-hasura-role = 'author'
And header x-hasura-user-id = 1
```

This will allow us to test things like emulating our `x-hasura-role` as well as `x-hasura-user-id` to check things like our permissions system setup (for example, we have a test case for _Users Cannot View Draft Posts_).

You can read more about customizing headers for more complicated use cases, such as dynamic headers, here: [https://github.com/intuit/karate#managing-headers-ssl-timeouts-and-http-proxy](https://github.com/intuit/karate#managing-headers-ssl-timeouts-and-http-proxy) and here: [https://github.com/intuit/karate#configure-headers](https://github.com/intuit/karate#configure-headers).

### Assertions

We'll also want to actually test for something. Karate has a deep set of assertion functions for checking your responses for the data you're requesting: [https://github.com/intuit/karate#payload-assertions](https://github.com/intuit/karate#payload-assertions)

```
* status 200
```

We can start by checking that our response status has returned as `200 (ok)`.

Now, remember earlier on we mentioned that just because a GraphQL response returns `200` doesn't necessarily mean that everything is ok.

```
* match response == "#object"
* match response.errors == '#notpresent'
```

What we're doing here is checking that 1) our response is returned as an object, and 2) our response doesn't have any error object included.

We can then get into testing the actual data which is returned as part of the response, such as:

```
* def postList = response.data.cms_post
* match postList !contains { status : "draft" }
```

The post list doesn't contain any _draft_ posts.

```
* def postCount = (response.data.cms_post.length)
* assert postCount >= 1
```

The post list _is greater than 1_.

```
* def return_obj = response.data.delete_cms_post.returning[0]
* match return_obj contains { title: "karate_test" }
```

The return object contains an exact match (in this case to a deleted post).

## Running Your Tests

Finally, we'll run the tests in a Docker container.

First, make sure your API is up and running from the earlier `docker-compose up` - you can then run your test suite with:

```
docker-compose up karate
```

This will output your test results in the `stdout` and create a new test result HTML report in the `./karate/results` directory of your project.

Happy testing!

<!--kg-card-end: markdown-->