From 199906b4e77a366e00b2298cb82873a210b570d6 Mon Sep 17 00:00:00 2001 From: sbriat Date: Fri, 27 Jan 2023 12:18:32 +0100 Subject: [PATCH] improve database tests --- .../tests/unit/prisma-repository.spec.ts | 221 ++++++++++++++---- 1 file changed, 176 insertions(+), 45 deletions(-) diff --git a/src/modules/database/tests/unit/prisma-repository.spec.ts b/src/modules/database/tests/unit/prisma-repository.spec.ts index 064ba6e..5ae3feb 100644 --- a/src/modules/database/tests/unit/prisma-repository.spec.ts +++ b/src/modules/database/tests/unit/prisma-repository.spec.ts @@ -3,6 +3,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { PrismaService } from '../../src/adapters/secondaries/prisma-service'; import { PrismaRepository } from '../../src/adapters/secondaries/prisma-repository.abstract'; import { DatabaseException } from '../../src/exceptions/database.exception'; +import { PrismaClientKnownRequestError } from '@prisma/client/runtime'; class FakeEntity { uuid?: string; @@ -57,7 +58,20 @@ const mockPrismaService = { return Promise.resolve([fakeEntities, fakeEntities.length]); }), fake: { - create: jest.fn().mockResolvedValue(fakeEntityCreated), + create: jest + .fn() + .mockResolvedValueOnce(fakeEntityCreated) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .mockImplementationOnce((params?: any) => { + throw new PrismaClientKnownRequestError('unknown request', { + code: 'code', + clientVersion: 'version', + }); + }) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .mockImplementationOnce((params?: any) => { + throw new Error('an unknown error'); + }), findMany: jest.fn().mockImplementation((params?: any) => { if (params?.where?.limit == 1) { @@ -77,46 +91,99 @@ const mockPrismaService = { ); } - if (!entity) { + if (!entity && params?.where?.uuid == 'unknown') { + throw new PrismaClientKnownRequestError('unknown request', { + code: 'code', + clientVersion: 'version', + }); + } else if (!entity) { throw new Error('no entity'); } return entity; }), - findFirst: jest.fn().mockImplementation((params?: any) => { - if (params?.where?.name) { - return Promise.resolve( - fakeEntities.find((entity) => entity.name === params?.where?.name), - ); - } - }), - - update: jest.fn().mockImplementation((params: any) => { - const entity = fakeEntities.find( - (entity) => entity.uuid === params.where.uuid, - ); - Object.entries(params.data).map(([key, value]) => { - entity[key] = value; - }); - - return Promise.resolve(entity); - }), - - delete: jest.fn().mockImplementation((params: any) => { - let found = false; - - fakeEntities.forEach((entity, index) => { - if (entity.uuid === params?.where?.uuid) { - found = true; - fakeEntities.splice(index, 1); + findFirst: jest + .fn() + .mockImplementationOnce((params?: any) => { + if (params?.where?.name) { + return Promise.resolve( + fakeEntities.find((entity) => entity.name === params?.where?.name), + ); } - }); + }) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .mockImplementationOnce((params?: any) => { + throw new PrismaClientKnownRequestError('unknown request', { + code: 'code', + clientVersion: 'version', + }); + }) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .mockImplementationOnce((params?: any) => { + throw new Error('an unknown error'); + }), - if (!found) { - throw new Error(); - } - }), + update: jest + .fn() + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .mockImplementationOnce((params?: any) => { + throw new PrismaClientKnownRequestError('unknown request', { + code: 'code', + clientVersion: 'version', + }); + }) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .mockImplementationOnce((params?: any) => { + throw new PrismaClientKnownRequestError('unknown request', { + code: 'code', + clientVersion: 'version', + }); + }) + .mockImplementationOnce((params: any) => { + const entity = fakeEntities.find( + (entity) => entity.name === params.where.name, + ); + Object.entries(params.data).map(([key, value]) => { + entity[key] = value; + }); + + return Promise.resolve(entity); + }) + .mockImplementation((params: any) => { + const entity = fakeEntities.find( + (entity) => entity.uuid === params.where.uuid, + ); + Object.entries(params.data).map(([key, value]) => { + entity[key] = value; + }); + + return Promise.resolve(entity); + }), + + delete: jest + .fn() + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .mockImplementationOnce((params?: any) => { + throw new PrismaClientKnownRequestError('unknown request', { + code: 'code', + clientVersion: 'version', + }); + }) + .mockImplementation((params: any) => { + let found = false; + + fakeEntities.forEach((entity, index) => { + if (entity.uuid === params?.where?.uuid) { + found = true; + fakeEntities.splice(index, 1); + } + }); + + if (!found) { + throw new Error(); + } + }), }, }; @@ -180,14 +247,32 @@ describe('PrismaRepository', () => { expect(newEntity).toBe(fakeEntityCreated); expect(prisma.fake.create).toHaveBeenCalledTimes(1); }); + + it('should throw a DatabaseException for client error', async () => { + await expect( + fakeRepository.create(fakeEntityToCreate), + ).rejects.toBeInstanceOf(DatabaseException); + }); + + it('should throw a DatabaseException if uuid is not found', async () => { + await expect( + fakeRepository.create(fakeEntityToCreate), + ).rejects.toBeInstanceOf(DatabaseException); + }); }); - describe('findOne', () => { + describe('findOneByUuid', () => { it('should find an entity by uuid', async () => { const entity = await fakeRepository.findOneByUuid(fakeEntities[0].uuid); expect(entity).toBe(fakeEntities[0]); }); + it('should throw a DatabaseException for client error', async () => { + await expect( + fakeRepository.findOneByUuid('unknown'), + ).rejects.toBeInstanceOf(DatabaseException); + }); + it('should throw a DatabaseException if uuid is not found', async () => { await expect( fakeRepository.findOneByUuid('wrong-uuid'), @@ -195,8 +280,55 @@ describe('PrismaRepository', () => { }); }); + describe('findOne', () => { + it('should find one entity', async () => { + const entity = await fakeRepository.findOne({ + name: fakeEntities[0].name, + }); + + expect(entity.name).toBe(fakeEntities[0].name); + }); + + it('should throw a DatabaseException for client error', async () => { + await expect( + fakeRepository.findOne({ + name: fakeEntities[0].name, + }), + ).rejects.toBeInstanceOf(DatabaseException); + }); + + it('should throw a DatabaseException for unknown error', async () => { + await expect( + fakeRepository.findOne({ + name: fakeEntities[0].name, + }), + ).rejects.toBeInstanceOf(DatabaseException); + }); + }); + describe('update', () => { - it('should update an entity', async () => { + it('should throw a DatabaseException for client error', async () => { + await expect( + fakeRepository.update('fake-uuid', { name: 'error' }), + ).rejects.toBeInstanceOf(DatabaseException); + await expect( + fakeRepository.updateWhere({ name: 'error' }, { name: 'new error' }), + ).rejects.toBeInstanceOf(DatabaseException); + }); + + it('should update an entity with name', async () => { + const newName = 'new-random-name'; + + await fakeRepository.updateWhere( + { name: fakeEntities[0].name }, + { + name: newName, + }, + ); + expect(fakeEntities[0].name).toBe(newName); + }); + + it('should update an entity with uuid', async () => { const newName = 'random-name'; await fakeRepository.update(fakeEntities[0].uuid, { @@ -209,10 +341,19 @@ describe('PrismaRepository', () => { await expect( fakeRepository.update('fake-uuid', { name: 'error' }), ).rejects.toBeInstanceOf(DatabaseException); + await expect( + fakeRepository.updateWhere({ name: 'error' }, { name: 'new error' }), + ).rejects.toBeInstanceOf(DatabaseException); }); }); describe('delete', () => { + it('should throw a DatabaseException for client error', async () => { + await expect(fakeRepository.delete('fake-uuid')).rejects.toBeInstanceOf( + DatabaseException, + ); + }); + it('should delete an entity', async () => { const savedUuid = fakeEntities[0].uuid; @@ -231,14 +372,4 @@ describe('PrismaRepository', () => { ); }); }); - - describe('findOne', () => { - it('should find one entity', async () => { - const entity = await fakeRepository.findOne({ - name: fakeEntities[0].name, - }); - - expect(entity.name).toBe(fakeEntities[0].name); - }); - }); });