Logo

dev-resources.site

for different kinds of informations.

Testing a GraphQL Application with Jest and SuperTest

Published at
1/13/2025
Categories
jest
javascript
typescript
testing
Author
joaosc17
Author
8 person written this
joaosc17
open
Testing a GraphQL Application with Jest and SuperTest

In this blog post, we'll explore the challenges and solutions involved in testing a GraphQL API using Jest and SuperTest. The journey began with the need to simulate headers, specifically for token-based authentication, in Jest tests.

The Challenge: Simulating Headers in Jest

While developing the Todo Backend GraphQL project for the Woovi challenge, I encountered a significant roadblock. I needed to test the GraphQL API's authentication, which relies on JSON Web Tokens (JWT) passed in the HTTP headers. Initially, I struggled to find a straightforward way to simulate these headers in Jest. The standard Jest setup wasn't enough because it didn't directly handle HTTP requests and responses in the same way a real server does.

The Solution: Discovering SuperTest

After several trials and errors, I came across SuperTest, a library designed for HTTP assertions. SuperTest extends the functionality of Jest by allowing you to test HTTP servers as if they were real clients. This capability made it possible to simulate headers, including the authorization tokens required for my API's authentication.

Setting Up the Test Environment

Before diving into the tests, let's set up the environment.

  1. Install Dependencies First, ensure you have Jest, SuperTest, and Faker installed:
   npm install --save-dev jest supertest faker
Enter fullscreen mode Exit fullscreen mode
  1. Configure Jest Create a jest.config.js file:
   module.exports = {
     preset: 'ts-jest',
     testEnvironment: 'node',
   };
Enter fullscreen mode Exit fullscreen mode
  1. Write Test Cases With the environment ready, we can now write test cases.

Writing Tests with SuperTest

SuperTest became the game-changer in this scenario. Here's how I used it to test the API's CRUD operations and authentication.

Testing CRUD Operations with SuperTest

  1. Setup and Teardown Use Jest's beforeAll and afterAll hooks for setup and teardown:
   import { connect, disconnectDatabase } from './mongooseConnection';
   import supertest from 'supertest';
   import app from './../index';

   beforeAll(async () => {
     await connect();
   });

   afterAll(async () => {
     await disconnectDatabase();
   });
Enter fullscreen mode Exit fullscreen mode
  1. Test Authentication and Token Usage Create a helper function to register a user and get the token:
   import { faker } from '@faker-js/faker';
   import { graphql } from 'graphql';
   import { schema } from '../schema';

   async function authUserTest() {
     const userTest = {
       name: faker.name.firstName(),
       email: faker.internet.email(),
       password: faker.internet.password(),
     };
     const source = `
       mutation {
         register(name: "${userTest.name}", email: "${userTest.email}", password: "${userTest.password}") {
           token
           user {
             name
             email
           }
         }
       }
     `;
     const result = await graphql({ schema, source });
     const data = result.data?.register;
     return data.token;
   }
