upgrade repositories
This commit is contained in:
parent
f111563137
commit
0ccaafc5e0
|
@ -5,6 +5,10 @@ SERVICE_PORT=5002
|
|||
# PRISMA
|
||||
DATABASE_URL="postgresql://mobicoop:mobicoop@localhost:5432/mobicoop-test?schema=auth"
|
||||
|
||||
# MESSAGE BROKER
|
||||
MESSAGE_BROKER_URI=amqp://v3-broker:5672
|
||||
MESSAGE_BROKER_EXCHANGE=mobicoop
|
||||
|
||||
# OPA
|
||||
OPA_IMAGE=openpolicyagent/opa:0.54.0
|
||||
OPA_URL=http://v3-auth-opa:8181/v1/data/
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
"test": "npm run migrate:test && dotenv -e .env.test jest",
|
||||
"test:unit": "jest --testPathPattern 'tests/unit/' --verbose",
|
||||
"test:unit:ci": "jest --testPathPattern 'tests/unit/' --coverage",
|
||||
"test:integration": "npm run migrate:test && dotenv -e .env.test -- jest --testPathPattern 'tests/integration/' --verbose",
|
||||
"test:integration": "npm run migrate:test && dotenv -e .env.test -- jest --testPathPattern 'tests/integration/' --verbose --runInBand",
|
||||
"test:integration:ci": "npm run migrate:test:ci && dotenv -e ci/.env.ci -- jest --testPathPattern 'tests/integration/'",
|
||||
"test:cov": "jest --testPathPattern 'tests/unit/' --coverage",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Inject } from '@nestjs/common';
|
||||
import { Inject, UnauthorizedException } from '@nestjs/common';
|
||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||
import { DeleteUsernameCommand } from './delete-username.command';
|
||||
import { USERNAME_REPOSITORY } from '@modules/authentication/authentication.di-tokens';
|
||||
|
@ -13,11 +13,20 @@ export class DeleteUsernameService implements ICommandHandler {
|
|||
) {}
|
||||
|
||||
async execute(command: DeleteUsernameCommand): Promise<boolean> {
|
||||
const username: UsernameEntity = await this.usernameRepository.findOneById(
|
||||
const username: UsernameEntity = await this.usernameRepository.findByName(
|
||||
command.name,
|
||||
);
|
||||
const usernamesCount: number = await this.usernameRepository.countUsernames(
|
||||
username.getProps().userId,
|
||||
);
|
||||
if (usernamesCount <= 1)
|
||||
throw new UnauthorizedException(
|
||||
'Authentication must have at least one username',
|
||||
);
|
||||
username.delete();
|
||||
const isDeleted: boolean = await this.usernameRepository.delete(username);
|
||||
const isDeleted: boolean = await this.usernameRepository.deleteUsername(
|
||||
username,
|
||||
);
|
||||
return isDeleted;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,6 @@ export type UsernameRepositoryPort = RepositoryPort<UsernameEntity> & {
|
|||
findByType(userId: string, type: Type): Promise<UsernameEntity>;
|
||||
findByName(name: string): Promise<UsernameEntity>;
|
||||
updateUsername(oldName: string, entity: UsernameEntity): Promise<void>;
|
||||
deleteUsername(entity: UsernameEntity): Promise<boolean>;
|
||||
countUsernames(userId: string): Promise<number>;
|
||||
};
|
||||
|
|
|
@ -71,11 +71,13 @@ export class UsernameRepository
|
|||
updateUsername = async (
|
||||
oldName: string,
|
||||
entity: UsernameEntity,
|
||||
): Promise<void> =>
|
||||
this.updateWhere(
|
||||
{
|
||||
username: oldName,
|
||||
},
|
||||
entity,
|
||||
);
|
||||
): Promise<void> => this.update(oldName, entity, 'username');
|
||||
|
||||
deleteUsername = async (entity: UsernameEntity): Promise<boolean> =>
|
||||
this.delete(entity, 'username');
|
||||
|
||||
countUsernames = async (userId: string): Promise<number> =>
|
||||
this.count({
|
||||
authUuid: userId,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
RpcExceptionCode,
|
||||
RpcValidationPipe,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import { Controller, UsePipes } from '@nestjs/common';
|
||||
import { Controller, UnauthorizedException, UsePipes } from '@nestjs/common';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { DeleteUsernameRequestDto } from './dtos/delete-username.request.dto';
|
||||
|
@ -25,12 +25,16 @@ export class DeleteUsernameGrpcController {
|
|||
try {
|
||||
await this.commandBus.execute(new DeleteUsernameCommand(data));
|
||||
} catch (error: any) {
|
||||
if (error instanceof UnauthorizedException)
|
||||
throw new RpcException({
|
||||
code: RpcExceptionCode.PERMISSION_DENIED,
|
||||
message: error.message,
|
||||
});
|
||||
if (error instanceof NotFoundException)
|
||||
throw new RpcException({
|
||||
code: RpcExceptionCode.NOT_FOUND,
|
||||
message: error.message,
|
||||
});
|
||||
|
||||
if (error instanceof DatabaseErrorException)
|
||||
throw new RpcException({
|
||||
code: RpcExceptionCode.INTERNAL,
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
import { TestingModule, Test } from '@nestjs/testing';
|
||||
import { v4 } from 'uuid';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { PrismaService } from '@modules/authentication/infrastructure/prisma.service';
|
||||
import { AuthenticationRepository } from '@modules/authentication/infrastructure/authentication.repository';
|
||||
import { AuthenticationMapper } from '@modules/authentication/authentication.mapper';
|
||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||
import { MESSAGE_PUBLISHER } from '@src/app.di-tokens';
|
||||
import {
|
||||
DatabaseErrorException,
|
||||
NotFoundException,
|
||||
UniqueConstraintException,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import { AuthenticationEntity } from '@modules/authentication/core/domain/authentication.entity';
|
||||
import { Type } from '@modules/authentication/core/domain/username.types';
|
||||
import { CreateAuthenticationProps } from '@modules/authentication/core/domain/authentication.types';
|
||||
|
||||
const uuid = '165192d4-398a-4469-a16b-98c02cc6f531';
|
||||
|
||||
const createAuthenticationProps: CreateAuthenticationProps = {
|
||||
userId: uuid,
|
||||
password: 'somePassword',
|
||||
usernames: [
|
||||
{
|
||||
type: Type.EMAIL,
|
||||
name: 'john.doe@email.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const mockMessagePublisher = {
|
||||
publish: jest.fn().mockImplementation(),
|
||||
};
|
||||
|
||||
const mockLogger = {
|
||||
log: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
error: jest.fn(),
|
||||
};
|
||||
|
||||
describe('AuthenticationRepository', () => {
|
||||
let prismaService: PrismaService;
|
||||
let authenticationRepository: AuthenticationRepository;
|
||||
|
||||
// const createAuthentications = async (nbToCreate = 10) => {
|
||||
// for (let i = 0; i < nbToCreate; i++) {
|
||||
// await prismaService.auth.create({
|
||||
// data: {
|
||||
// uuid: v4(),
|
||||
// password: bcrypt.hashSync(`password-${i}`, 10),
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [EventEmitterModule.forRoot()],
|
||||
providers: [
|
||||
AuthenticationRepository,
|
||||
PrismaService,
|
||||
AuthenticationMapper,
|
||||
{
|
||||
provide: MESSAGE_PUBLISHER,
|
||||
useValue: mockMessagePublisher,
|
||||
},
|
||||
],
|
||||
})
|
||||
// disable logging
|
||||
.setLogger(mockLogger)
|
||||
.compile();
|
||||
|
||||
prismaService = module.get<PrismaService>(PrismaService);
|
||||
authenticationRepository = module.get<AuthenticationRepository>(
|
||||
AuthenticationRepository,
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await prismaService.$disconnect();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await prismaService.auth.deleteMany();
|
||||
});
|
||||
|
||||
// describe('findAll', () => {
|
||||
// it('should return an empty data array', async () => {
|
||||
// const res = await authenticationRepository.findAll();
|
||||
// expect(res).toEqual({
|
||||
// data: [],
|
||||
// total: 0,
|
||||
// });
|
||||
// });
|
||||
|
||||
// it('should return a data array with 8 auths', async () => {
|
||||
// await createAuthentications(8);
|
||||
// const auths = await authenticationRepository.findAll();
|
||||
// expect(auths.data.length).toBe(8);
|
||||
// expect(auths.total).toBe(8);
|
||||
// });
|
||||
|
||||
// it('should return a data array limited to 10 authentications', async () => {
|
||||
// await createAuthentications(20);
|
||||
// const auths = await authenticationRepository.findAll();
|
||||
// expect(auths.data.length).toBe(10);
|
||||
// expect(auths.total).toBe(20);
|
||||
// });
|
||||
// });
|
||||
|
||||
describe('findOneById', () => {
|
||||
it('should return an authentication', async () => {
|
||||
const authToFind = await prismaService.auth.create({
|
||||
data: {
|
||||
uuid: v4(),
|
||||
password: bcrypt.hashSync(`password`, 10),
|
||||
},
|
||||
});
|
||||
|
||||
const auth = await authenticationRepository.findOneById(authToFind.uuid);
|
||||
expect(auth.id).toBe(authToFind.uuid);
|
||||
});
|
||||
|
||||
it('should throw an exception if record is not found', async () => {
|
||||
await expect(
|
||||
authenticationRepository.findOneById(
|
||||
'544572be-11fb-4244-8235-587221fc9104',
|
||||
),
|
||||
).rejects.toBeInstanceOf(NotFoundException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('should create an authentication', async () => {
|
||||
const beforeCount = await prismaService.auth.count();
|
||||
|
||||
const authenticationToCreate: AuthenticationEntity =
|
||||
await AuthenticationEntity.create(createAuthenticationProps);
|
||||
await authenticationRepository.insert(authenticationToCreate);
|
||||
|
||||
const afterCount = await prismaService.auth.count();
|
||||
|
||||
expect(afterCount - beforeCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should throw a UniqueConstraintException if authentication already exists', async () => {
|
||||
await prismaService.auth.create({
|
||||
data: {
|
||||
uuid: uuid,
|
||||
password: bcrypt.hashSync(`password`, 10),
|
||||
},
|
||||
});
|
||||
|
||||
const authenticationToCreate: AuthenticationEntity =
|
||||
await AuthenticationEntity.create(createAuthenticationProps);
|
||||
await expect(
|
||||
authenticationRepository.insert(authenticationToCreate),
|
||||
).rejects.toBeInstanceOf(UniqueConstraintException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
it('should update an authentication', async () => {
|
||||
const authenticationToUpdate = await prismaService.auth.create({
|
||||
data: {
|
||||
uuid: v4(),
|
||||
password: bcrypt.hashSync(`password`, 10),
|
||||
},
|
||||
});
|
||||
|
||||
const toUpdate: AuthenticationEntity = await AuthenticationEntity.create(
|
||||
createAuthenticationProps,
|
||||
);
|
||||
await authenticationRepository.update(
|
||||
authenticationToUpdate.uuid,
|
||||
toUpdate,
|
||||
);
|
||||
|
||||
const updatedAuthentication = await prismaService.auth.findUnique({
|
||||
where: {
|
||||
uuid: toUpdate.id,
|
||||
},
|
||||
});
|
||||
|
||||
expect(updatedAuthentication.uuid).toBe(uuid);
|
||||
expect(authenticationToUpdate.updatedAt.getTime()).toBeLessThan(
|
||||
updatedAuthentication.updatedAt.getTime(),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw a DatabaseException if id is unknown', async () => {
|
||||
const toUpdate: AuthenticationEntity = await AuthenticationEntity.create(
|
||||
createAuthenticationProps,
|
||||
);
|
||||
|
||||
await expect(
|
||||
authenticationRepository.update(
|
||||
'544572be-11fb-4244-8235-587221fc9104',
|
||||
toUpdate,
|
||||
),
|
||||
).rejects.toBeInstanceOf(DatabaseErrorException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete', () => {
|
||||
it('should delete an authentication', async () => {
|
||||
await prismaService.auth.create({
|
||||
data: {
|
||||
uuid,
|
||||
password: bcrypt.hashSync(`password`, 10),
|
||||
},
|
||||
});
|
||||
const toDelete: AuthenticationEntity = await AuthenticationEntity.create(
|
||||
createAuthenticationProps,
|
||||
);
|
||||
await authenticationRepository.delete(toDelete);
|
||||
|
||||
const count = await prismaService.auth.count();
|
||||
expect(count).toBe(0);
|
||||
});
|
||||
|
||||
it('should throw a DatabaseException if authentication does not exist', async () => {
|
||||
const toDelete: AuthenticationEntity = await AuthenticationEntity.create(
|
||||
createAuthenticationProps,
|
||||
);
|
||||
await expect(
|
||||
authenticationRepository.delete(toDelete),
|
||||
).rejects.toBeInstanceOf(DatabaseErrorException);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,202 @@
|
|||
import { TestingModule, Test } from '@nestjs/testing';
|
||||
import { PrismaService } from '@modules/authentication/infrastructure/prisma.service';
|
||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||
import { MESSAGE_PUBLISHER } from '@src/app.di-tokens';
|
||||
import {
|
||||
DatabaseErrorException,
|
||||
NotFoundException,
|
||||
UniqueConstraintException,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import {
|
||||
CreateUsernameProps,
|
||||
Type,
|
||||
} from '@modules/authentication/core/domain/username.types';
|
||||
import { UsernameRepository } from '@modules/authentication/infrastructure/username.repository';
|
||||
import { UsernameMapper } from '@modules/authentication/username.mapper';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { UsernameEntity } from '@modules/authentication/core/domain/username.entity';
|
||||
|
||||
const authUuid = 'a4524d22-7be3-46cd-8444-3145470476dc';
|
||||
|
||||
const createUsernameProps: CreateUsernameProps = {
|
||||
userId: authUuid,
|
||||
type: Type.EMAIL,
|
||||
name: 'john.doe@email.com',
|
||||
};
|
||||
|
||||
const mockMessagePublisher = {
|
||||
publish: jest.fn().mockImplementation(),
|
||||
};
|
||||
|
||||
const mockLogger = {
|
||||
log: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
error: jest.fn(),
|
||||
};
|
||||
|
||||
describe('UsernameRepository', () => {
|
||||
let prismaService: PrismaService;
|
||||
let usernameRepository: UsernameRepository;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [EventEmitterModule.forRoot()],
|
||||
providers: [
|
||||
UsernameRepository,
|
||||
PrismaService,
|
||||
UsernameMapper,
|
||||
{
|
||||
provide: MESSAGE_PUBLISHER,
|
||||
useValue: mockMessagePublisher,
|
||||
},
|
||||
],
|
||||
})
|
||||
// disable logging
|
||||
.setLogger(mockLogger)
|
||||
.compile();
|
||||
|
||||
prismaService = module.get<PrismaService>(PrismaService);
|
||||
usernameRepository = module.get<UsernameRepository>(UsernameRepository);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await prismaService.$disconnect();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await prismaService.username.deleteMany();
|
||||
await prismaService.auth.deleteMany();
|
||||
await prismaService.auth.create({
|
||||
data: {
|
||||
uuid: authUuid,
|
||||
password: bcrypt.hashSync(`password`, 10),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe('findOne', () => {
|
||||
it('should return a Username', async () => {
|
||||
await prismaService.username.create({
|
||||
data: {
|
||||
authUuid,
|
||||
username: 'john.doe@email.com',
|
||||
type: Type.EMAIL,
|
||||
},
|
||||
});
|
||||
|
||||
const username = await usernameRepository.findOne({
|
||||
username: 'john.doe@email.com',
|
||||
});
|
||||
expect(username.id).toBe('john.doe@email.com');
|
||||
});
|
||||
|
||||
it('should throw an exception if record is not found', async () => {
|
||||
await expect(
|
||||
usernameRepository.findOne({
|
||||
username: 'jane.doe@email.com',
|
||||
}),
|
||||
).rejects.toBeInstanceOf(NotFoundException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('should create a username', async () => {
|
||||
const beforeCount = await prismaService.username.count();
|
||||
|
||||
const usernameToCreate: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
await usernameRepository.insert(usernameToCreate);
|
||||
|
||||
const afterCount = await prismaService.username.count();
|
||||
|
||||
expect(afterCount - beforeCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should throw a UniqueConstraintException if username already exists', async () => {
|
||||
await prismaService.username.create({
|
||||
data: {
|
||||
authUuid,
|
||||
type: Type.EMAIL,
|
||||
username: 'john.doe@email.com',
|
||||
},
|
||||
});
|
||||
|
||||
const usernameToCreate: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
await expect(
|
||||
usernameRepository.insert(usernameToCreate),
|
||||
).rejects.toBeInstanceOf(UniqueConstraintException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('update username', () => {
|
||||
it('should update the name of a username', async () => {
|
||||
const usernameToUpdate = await prismaService.username.create({
|
||||
data: {
|
||||
authUuid,
|
||||
type: Type.EMAIL,
|
||||
username: 'johnny.doe@email.com',
|
||||
},
|
||||
});
|
||||
|
||||
const toUpdate: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
await usernameRepository.updateUsername(
|
||||
usernameToUpdate.username,
|
||||
toUpdate,
|
||||
);
|
||||
|
||||
const updatedUsername = await prismaService.username.findUnique({
|
||||
where: {
|
||||
username: toUpdate.id,
|
||||
},
|
||||
});
|
||||
|
||||
expect(updatedUsername.username).toBe('john.doe@email.com');
|
||||
expect(usernameToUpdate.updatedAt.getTime()).toBeLessThan(
|
||||
updatedUsername.updatedAt.getTime(),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw a DatabaseException if id is unknown', async () => {
|
||||
const toUpdate: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
|
||||
await expect(
|
||||
usernameRepository.updateUsername('jane.doe@email.com', toUpdate),
|
||||
).rejects.toBeInstanceOf(DatabaseErrorException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete', () => {
|
||||
it('should delete a username', async () => {
|
||||
await prismaService.username.create({
|
||||
data: {
|
||||
authUuid,
|
||||
type: Type.EMAIL,
|
||||
username: 'john.doe@email.com',
|
||||
},
|
||||
});
|
||||
const toDelete: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
await usernameRepository.delete(toDelete);
|
||||
|
||||
const count = await prismaService.username.count();
|
||||
expect(count).toBe(0);
|
||||
});
|
||||
|
||||
it('should throw a DatabaseException if username does not exist', async () => {
|
||||
const toDelete: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
await expect(usernameRepository.delete(toDelete)).rejects.toBeInstanceOf(
|
||||
DatabaseErrorException,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -2,6 +2,7 @@ import { USERNAME_REPOSITORY } from '@modules/authentication/authentication.di-t
|
|||
import { DeleteUsernameCommand } from '@modules/authentication/core/application/commands/delete-username/delete-username.command';
|
||||
import { DeleteUsernameService } from '@modules/authentication/core/application/commands/delete-username/delete-username.service';
|
||||
import { DeleteUsernameRequestDto } from '@modules/authentication/interface/grpc-controllers/dtos/delete-username.request.dto';
|
||||
import { UnauthorizedException } from '@nestjs/common';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
const deleteUsernameRequest: DeleteUsernameRequestDto = {
|
||||
|
@ -10,11 +11,18 @@ const deleteUsernameRequest: DeleteUsernameRequestDto = {
|
|||
|
||||
const mockUsernameEntity = {
|
||||
delete: jest.fn(),
|
||||
getProps: jest.fn().mockImplementation(() => ({
|
||||
userId: 'b1643072-757f-4e3b-87f2-63af3684afb8',
|
||||
})),
|
||||
};
|
||||
|
||||
const mockUsernameRepository = {
|
||||
findOneById: jest.fn().mockImplementation(() => mockUsernameEntity),
|
||||
delete: jest.fn().mockImplementationOnce(() => true),
|
||||
findByName: jest.fn().mockImplementation(() => mockUsernameEntity),
|
||||
countUsernames: jest
|
||||
.fn()
|
||||
.mockImplementationOnce(() => 2)
|
||||
.mockImplementationOnce(() => 1),
|
||||
deleteUsername: jest.fn().mockImplementationOnce(() => true),
|
||||
};
|
||||
|
||||
describe('Delete Username Service', () => {
|
||||
|
@ -50,5 +58,10 @@ describe('Delete Username Service', () => {
|
|||
);
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
it('should throw an exception when trying to delete the last username', async () => {
|
||||
await expect(
|
||||
deleteUsernameService.execute(deleteUsernameCommand),
|
||||
).rejects.toBeInstanceOf(UnauthorizedException);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,8 +22,9 @@ const mockPrismaService = {
|
|||
};
|
||||
return record;
|
||||
}),
|
||||
|
||||
update: jest.fn().mockImplementation(),
|
||||
delete: jest.fn().mockImplementation(),
|
||||
count: jest.fn().mockImplementation(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -67,6 +68,7 @@ describe('Username repository', () => {
|
|||
it('should be defined', () => {
|
||||
expect(usernameRepository).toBeDefined();
|
||||
});
|
||||
|
||||
it('should find a username by its userId and Type', async () => {
|
||||
jest.spyOn(usernameRepository, 'findOne');
|
||||
const username: UsernameEntity = await usernameRepository.findByType(
|
||||
|
@ -80,6 +82,7 @@ describe('Username repository', () => {
|
|||
});
|
||||
expect(username.getProps().name).toBe('john.doe@email.com');
|
||||
});
|
||||
|
||||
it('should find a username by its name', async () => {
|
||||
jest.spyOn(usernameRepository, 'findOne');
|
||||
const username: UsernameEntity = await usernameRepository.findByName(
|
||||
|
@ -91,8 +94,9 @@ describe('Username repository', () => {
|
|||
});
|
||||
expect(username.getProps().name).toBe('john.doe@email.com');
|
||||
});
|
||||
|
||||
it('should update a username', async () => {
|
||||
jest.spyOn(usernameRepository, 'updateWhere');
|
||||
jest.spyOn(usernameRepository, 'update');
|
||||
const usernameToUpdate: UsernameEntity = await UsernameEntity.create({
|
||||
userId: '165192d4-398a-4469-a16b-98c02cc6f531',
|
||||
type: Type.EMAIL,
|
||||
|
@ -102,12 +106,35 @@ describe('Username repository', () => {
|
|||
'john.doe@email.com',
|
||||
usernameToUpdate,
|
||||
);
|
||||
expect(usernameRepository.updateWhere).toHaveBeenCalledTimes(1);
|
||||
expect(usernameRepository.updateWhere).toHaveBeenCalledWith(
|
||||
{
|
||||
username: 'john.doe@email.com',
|
||||
},
|
||||
expect(usernameRepository.update).toHaveBeenCalledTimes(1);
|
||||
expect(usernameRepository.update).toHaveBeenCalledWith(
|
||||
'john.doe@email.com',
|
||||
usernameToUpdate,
|
||||
'username',
|
||||
);
|
||||
});
|
||||
|
||||
it('should delete a username', async () => {
|
||||
jest.spyOn(usernameRepository, 'delete');
|
||||
const usernameToDelete: UsernameEntity = await UsernameEntity.create({
|
||||
userId: '165192d4-398a-4469-a16b-98c02cc6f531',
|
||||
type: Type.EMAIL,
|
||||
name: 'john.doe@new-email.com',
|
||||
});
|
||||
await usernameRepository.deleteUsername(usernameToDelete);
|
||||
expect(usernameRepository.delete).toHaveBeenCalledTimes(1);
|
||||
expect(usernameRepository.delete).toHaveBeenCalledWith(
|
||||
usernameToDelete,
|
||||
'username',
|
||||
);
|
||||
});
|
||||
|
||||
it('should count usernames for a given userId', async () => {
|
||||
jest.spyOn(usernameRepository, 'count');
|
||||
await usernameRepository.countUsernames('john.doe@email.com');
|
||||
expect(usernameRepository.count).toHaveBeenCalledTimes(1);
|
||||
expect(usernameRepository.count).toHaveBeenCalledWith({
|
||||
authUuid: 'john.doe@email.com',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
import { RpcExceptionCode } from '@mobicoop/ddd-library';
|
||||
import { DeleteUsernameGrpcController } from '@modules/authentication/interface/grpc-controllers/delete-username.grpc.controller';
|
||||
import { DeleteUsernameRequestDto } from '@modules/authentication/interface/grpc-controllers/dtos/delete-username.request.dto';
|
||||
import { UnauthorizedException } from '@nestjs/common';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { RpcException } from '@nestjs/microservices';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
@ -17,6 +18,9 @@ const mockCommandBus = {
|
|||
execute: jest
|
||||
.fn()
|
||||
.mockImplementationOnce(() => ({}))
|
||||
.mockImplementationOnce(() => {
|
||||
throw new UnauthorizedException();
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
throw new NotFoundException();
|
||||
})
|
||||
|
@ -61,6 +65,18 @@ describe('Delete Username Grpc Controller', () => {
|
|||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a dedicated RpcException when trying to delete the last username', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
expect.assertions(3);
|
||||
try {
|
||||
await deleteUsernameGrpcController.delete(deleteUsernameRequest);
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(RpcException);
|
||||
expect(e.error.code).toBe(RpcExceptionCode.PERMISSION_DENIED);
|
||||
}
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a dedicated RpcException if username does not exist', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
expect.assertions(3);
|
||||
|
|
Loading…
Reference in New Issue