How to mock functions using Vitest and supertest in GraphQL Api

Viewed 263

I created a simple api using Hapi, Apollo Server, among other dependencies and decided to use dependency injection so that I can test the services' functions (insert user in the database, etc). Such as checking if they were invoked, what arguments were passed and what their returns.

These functions I call services and are passed to my GraphQL api's resolvers, so they can be used. When I'm in the development environment, I pass the real services, while in the test environment my idea was to pass each of the services with vi.fn() to have mocked functions.

const findUserByUsername = vi.fn()
// ...

And before the tests run, I create the server instance passing the mocked services in it:

beforeAll(async () => {
    server = (await startServer({
      deleteRefreshToken,
      findRefreshToken,
      findUserById,
      findUserByUsername,
      insertRefreshToken,
      insertUser
    })).listener
    // ...
  })

However I have had a problem, from what I understand the services are not invoked in the resolvers when I test the procedures (query/mutation) using the mocked functions.

I believe that normally when we need to know if the function was invoked I could do the following:

it('Insert New User', async () => {
    await supertest(server)
      .post('/graphql')
      .set('Accept', 'application/json')
      .send({
        query: `
        mutation {
          signUp(input: {
            username: ${username},
            password: ${password}
          }) {
            id
            username
          }
        }
        `
      })
    expect(findUserByUsername.mock.calls.length).toBe(1)
  })

And to find out if the first argument of the function matched the username you would do the following:

it('Insert New User', async () => {
    await supertest(server)
      .post('/graphql')
      .set('Accept', 'application/json')
      .send({
        query: `
        mutation {
          signUp(input: {
            username: ${username},
            password: ${password}
          }) {
            id
            username
          }
        }
        `
      })
    expect(findUserByUsername.mock.calls.length).toBe(1)
    expect(findUserByUsername.mock.calls[0][0]).toBe(username)
  })

However I get the error that the function was not invoked once when it was expected to be invoked only once.

This is my test file:

import { Server } from 'http'

import { describe, it, expect, beforeAll, afterAll, vi, beforeEach } from 'vitest'
import supertest from 'supertest'
import { faker } from '@faker-js/faker'

import { startServer } from '../index'

const findUserByUsername = vi.fn()
const deleteRefreshToken = vi.fn()
const findRefreshToken = vi.fn()
const findUserById = vi.fn()
const insertRefreshToken = vi.fn()
const insertUser = vi.fn()

describe('Sign Up Mutation Suite', () => {
  let server: Server
  let username: string
  let password: string

  beforeAll(async () => {
    server = (await startServer({
      deleteRefreshToken,
      findRefreshToken,
      findUserById,
      findUserByUsername,
      insertRefreshToken,
      insertUser
    })).listener
    username = faker.internet.userName()
    password = faker.internet.password(9)
  })

  afterAll(() => {
    server.close()
  })

  beforeEach(() => {
    vi.restoreAllMocks()
  })

  it('Insert New User', async () => {
    await supertest(server)
      .post('/graphql')
      .set('Accept', 'application/json')
      .send({
        query: `
        mutation {
          signUp(input: {
            username: ${username},
            password: ${password}
          }) {
            id
            username
          }
        }
        `
      })
    expect(findUserByUsername.mock.calls.length).toBe(1)
  })
})

Am I using the function mocks incorrectly? If you want to try it locally, here is the link to the repo to clone.

0 Answers
Related