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.