Enter fullscreen mode Exit fullscreen mode
  1. Testing Tasks CRUD Operations

    • Create a New Task
     it('should create a new task', async () => {
       const todo = {
         task: faker.lorem.words(),
         status: faker.helpers.arrayElement(['pending', 'complete', 'in progress']),
       };
       const query = `
         mutation {
           todo(task: "${todo.task}", status: "${todo.status}") {
             task
             status
           }
         }
       `;
       const { body } = await supertest(app)
         .post('/graphql')
         .send({ query })
         .set('Accept', 'application/json')
         .set('Authorization', `Bearer ${await authUserTest()}`);
       expect(body.data.todo).toMatchObject(todo);
     });
    
  • Retrieve All Tasks

     it('should retrieve all tasks', async () => {
       const query = `
         query {
           todos {
             _id
             task
             status
           }
         }
       `;
       const { body } = await supertest(app)
         .post('/graphql')
         .send({ query })
         .set('Accept', 'application/json')
         .set('Authorization', `Bearer ${await authUserTest()}`);
       expect(body.data.todos).toBeInstanceOf(Array);
     });
    
  • Update a Task

     it('should update a task', async () => {
       const todos = await Todo.find();
       const randomTodo = todos[Math.floor(Math.random() * todos.length)];
       const updatedTask = faker.lorem.words();
       const updatedStatus = faker.helpers.arrayElement(['pending', 'complete', 'in progress']);
       const query = `
         mutation {
           updateTodo(_id: "${randomTodo._id}", task: "${updatedTask}", status: "${updatedStatus}") {
             task
             status
           }
         }
       `;
       const { body } = await supertest(app)
         .post('/graphql')
         .send({ query })
         .set('Accept', 'application/json')
         .set('Authorization', `Bearer ${await authUserTest()}`);
       expect(body.data.updateTodo.task).toBe(updatedTask);
       expect(body.data.updateTodo.status).toBe(updatedStatus);
     });
    
  • Delete a Task

     it('should delete a task', async () => {
       const todos = await Todo.find();
       const randomTodo = todos[Math.floor(Math.random() * todos.length)];
       const query = `
         mutation {
           deleteTodo(_id: "${randomTodo._id}") {
             _id
           }
         }
       `;
       const { body } = await supertest(app)
         .post('/graphql')
         .send({ query })
         .set('Accept', 'application/json')
         .set('Authorization', `Bearer ${await authUserTest()}`);
       expect(body.data.deleteTodo._id).toBe(randomTodo._id);
     });
    

Running the Tests

Run your tests using Jest:

npm test
Enter fullscreen mode Exit fullscreen mode

This command will execute all test files, providing a detailed report of the results.

Conclusion

The difficulty in simulating headers in Jest led to the discovery of SuperTest, which significantly simplified the process. By leveraging SuperTest alongside Jest, I was able to effectively test the GraphQL API's authentication and CRUD operations, ensuring the application's security and functionality. Sharing this learning process highlights the power of public learning and community-driven problem-solving.

jest Article's
30 articles in total
Favicon
Why You Hate Test Coverage
Favicon
Mockando Constantes em Testes com Jest: Um Exemplo Prático
Favicon
Taming the CI Beast: Optimizing a Massive Next.js Application (Part 1)
Favicon
Testing a GraphQL Application with Jest and SuperTest
Favicon
[Boost]
Favicon
How to write unit test in react?
Favicon
4. Testing (async) searchParams with Jest in Next 15
Favicon
3. How to setup Jest in a Next 15 project (+ eslint for testing)
Favicon
Sharding Jest tests. Harder than it should be?
Favicon
Migration from Jest to Vitest: A Real-World Experience with 2900+ Tests
Favicon
Mastering Jest: A Guide to Efficient JavaScript Testing
Favicon
Guide - Setting Up Jest for Unit Testing in a TypeScript React Project
Favicon
Testes Unitários com Jest
Favicon
5. Mocking usePathName, useSearchParams and useRouter with Jest in Next 15
Favicon
🛠️ Writing Reliable Code from the Ground Up !
Favicon
How To Test Your JavaScript Application With Jest Framework?
Favicon
Mocking with Jest and typescript - a cheatsheet
Favicon
Mastering Testing in React with Jest and React Testing Library
Favicon
Exploring Snapshot Testing in Jest: Pros and Cons
Favicon
Implementing CI with GitHub Actions Workflow
Favicon
How to write jest test cases for react component?
Favicon
Testing LLM Applications: Misadventures in Mocking SDKs vs Direct HTTP Requests
Favicon
Creating tests in real database with NestJS, TypeORM and PostgreSQL
Favicon
Let’s Make Jest Run Much Faster
Favicon
Testing and Debugging: Basic Tools and Techniques for Effective Full-Stack Tests
Favicon
Comparing Jest, React Testing Library, and Playwright: Testing Approaches for React Applications
Favicon
Error in Jest integration with Vue js
Favicon
Declarative Programming
Favicon
Maximize a Performance dos Seus Testes com Jest e Vitest
Favicon
Introduction to Jest: Unit Testing, Mocking, and Asynchronous Code

Featured ones: