Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

GraphQL integration testing

The GraphQL plugin allows you to test GraphQL APIs using Tavern. It provides specialized request and response handling that understands GraphQL’s unique structure and requirements.

Important Note on Query Formatting

GraphQL queries cannot use Tavern’s standard variable formatting (curly braces {}) because GraphQL syntax itself uses curly braces. If you try to use formatting like {variable} in your GraphQL queries, it will fail because Tavern will attempt to format them before sending the query.

Instead, use GraphQL variables for any dynamic content:

# ✅ GOOD - Use GraphQL variables
stages:
  - name: Query user with variable
    graphql_request:
      url: "{graphql_server_url}/graphql"    # URL formatting works fine
      query: |
        query GetUser($id: ID!) {
          user(id: $id) {                     # GraphQL variables work fine
            id
            name
            email
          }
        }
      variables:
        id: "{user_id}"                      # Variables in the variables object support formatting

# ❌ BAD - Don't use formatting in queries
stages:
  - name: Query user with formatting in query
    graphql_request:
      url: "{graphql_server_url}/graphql"
      query: |
        query GetUser {
          user(id: "{user_id}") {             # This will fail - formatting in query
            id
            name
          }
        }

Configuration

If using the default gql backend for graphql, default options can be passed to the underlying HTTP transport in the “gql” block at the top level for a test. The GraphQL configuration schema supports these options:

gql:
  headers:
    string: string              # Default headers for all requests

For example, to make a query with an authorization header for all requests, not just for a single stage like in the example below:

---

test_name: Query with global authorization header

gql:
  headers:
    Authorization: "Bearer test-token"

stages:
  - name: Query with authorization header
    graphql_request:
      ...

Requests

Basic Query

stages:
  - name: Get user by ID
    graphql_request:
      url: "{graphql_server_url}/graphql"
      query: |
        query GetUser($id: ID!) {
          user(id: $id) {
            id
            name
            email
          }
        }
      variables:
        id: "1"

Query with Variables

Use variables for dynamic data. Variables support standard Tavern formatting:

stages:
  - name: Create user with test variables
    graphql_request:
      url: "{graphql_server_url}/graphql"
      query: |
        mutation CreateUser($name: String!, $email: String!) {
          createUser(name: $name, email: $email) {
            id
            name
            email
          }
        }
      variables:
        name: "{user_name}"        # Formatting works in variables
        email: "{user_email}"

Query with Headers

stages:
  - name: Authenticated query
    graphql_request:
      url: "{graphql_server_url}/graphql"
      headers:
        Authorization: "Bearer {auth_token}"
        Content-Type: "application/json"  # Automatically added if not present
      query: |
        query GetUserData {
          me {
            id
            name
          }
        }

Query with Operation Name

stages:
  - name: Named operation
    graphql_request:
      url: "{graphql_server_url}/graphql"
      query: |
        query GetUserProfile($id: ID!) {
          user(id: $id) {
            id
            name
            profile {
              bio
              avatar
            }
          }
        }
      operation_name: GetUserProfile      # Optional operation name
      variables:
        id: "1"

Multiple Operations in One Query

stages:
  - name: Multiple operations
    graphql_request:
      url: "{graphql_server_url}/graphql"
      query: |
        query GetUser($id: ID!) {
          user(id: $id) {
            id
            name
          }
        }

        mutation UpdateUser($id: ID!, $name: String!) {
          updateUser(id: $id, name: $name) {
            id
            name
          }
        }
      operation_name: GetUser           # Specify which operation to execute
      variables:
        id: "1"

File Uploads

GraphQL file uploads are handled through variables using the Upload scalar type. You need to:

  1. Define a GraphQL mutation with an Upload parameter

  2. Use the files: block in your test to specify which file to upload

  3. The variable name in files: must match the parameter name in your mutation

stages:
  - name: Upload a file
    graphql_request:
      url: "{graphql_server_url}/graphql"
      query: |
        mutation UploadFile($file: Upload!, $title: String!) {
          uploadFile(file: $file, title: $title) {
            id
            filename
            url
          }
        }
      variables:
        title: "My File"
      files:
        file: path/to/local/file.txt
    graphql_response:
      data:
        uploadFile:
          id: !anyint
          filename: "file.txt"

You can upload multiple files by specifying them in the files: block:

stages:
  - name: Upload multiple files
    graphql_request:
      url: "{graphql_server_url}/graphql"
      query: |
        mutation UploadFiles($file1: Upload!, $file2: Upload!) {
          uploadMultiple(file1: $file1, file2: $file2) {
            id
            files {
              filename
              url
            }
          }
        }
      variables:
        # Note: variables here should not contain the file data
      files:
        file1: path/to/first/file.txt
        file2: path/to/second/file.txt
    graphql_response:
      json:
        data:
          uploadMultiple:
            id: !anyint
            files:
              - filename: "file.txt"
              - filename: "file.txt"

You can also use the long form to specify the content_type of the file:

stages:
  - name: Upload file with custom content type
    graphql_request:
      url: "{graphql_server_url}/graphql"
      query: |
        mutation UploadFile($myFileName: Upload!, $title: String!) {
          uploadFile(file: $myFileName, title: $title) {
            id
            filename
          }
        }
      variables:
        title: "Custom File"
      files:
        myFileName:
          file_path: path/to/file.txt
          content_type: text/plain
    graphql_response:
      data:
        uploadFile:
          id: !anyint
          filename: "file.txt"

Responses

GraphQL responses follow the standard GraphQL format with data and/or errors at the top level:

Successful Response

stages:
  - name: Query user
    graphql_request:
      url: "{graphql_server_url}/graphql"
      query: |
        query GetUser($id: ID!) {
          user(id: $id) {
            id
            name
          }
        }
      variables:
        id: "1"
    graphql_response:
      json:
        data:
          user:
            id: "1"
            name: "John Doe"

Response with Errors

stages:
  - name: Invalid query
    graphql_request:
      url: "{graphql_server_url}/graphql"
      query: |
        query InvalidQuery {
          invalidField {
            id
          }
        }
    graphql_response:
      json:
        errors:
          - message: "Cannot query field 'invalidField' on type 'Query'."

Strictness

As described in the strict key checking section in the basics, GraphQL responses can use the strict key to check that the response contains all or some of the expected keys. See that section for more details. The json strictness setting is reused for the data key in GraphQL responses.

Error Handling

The GraphQL plugin provides specific error handling for common GraphQL scenarios:

Response Structure Validation

Tavern automatically validates that GraphQL responses have the correct structure:

Status Code Handling

GraphQL responses should always return HTTP 200 status codes, even for:

Non-200 status codes indicate HTTP-level problems (authentication, network issues, etc.).

Limitations

Current Limitations

Future Plans