DEV Community

Vincent Jang
Vincent Jang

Posted on

NestJS + Prisma Testing with Test database

Hello! My Dev friends!

I found a job few month ago, I took a back-office project, It was very good opportunity to make test environment and write a test code.

So, I want to archiving personal experience and share with you how did I implemented testing environment.

I made NestJS + PrismaORM for back-office server, But This structure was major challenge for me when make test environment.

First of all, NestJS official docs recommend using TypeORM.

TypeORM can mocking in test code, But Prisma is not.
Prisma also supported unit testing and mocking, but it's little lack something.

For example, my service logic(business logic) has Prisma Service (Wrapped PrismaClient with @Injectable decorator) dependency, But it cannot inject inside business logic in test code.

NestJS with @nestjs/testing library allow to make a test module in test code.

Here's my code

auth.service.ts

@Injectable()
export class AuthService {
  constructor(
    private backofficePrisma: PrismaBackofficeService,
    private jwtService: JwtService
  ) {}

// AuthService has a Prisma service dependency.

...
Enter fullscreen mode Exit fullscreen mode

auth.service.spec.ts


describe("AuthService", () => {
  let service: AuthService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [AuthModule, ServiceModule],
      providers: [AuthService, JwtService],
    }).compile();

    service = module.get<AuthService>(AuthService);
  });

  it("Auth Service should be defined", () => {
    expect(service).toBeDefined();
  });
});

Enter fullscreen mode Exit fullscreen mode

I want to simple test auth service.
So I wrote a code like this.

it("Sign up should be return User model without password", async() => {
    const userCreateDto = {
      email : "user@example.com",
      password : "abcdef1234"
    }

    const userCreatedDate = new Date();
    const user = await service.signUp(userCreateDto);

    expect(user.email).toMatch(userCreateDto.email);
    expect(user).toHaveProperty('crated');
    expect(user).toHaveProperty('updated');
  })

Enter fullscreen mode Exit fullscreen mode

above code not explain how mocking PrismaClient, But I actually did it, but not works.

Because, Mocking Prisma same as Mocking PrismaClient, not a PrismaService

So I failed this way.

I tried to another way. just make a test database using docker.

First I wrote a docker-compose.yml

//...

test:
    command: mysqld --character-set-server=utf8 --collation-server=utf8_general_ci
    container_name: test-backoffice
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 1
    image: mysql
    ports:
      - "3307:3306"

Enter fullscreen mode Exit fullscreen mode

and setting .env.test


DATABASE_URL="mysql://root@localhost:3307/backoffice"

JWT_SECRET="your_auth_secrets"

Enter fullscreen mode Exit fullscreen mode

also setting package.json for yarn command

"test:watch": "dotenv -e .env.test -- jest --watch --config jest-int.json",

Enter fullscreen mode Exit fullscreen mode

As you can see a jest-int.json
like down below

{
  "moduleFileExtensions": ["js", "json", "ts"],
  "rootDir": ".",
  "testRegex": ".*\\.spec\\.ts$",
  "transform": {
    "^.+\\.(t|j)s$": "ts-jest"
  },
  "collectCoverageFrom": ["**/*.(t|j)s"],
  "coverageDirectory": "../coverage",
  "testEnvironment": "node",
  "moduleNameMapper": {
    "src/(.*)": "<rootDir>/src/$1"
  }
}
Enter fullscreen mode Exit fullscreen mode

And just run command yarn run test:watch and works very well.

It seems like very ugly way.

If you have a method about test business logic with inject mocking prisma without making test db, Please share me..

If I find a new good method, I will share it also.

Thanks for reading. Whatever, whenever I will appreciate your criticizing of code or method.

Top comments (3)

Collapse
 
afzal_s_h profile image
Afzal Shahul Hameed • Edited

I understand this post is a little old and you probably found a way to mock prisma. But in case someone stumbles here for help, the "jest-mock-extended" library can efficiently help in mocking prisma.

How:



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

describe('Cats (e2e)', () => {
    let mockPrisma: DeepMockProxy<PrismaClient>;
    ..
    ..
    ..

    beforeEach(async () => {
        const moduleFixture: TestingModule = await Test.createTestingModule({
            imports: [AppModule],
        })
          .overrideProvider(PrismaService)
          .useValue(mockDeep<PrismaClient>())
          ..
          ..
          .compile();

        ..
        ..
        mockPrisma = moduleFixture.get(PrismaService);
        await app.init();
    })

    ..
    ..
    it('Creates a new cat', async () => {
      mockPrisma.cat.create.mockResolvedValueOnce(mockCat);
      const res = await request(app.getHttpServer()).post('/cats').send({});
      expect(res.status).toBe(201);
      expect(res.body).toStrictEqual(mockCatResponse);
    });
    ..
    ..
})
Enter fullscreen mode Exit fullscreen mode
Collapse
 
vincentjang profile image
Vincent Jang

Thanks a lot. I will try!
Have a nice day

Collapse
 
ninthsun91 profile image
Ninthsun

Thanks, this was exactly what I was looking for!