Reputation: 19680
I use prisma to interact with my database and i would like to use jest-mock to mock the findMany
call. https://jestjs.io/docs/jest-object#jestmockedtitem-t-deep--false
brands.test.ts
import { PrismaService } from "@services/mysql.service";
import { mocked } from "jest-mock";
import faker from "@faker-js/faker";
import { GetBrands } from "./brand";
jest.mock("@services/mysql.service");
/**
* @group unit
*/
describe("Brand", () => {
afterAll(async () => {});
const mockedPrismaService = mocked(PrismaService, true);
it("should get a list of brands", async () => {
const mockedData = [
{
id: faker.datatype.uuid(),
name: faker.datatype.string(),
image: {
source: "some_source",
dtype: "some_dtype",
},
},
];
//@ts-ignore - because of relational data mockedData.image
mockedPrismaService.brand.findMany.mockResolvedValueOnce(mockedData);
const [response, error] = await GetBrands();
console.log(response, error);
});
});
mysql.service.ts
import mysql from "mysql2/promise";
import { Config } from "@config";
import { PrismaClient, Prisma } from "@prisma/client";
export const MySQLEscape = mysql.escape;
export const MySQLPreparedStatement = mysql.format;
export const PrismaService = new PrismaClient({});
export const PrismaHelper = Prisma;
However when i run this test i get the following error.
TypeError: Cannot read properties of undefined (reading 'brand')
Upvotes: 4
Views: 12937
Reputation: 1650
I added prisma object as an optional input to my resolver. If it is not being sent from parent class, it is generated in the runtime. But if it is being sent, then it is going to be used. So, I am not sending anything to that resolver in runtime but for testing purposes i am sending a MockPrismaClient class.
This is the design of my resolver
import { PrismaClient } from '@prisma/client';
export class MyResolver{
private prisma: any;
constructor(prisma?: any) {
this.prisma = (prisma || new PrismaClient()) as PrismaClient;
}
async perform(customerName: string, customerSurname: string) {
const result = await this.prisma.Customers.create({
data: {
name: customerName,
surname: customerSurname
}
})
}
And this is my test file
import {MyResolver} from '../src/MyResolver'
class MockPrismaClient {
Customers = {
create: jest.fn(),
};
}
describe('CustomOnboardingResolver', () => {
it('mocking prisma client', async () => {
const mockPrisma = new MockPrismaClient();
// set a mock return value for Customers.create
mockPrisma.Customers.create.mockResolvedValueOnce({customerId: 123});
const resolver = MyResolver(mockPrisma);
await resolver.perform("John", "Casey")
expect(mockPrisma.Customers.create).toHaveBeenCalledWith({
data: {
name: "John",
surname: "Casey"
},
});
}
}
I hope this approach would help you.
Upvotes: 0
Reputation: 886
example from my experience, in brands.test.ts:
import { PrismaService } from "@services/mysql.service";
..
jest.spyOn(PrismaService.brand , 'findMany').mockResolvedValueOnce(mockedData)
Upvotes: 0
Reputation: 2629
One option is to option use the factory approach when mocking your client.
jest.mock("@services/mysql.service", () => ({
PrismaService: {
brand: {
findMany: jest.fn(() => { })
}
},
}));
Then within your test, you can mock the findMany
function to return your test data, then call the function being tested.
const mockedData = [...];
PrismaService.brand.findMany.mockResolvedValueOnce(mockedData);
const result = await GetBrands();
It's a bit cumbersome, but it works.
Note that in my example, I've implemented GetBrands
as follows:
import { PrismaService } from "@services/mysql.service"
export const GetBrands = async () => {
const data = await PrismaService.brand.findMany();
return data;
}
In your example, you're using automatic mocking, and I'm not too familiar with it so I'm not sure how to get it working.
What seems to be happening to cause the error is your PrismaService
is undefined when it's imported here:
import { PrismaService } from "@services/mysql.service";
And then calling the mocked
function with an undefined parameter returns undefined:
const mockedPrismaService = mocked(undefined, true); // returns undefined
And finally, calling the following is what throws the error:
mockedPrismaService.brand.findMany.mockResolvedValueOnce(mockedData);
// TypeError: Cannot read properties of undefined (reading 'brand')
I would have thought something like this would be what you're after, but this throws an error:
jest.mock("@services/mysql.service", () => ({
PrismaService: mocked(PrismaService, true)
}));
// 6 |
// 7 | jest.mock("@services/mysql.service", () => ({
//> 8 | PrismaService: mocked(PrismaClient, true)
// | ^
// 9 | }));
Might be worth checking out the Prismas documentation on unit testing, as they suggest a couple of pretty different approaches.
Upvotes: 2