libs tests
This commit is contained in:
parent
8d1d0f82cf
commit
26dab584b2
14
package.json
14
package.json
|
@ -93,10 +93,15 @@
|
||||||
"ts"
|
"ts"
|
||||||
],
|
],
|
||||||
"modulePathIgnorePatterns": [
|
"modulePathIgnorePatterns": [
|
||||||
"libs/",
|
|
||||||
".module.ts",
|
".module.ts",
|
||||||
".dto.ts",
|
".dto.ts",
|
||||||
".constants.ts",
|
".constants.ts",
|
||||||
|
".response.ts",
|
||||||
|
".response.base.ts",
|
||||||
|
".port.ts",
|
||||||
|
"libs/exceptions",
|
||||||
|
"libs/types",
|
||||||
|
"prisma-service.base.ts",
|
||||||
"main.ts"
|
"main.ts"
|
||||||
],
|
],
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
|
@ -108,10 +113,15 @@
|
||||||
"**/*.(t|j)s"
|
"**/*.(t|j)s"
|
||||||
],
|
],
|
||||||
"coveragePathIgnorePatterns": [
|
"coveragePathIgnorePatterns": [
|
||||||
"libs/",
|
|
||||||
".module.ts",
|
".module.ts",
|
||||||
".dto.ts",
|
".dto.ts",
|
||||||
".constants.ts",
|
".constants.ts",
|
||||||
|
".response.ts",
|
||||||
|
".response.base.ts",
|
||||||
|
".port.ts",
|
||||||
|
"libs/exceptions",
|
||||||
|
"libs/types",
|
||||||
|
"prisma-service.base.ts",
|
||||||
"main.ts"
|
"main.ts"
|
||||||
],
|
],
|
||||||
"coverageDirectory": "../coverage",
|
"coverageDirectory": "../coverage",
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './exception.base';
|
export * from './exception.base';
|
||||||
export * from './exception.codes';
|
export * from './exception.codes';
|
||||||
export * from './exceptions';
|
export * from './exceptions';
|
||||||
|
export * from './rpc-exception.codes.enum';
|
||||||
|
|
|
@ -0,0 +1,250 @@
|
||||||
|
import { ResponseBase } from '@libs/api/response.base';
|
||||||
|
import { PrismaRepositoryBase } from '@libs/db/prisma-repository.base';
|
||||||
|
import { PrismaService } from '@libs/db/prisma.service';
|
||||||
|
import { AggregateID, AggregateRoot, Mapper, RepositoryPort } from '@libs/ddd';
|
||||||
|
import { ConflictException } from '@libs/exceptions';
|
||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { Prisma } from '@prisma/client';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
export interface FakeProps {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateFakeProps {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeEntity extends AggregateRoot<FakeProps> {
|
||||||
|
protected readonly _id: AggregateID;
|
||||||
|
|
||||||
|
static create = (create: CreateFakeProps): FakeEntity => {
|
||||||
|
const id = v4();
|
||||||
|
const props: FakeProps = { ...create };
|
||||||
|
const fake = new FakeEntity({ id, props });
|
||||||
|
return fake;
|
||||||
|
};
|
||||||
|
|
||||||
|
validate(): void {
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FakeModel = {
|
||||||
|
uuid: string;
|
||||||
|
name: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
};
|
||||||
|
|
||||||
|
type FakeRepositoryPort = RepositoryPort<FakeEntity>;
|
||||||
|
|
||||||
|
class FakeResponseDto extends ResponseBase {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fakeDbWriteModel: FakeModel = {
|
||||||
|
uuid: 'd567ea3b-4981-43c9-9449-a409b5fa9fed',
|
||||||
|
name: 'fakeName',
|
||||||
|
createdAt: new Date('2023-06-28T16:02:00Z'),
|
||||||
|
updatedAt: new Date('2023-06-28T16:02:00Z'),
|
||||||
|
};
|
||||||
|
|
||||||
|
let modelId = 2;
|
||||||
|
const modelUuid = 'uuid-';
|
||||||
|
const modelName = 'name-';
|
||||||
|
|
||||||
|
const createRandomModel = (): FakeModel => {
|
||||||
|
const fakeModel: FakeModel = {
|
||||||
|
uuid: `${modelUuid}${modelId}`,
|
||||||
|
name: `${modelName}${modelId}`,
|
||||||
|
createdAt: new Date('2023-06-30T08:00:00Z'),
|
||||||
|
updatedAt: new Date('2023-06-30T08:00:00Z'),
|
||||||
|
};
|
||||||
|
|
||||||
|
modelId++;
|
||||||
|
|
||||||
|
return fakeModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fakeModels: FakeModel[] = [];
|
||||||
|
Array.from({ length: 10 }).forEach(() => {
|
||||||
|
fakeModels.push(createRandomModel());
|
||||||
|
});
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
class FakeMapper
|
||||||
|
implements Mapper<FakeEntity, FakeModel, FakeModel, FakeResponseDto>
|
||||||
|
{
|
||||||
|
toPersistence = (entity: FakeEntity): FakeModel => {
|
||||||
|
const copy = entity.getProps();
|
||||||
|
const record: FakeModel = {
|
||||||
|
uuid: copy.id,
|
||||||
|
name: copy.name,
|
||||||
|
createdAt: copy.createdAt,
|
||||||
|
updatedAt: copy.updatedAt,
|
||||||
|
};
|
||||||
|
return record;
|
||||||
|
};
|
||||||
|
|
||||||
|
toDomain = (record: FakeModel): FakeEntity => {
|
||||||
|
const entity = new FakeEntity({
|
||||||
|
id: record.uuid,
|
||||||
|
createdAt: new Date(record.createdAt),
|
||||||
|
updatedAt: new Date(record.updatedAt),
|
||||||
|
props: {
|
||||||
|
name: record.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return entity;
|
||||||
|
};
|
||||||
|
|
||||||
|
toResponse = (entity: FakeEntity): FakeResponseDto => {
|
||||||
|
const props = entity.getProps();
|
||||||
|
const response = new FakeResponseDto(entity);
|
||||||
|
response.name = props.name;
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
class FakePrismaService extends PrismaService {
|
||||||
|
fake: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockPrismaService = {
|
||||||
|
$queryRaw: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||||
|
code: 'code',
|
||||||
|
clientVersion: 'version',
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.mockImplementation(() => {
|
||||||
|
throw new Prisma.PrismaClientKnownRequestError('Database unavailable', {
|
||||||
|
code: 'code',
|
||||||
|
clientVersion: 'version',
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
fake: {
|
||||||
|
create: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce(fakeDbWriteModel)
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
throw new Prisma.PrismaClientKnownRequestError('Already exists', {
|
||||||
|
code: 'code',
|
||||||
|
clientVersion: 'version',
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
throw new Error('an unknown error');
|
||||||
|
}),
|
||||||
|
|
||||||
|
findUnique: jest.fn().mockImplementation(async (params?: any) => {
|
||||||
|
let model: FakeModel;
|
||||||
|
|
||||||
|
if (params?.where?.uuid) {
|
||||||
|
model = fakeModels.find(
|
||||||
|
(entity) => entity.uuid === params?.where?.uuid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!model && params?.where?.uuid == 'unknown') {
|
||||||
|
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||||
|
code: 'code',
|
||||||
|
clientVersion: 'version',
|
||||||
|
});
|
||||||
|
} else if (!model) {
|
||||||
|
throw new Error('No record found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
class FakeRepository
|
||||||
|
extends PrismaRepositoryBase<FakeEntity, FakeModel, FakeModel>
|
||||||
|
implements FakeRepositoryPort
|
||||||
|
{
|
||||||
|
constructor(
|
||||||
|
prisma: FakePrismaService,
|
||||||
|
mapper: FakeMapper,
|
||||||
|
eventEmitter: EventEmitter2,
|
||||||
|
) {
|
||||||
|
super(
|
||||||
|
prisma.fake,
|
||||||
|
prisma,
|
||||||
|
mapper,
|
||||||
|
eventEmitter,
|
||||||
|
new Logger(FakeRepository.name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('PrismaRepositoryBase', () => {
|
||||||
|
let fakeRepository: FakeRepository;
|
||||||
|
let prisma: FakePrismaService;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
EventEmitter2,
|
||||||
|
FakeRepository,
|
||||||
|
FakeMapper,
|
||||||
|
{
|
||||||
|
provide: FakePrismaService,
|
||||||
|
useValue: mockPrismaService,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
fakeRepository = module.get<FakeRepository>(FakeRepository);
|
||||||
|
prisma = module.get<FakePrismaService>(FakePrismaService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(fakeRepository).toBeDefined();
|
||||||
|
expect(prisma).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('insert', () => {
|
||||||
|
it('should create a model', async () => {
|
||||||
|
jest.spyOn(prisma.fake, 'create');
|
||||||
|
|
||||||
|
await fakeRepository.insert(
|
||||||
|
FakeEntity.create({
|
||||||
|
name: 'someFakeName',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(prisma.fake.create).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw a ConflictException if model already exists', async () => {
|
||||||
|
await expect(
|
||||||
|
fakeRepository.insert(
|
||||||
|
FakeEntity.create({
|
||||||
|
name: 'someFakeName',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).rejects.toBeInstanceOf(ConflictException);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an exception an error occurs', async () => {
|
||||||
|
await expect(
|
||||||
|
fakeRepository.insert(
|
||||||
|
FakeEntity.create({
|
||||||
|
name: 'someFakeName',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).rejects.toBeInstanceOf(Error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { Guard } from '@libs/guard';
|
||||||
|
|
||||||
|
describe('Guard', () => {
|
||||||
|
describe('isEmpty', () => {
|
||||||
|
it('should return false for a number', () => {
|
||||||
|
expect(Guard.isEmpty(1)).toBeFalsy();
|
||||||
|
});
|
||||||
|
it('should return false for a falsy boolean', () => {
|
||||||
|
expect(Guard.isEmpty(false)).toBeFalsy();
|
||||||
|
});
|
||||||
|
it('should return false for a truthy boolean', () => {
|
||||||
|
expect(Guard.isEmpty(true)).toBeFalsy();
|
||||||
|
});
|
||||||
|
it('should return true for undefined', () => {
|
||||||
|
expect(Guard.isEmpty(undefined)).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should return true for null', () => {
|
||||||
|
expect(Guard.isEmpty(null)).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should return false for a Date', () => {
|
||||||
|
expect(Guard.isEmpty(new Date('2023-06-28'))).toBeFalsy();
|
||||||
|
});
|
||||||
|
it('should return false for an object with keys', () => {
|
||||||
|
expect(Guard.isEmpty({ key: 'value' })).toBeFalsy();
|
||||||
|
});
|
||||||
|
it('should return true for an object without keys', () => {
|
||||||
|
expect(Guard.isEmpty({})).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should return true for an array without values', () => {
|
||||||
|
expect(Guard.isEmpty([])).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should return true for an array with only empty values', () => {
|
||||||
|
expect(Guard.isEmpty([null, undefined])).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should return false for an array with some empty values', () => {
|
||||||
|
expect(Guard.isEmpty([1, null, undefined])).toBeFalsy();
|
||||||
|
});
|
||||||
|
it('should return true for an empty string', () => {
|
||||||
|
expect(Guard.isEmpty('')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('lengthIsBetween', () => {
|
||||||
|
it('should return true for a string in the range', () => {
|
||||||
|
expect(Guard.lengthIsBetween('test', 0, 4)).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should return true for a number in the range', () => {
|
||||||
|
expect(Guard.lengthIsBetween(2, 0, 4)).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should return true for an array with number of elements in the range', () => {
|
||||||
|
expect(Guard.lengthIsBetween([1, 2, 3], 0, 4)).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should return false for a string not in the range', () => {
|
||||||
|
expect(Guard.lengthIsBetween('test', 5, 9)).toBeFalsy();
|
||||||
|
});
|
||||||
|
it('should return false for a number not in the range', () => {
|
||||||
|
expect(Guard.lengthIsBetween(2, 3, 6)).toBeFalsy();
|
||||||
|
});
|
||||||
|
it('should return false for an array with number of elements not in the range', () => {
|
||||||
|
expect(Guard.lengthIsBetween([1, 2, 3], 10, 12)).toBeFalsy();
|
||||||
|
});
|
||||||
|
it('should throw an exception if value is empty', () => {
|
||||||
|
expect(() => Guard.lengthIsBetween(undefined, 0, 4)).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue