Why are my Prisma unit tests calling my database

416 Views Asked by At

I have written a unit test for a function that creates data in my database. I created the test based on the Unit testing with Prisma guide and, according to the guide, mocking the Prisma client should prevent calls to my database. When I run the test, however, my database is called and data is actually created.

To perform the test, there are several relevant files.

In prsma.js, I instantiate the Prisma client.

import { PrismaClient } from "@prisma/client"

let prisma

if(process.env.NODE_ENV === 'production') {
    prisma = new PrismaClient()
} else {
    if(!global.prisma) {
        global.prisma = new PrismaClient()
    }
    prisma = global.prisma
}

export default prisma

In singleton.ts, I tell Jest to mock the default export.

import { PrismaClient } from '@prisma/client'
import { mockDeep, mockReset, DeepMockProxy } from 'jest-mock-extended'

import prisma from './client'

jest.mock('./client', () => ({
  __esModule: true,
  default: mockDeep<PrismaClient>(),
}))

beforeEach(() => {
  mockReset(prismaMock)
})

export const prismaMock = prisma as unknown as DeepMockProxy<PrismaClient>

In schema.prisma, I create the model for the table I'm trying to test.

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Test {
  id            Int         @id @default(autoincrement())
}

In functions-without-context.ts, I mock the process of creating data in the Test table.

import prisma from './client'

interface CreateTest {
    description: string
}

export async function createTest(test: CreateTest) {
    return await prisma.test.create({
        data: test,
    })
}

And finally, In with-singleton.ts, I create the actual tests.

import { createTest, updateTest } from '../lib/mock/functions-without-context'
import { prismaMock } from '../lib/mock/singleton'

it('should create new data ', async () => {
  const test = {
    id: 1,
  }

  prismaMock.test.prismaMock.mockResolvedValue(test)

  await expect(createTest(test)).resolves.toEqual({
    id: 1,
  })
})

Given that these files line up pretty closely to the examples in the guide, I was expecting the test I wrote to not make a call my database. How can I prevent my database from being called when I run the test?

3

There are 3 best solutions below

0
On

this is what I did and it worked perfectly with DI as well (just do container register for PrismaClient as the mockPrisma)

import { PrismaClient } from '@prisma/client';
const mockPrismaDeep = () => {
    const actualPrisma = jest.requireActual('@prisma/client');

    const mockPrisma: PrismaClient = {
        ...new actualPrisma.PrismaClient(),
        $connect: jest.fn().mockImplementation(() => Promise.resolve()),
        $disconnect: jest.fn().mockImplementation(() => Promise.resolve()),
        $transaction: jest.fn().mockImplementation(async callback => {
            const mockPrismaTransaction = {
                ...mockPrisma
            };
            await callback(mockPrismaTransaction);
        })
    };
    jest.mock('@prisma/client', () => {
        return {
            ...actualPrisma, //We want all the actual prisma stuff
            PrismaClient: jest.fn(() => mockPrisma)
        };
    });
};
mockPrismaDeep();

I have setup this as a setup file for jest after env

0
On

Also came across this issue. I used the same prisma client that is being used throughout the application and it mocks correctly.

import { PrismaClient } from '@prisma/client'
import { mockDeep, mockReset, DeepMockProxy } from 'jest-mock-extended'

import prisma from './prsma.js' //In your case

jest.mock('./prsma.js', () => ({ //In your case
  __esModule: true,
  default: mockDeep<PrismaClient>(),
}))

beforeEach(() => {
  mockReset(prismaMock)
})

export const prismaMock = prisma as unknown as DeepMockProxy<PrismaClient>

If you already have an exported prisma client in ./lib/prisma.ts that you use to make calls to the database, use the same client in .singleton.ts.

0
On

According to the docs:

enter image description here

The key is to call the following from setupFilesAfterEnv in jest.config.ts:

import { PrismaClient } from '@prisma/client'
import { mockDeep, mockReset, DeepMockProxy } from 'jest-mock-extended'

import prisma from './client'

jest.mock('./client', () => ({
  __esModule: true,
  default: mockDeep<PrismaClient>(),
}))

beforeEach(() => {
  mockReset(prismaMock)
})

export const prismaMock = prisma as unknown as DeepMockProxy<PrismaClient>

This seems like it might not be that important, but it is crucial. After doing this, you'll see that Prisma stops trying to connect to a database.