-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Docs: Testing with Jest and Jest.Mock #5014
Comments
We had some test utils that are not maintained anymore since we are focusing on the core right now: https://github.com/prisma/prisma-test-utils They will give you a vague idea on what testing could look like with photon in the future. But we do need to create some testing guides |
Thanks @pantharshit00 I had taken a look at those but had a hard time using those patterns in my own tests for some reason. |
Thanks for asking @seawatts! One thing, which is already very useful, is changing the datasource, that Photon connects to in the Photon constructor. You can e.g. say: const photon = new Photon({
datasources: {
db: 'file:test.db'
}
}) if you just want to use a local test db. |
@timsuchanek thanks, that is helpful. However, isn't very useful when trying to do a lot of unit tests. |
I'm not super familiar with Jest, so I wasn't able to get it fully working, but I have setup how you should mock Photon and I have an idea on how to make Photon more mockable. schema.prisma generator photon {
provider = "photonjs"
}
model User {
id Int @id
name String
posts Post[]
created_at DateTime @default(now())
updated_at DateTime @updatedAt
}
model Post {
id Int @id
title String
author User
created_at DateTime @default(now())
updated_at DateTime @updatedAt
} index.ts Simple API that allows you to get users from Photon. import { Photon } from '@prisma/photon'
import express from 'express'
export default class API {
public readonly app: express.Express
constructor(private readonly photon: Photon) {
this.app = express()
this.app.get('/', this.index.bind(this))
this.app.get('/users', this.getUsers.bind(this))
}
index(_req: express.Request, res: express.Response) {
res.send('welcome to this wonderful server')
}
getUsers(
_req: express.Request,
res: express.Response,
next: express.NextFunction
) {
this.photon.users
.findMany()
.then(users => res.send(users))
.catch(next)
}
listen(port: number, handler: (args: any[]) => void) {
this.app.listen(port, handler)
}
} index.test.ts import { Photon } from '@prisma/photon'
import supertest from 'supertest'
import API from './index'
jest.mock('@prisma/photon')
describe('API', () => {
it('GET /users', async () => {
const photon = new Photon()
const api = new API(photon)
await supertest(api.app)
.get('/users')
.expect(200)
expect(photon.users).toBeCalled()
})
}) I got stuck at the To make mocking more "traditional", I suggest we export a Photon interface that can be mocked: interface IPhoton {
connect(): Promise<void>;
disconnect(): Promise<void>;
get users(): UserDelegate;
get posts(): PostDelegate;
} Then to implement it you could have something like the following (I didn't test this): class PhotonMock implements IPhoton {
public connect: () => Promise<void>
public disconnect: () => Promise<void>
public get users: () => UserDelegate
public get posts: () => PostDelegate
constructor(photon: Photon) {
this.connect = photon.connect
this.disconnect = photon.disconnect
this.users = photon.users
this.posts = photon.posts
}
} You can then granularly mock what you want to mock, and passthrough the rest: import { Photon, UserDelegate } from '@prisma/photon'
const mock = new PhotonMock(Photon())
mock.users = () => {
// return mocked implementation
} This is quite tedious so we'll probably want to autogenerate this mockable photon class. |
We recommend testing against a real test database for now: https://github.com/prisma/photonjs/issues/317#issuecomment-561558330 In the future a mocking api could look like this: const photon = new Photon({
mocks: {
users: [{
findMany: {
args: { where: {} },
response: []
}
}]
}
}) |
I ended up doing something different import { Photon } from '@prisma/photon';
const modelNames = ['user', 'tenant'];
const modelFunctions = ['findOne', 'findMany', 'create', 'delete', 'update', 'deleteMany', 'updateMany', 'upsert', 'count'];
const mock = modelNames.reduce((obj, modelName) => {
const objCopy = {
...obj,
};
objCopy[modelName] = jest.fn();
modelFunctions.forEach(modelFunction => {
objCopy[modelName][modelFunction] = jest.fn();
});
return objCopy;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}, {} as any) as jest.Mocked<Photon>; I don't love it but it works Because this allows me to do the following import { Photon } from '@prisma/photon';
import { mocked } from 'ts-jest/utils';
jest.mock('@photon/prisma');
const mockDb = mocked(db, true);
const mockUser = { id: '1'};
const mockTenant = {id: '2'};
const mockCreatedBy = jest.fn().mockResolvedValue(mockUser);
mockDb.tenants.findOne.mockImplementation((): any => {
return {
createdBy: mockCreatedBy,
};
});
it('tests the db', async () => {
mockDb.tenants.findMany.mockResolvedValue([mockTenant]);
await myFunctionThatCallsTenantsFindMany()
expect(mockDb.tenants.findMany).toBeCalled();
}); |
Just curious, is there a timeline for testing with the prisma client (since prisma v2 got out of beta)? |
Hey everyone, we'd love to learn more about why you're trying to mock the Prisma Client. We currently suggest running your tests against a real test database. From my perspective, installing and running a test database locally is straightforward nowadays and it's better to try and simulate your production environment as much as possible. Do you have any use cases where this would not be possible or practical? |
We personally do unit tests with a mocked version of prisma for faster local iteration. We use https://github.com/marchaos/jest-mock-extended for that. We also have test with a real database, but there prisma could help us to seed the DB at the beginning and delete the data at the end of the test suite or specific test. Currently we have a custom script with a list of tables to truncate and a list of input to seed, but it is not ideal and not easy to seed different data for each test suite. |
@Sytten thanks for sharing. Faster feedback is an interesting point. What's your test setup look like with https://github.com/marchaos/jest-mock-extended? We've played around with the idea of using a pool of docker containers to run tests in parallel or at least have warm databases ready at the end of each test. I could see that being an acceptable solution to the faster iteration problem. Yah, we also really need to make it easier to seed. That seems like a more urgent need to me. I'd expect seeding to come shortly after migrate stabilizes. |
Basically all our core logic function take in a context parameter that is usually the context passed from apollo. But in the case of the unit test I would create a fake context with a mocked version of prisma. What is super great with this lib is that you get full typing of the functions you mock so I do something like: mockCtx.prisma.ticketTier.findMany.mockResolvedValue([
givenTicketTier(1),
givenTicketTier(2),
]); And it will tell you if you return a bad object. Obviously it doesn't work if you start to include/select children fields. Yeah having a way to spawn multiple DB, seed them, direct the client to it and run the test would be great for unit testing with a live DB. But even just basic seeding tooling would help a lot. |
Hi folks, this has been addressed in prisma/docs#1664 so im going to go ahead and close it. If you have anything further to add please create a new issue. 🙌 |
The documentation is live here: https://www.prisma.io/docs/guides/testing/unit-testing. Thanks @molebox! |
It would be great to have something more complex for example with relations 🙌 There is no good DX regarding this 😢 |
Can you open an separate issue for that @huv1k? Then we can track this and try to make it happen. |
I am trying to figure out a good pattern for using Jest with Photon. If anyone has suggestions it would be great. And Would probably be good to document this somewhere as well.
I have tried out a couple different things but they don't seem to be working with the
jest.mock
function. Every time I try to runjest.mock('@prisma/photon')
it doesn't actually mock out the instance that has been created.The text was updated successfully, but these errors were encountered: