Merge branch 'betterTest' into 'main'

better tests

See merge request v3/services/auth!5
This commit is contained in:
Sylvain Briat 2023-01-11 11:56:25 +00:00
commit 88a6b58af9
9 changed files with 125 additions and 51 deletions

View File

@ -7,7 +7,7 @@ stages:
# TEST STAGE # # TEST STAGE #
############## ##############
integration-test: test:
stage: test stage: test
image: docker/compose:latest image: docker/compose:latest
variables: variables:
@ -17,7 +17,6 @@ integration-test:
script: script:
- docker-compose -f docker-compose.ci.yml --env-file ci/.env.ci up -d - docker-compose -f docker-compose.ci.yml --env-file ci/.env.ci up -d
- sh ci/wait-up.sh - sh ci/wait-up.sh
- docker-compose -f docker-compose.ci.yml --env-file ci/.env.ci logs
- docker exec -t v3-auth sh -c "npm run test:integration:ci" - docker exec -t v3-auth sh -c "npm run test:integration:ci"
coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/ coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
rules: rules:

View File

@ -19,7 +19,7 @@
"test:unit:ci": "jest --testPathPattern 'tests/unit/' --coverage", "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",
"test:integration:ci": "npm run migrate:test:ci && dotenv -e ci/.env.ci -- jest --testPathPattern 'tests/integration/'", "test:integration:ci": "npm run migrate:test:ci && dotenv -e ci/.env.ci -- jest --testPathPattern 'tests/integration/'",
"test:cov": "npm run migrate:test && dotenv -e .env.test -- jest --coverage", "test:cov": "jest --testPathPattern 'tests/unit/' --coverage",
"test:e2e": "jest --config ./test/jest-e2e.json", "test:e2e": "jest --config ./test/jest-e2e.json",
"migrate": "docker exec v3-auth sh -c 'npx prisma migrate dev'", "migrate": "docker exec v3-auth sh -c 'npx prisma migrate dev'",
"migrate:test": "dotenv -e .env.test -- npx prisma migrate deploy", "migrate:test": "dotenv -e .env.test -- npx prisma migrate deploy",
@ -80,6 +80,7 @@
"json", "json",
"ts" "ts"
], ],
"modulePathIgnorePatterns": [".controller.ts",".module.ts"],
"rootDir": "src", "rootDir": "src",
"testRegex": ".*\\.spec\\.ts$", "testRegex": ".*\\.spec\\.ts$",
"transform": { "transform": {

View File

@ -20,7 +20,14 @@ const addUsernameCommand: AddUsernameCommand = new AddUsernameCommand(
); );
const mockUsernameRepository = { const mockUsernameRepository = {
create: jest.fn().mockResolvedValue(addUsernameRequest), create: jest
.fn()
.mockImplementationOnce(() => {
return Promise.resolve(addUsernameRequest);
})
.mockImplementation(() => {
throw new Error('Already exists');
}),
}; };
const mockMessager = { const mockMessager = {
@ -63,5 +70,10 @@ describe('AddUsernameUseCase', () => {
expect(addedUsername.username).toBe(addUsernameRequest.username); expect(addedUsername.username).toBe(addUsernameRequest.username);
expect(addedUsername.type).toBe(addUsernameRequest.type); expect(addedUsername.type).toBe(addUsernameRequest.type);
}); });
it('should throw an error if user already exists', async () => {
await expect(
addUsernameUseCase.execute(addUsernameCommand),
).rejects.toBeInstanceOf(Error);
});
}); });
}); });

View File

@ -11,18 +11,24 @@ import { UsernameRepository } from '../../adapters/secondaries/username.reposito
import { Type } from '../../domain/dtos/type.enum'; import { Type } from '../../domain/dtos/type.enum';
import { LoggingMessager } from '../../adapters/secondaries/logging.messager'; import { LoggingMessager } from '../../adapters/secondaries/logging.messager';
const newAuthRequest: CreateAuthRequest = { const newAuthRequest: CreateAuthRequest = new CreateAuthRequest();
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91', newAuthRequest.uuid = 'bb281075-1b98-4456-89d6-c643d3044a91';
username: 'john.doe@email.com', newAuthRequest.username = 'john.doe@email.com';
password: 'John123', newAuthRequest.password = 'John123';
type: Type.EMAIL, newAuthRequest.type = Type.EMAIL;
};
const newAuthCommand: CreateAuthCommand = new CreateAuthCommand(newAuthRequest); const newAuthCommand: CreateAuthCommand = new CreateAuthCommand(newAuthRequest);
const mockAuthRepository = { const mockAuthRepository = {
create: jest.fn().mockResolvedValue({ create: jest
.fn()
.mockImplementationOnce(() => {
return Promise.resolve({
uuid: newAuthRequest.uuid, uuid: newAuthRequest.uuid,
password: bcrypt.hashSync(newAuthRequest.password, 10), password: bcrypt.hashSync(newAuthRequest.password, 10),
});
})
.mockImplementation(() => {
throw new Error('Already exists');
}), }),
}; };
@ -76,5 +82,10 @@ describe('CreateAuthUseCase', () => {
bcrypt.compareSync(newAuthRequest.password, newAuth.password), bcrypt.compareSync(newAuthRequest.password, newAuth.password),
).toBeTruthy(); ).toBeTruthy();
}); });
it('should throw an error if user already exists', async () => {
await expect(
createAuthUseCase.execute(newAuthCommand),
).rejects.toBeInstanceOf(Error);
});
}); });
}); });

View File

@ -25,15 +25,19 @@ const usernames = {
total: 2, total: 2,
}; };
const deleteAuthRequest: DeleteAuthRequest = { const deleteAuthRequest: DeleteAuthRequest = new DeleteAuthRequest();
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91', deleteAuthRequest.uuid = 'bb281075-1b98-4456-89d6-c643d3044a91';
};
const deleteAuthCommand: DeleteAuthCommand = new DeleteAuthCommand( const deleteAuthCommand: DeleteAuthCommand = new DeleteAuthCommand(
deleteAuthRequest, deleteAuthRequest,
); );
const mockAuthRepository = { const mockAuthRepository = {
delete: jest.fn().mockResolvedValue(undefined), delete: jest
.fn()
.mockResolvedValueOnce(undefined)
.mockImplementation(() => {
throw new Error('Error');
}),
}; };
const mockUsernameRepository = { const mockUsernameRepository = {
@ -85,5 +89,10 @@ describe('DeleteAuthUseCase', () => {
expect(deletedAuth).toBe(undefined); expect(deletedAuth).toBe(undefined);
}); });
it('should throw an error if auth does not exist', async () => {
await expect(
deleteAuthUseCase.execute(deleteAuthCommand),
).rejects.toBeInstanceOf(Error);
});
}); });
}); });

View File

@ -36,13 +36,13 @@ const usernamesPhone = {
total: 1, total: 1,
}; };
const deleteUsernameEmailRequest: DeleteUsernameRequest = { const deleteUsernameEmailRequest: DeleteUsernameRequest =
username: 'john.doe@email.com', new DeleteUsernameRequest();
}; deleteUsernameEmailRequest.username = 'john.doe@email.com';
const deleteUsernamePhoneRequest: DeleteUsernameRequest = { const deleteUsernamePhoneRequest: DeleteUsernameRequest =
username: '0611223344', new DeleteUsernameRequest();
}; deleteUsernamePhoneRequest.username = '0611223344';
const deleteUsernameEmailCommand: DeleteUsernameCommand = const deleteUsernameEmailCommand: DeleteUsernameCommand =
new DeleteUsernameCommand(deleteUsernameEmailRequest); new DeleteUsernameCommand(deleteUsernameEmailRequest);

View File

@ -9,18 +9,24 @@ import { UpdatePasswordCommand } from '../../commands/update-password.command';
import { UpdatePasswordUseCase } from '../../domain/usecases/update-password.usecase'; import { UpdatePasswordUseCase } from '../../domain/usecases/update-password.usecase';
import { LoggingMessager } from '../../adapters/secondaries/logging.messager'; import { LoggingMessager } from '../../adapters/secondaries/logging.messager';
const updatePasswordRequest: UpdatePasswordRequest = { const updatePasswordRequest: UpdatePasswordRequest =
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91', new UpdatePasswordRequest();
password: 'John123', updatePasswordRequest.uuid = 'bb281075-1b98-4456-89d6-c643d3044a91';
}; updatePasswordRequest.password = 'John123';
const updatePasswordCommand: UpdatePasswordCommand = new UpdatePasswordCommand( const updatePasswordCommand: UpdatePasswordCommand = new UpdatePasswordCommand(
updatePasswordRequest, updatePasswordRequest,
); );
const mockAuthRepository = { const mockAuthRepository = {
update: jest.fn().mockResolvedValue({ update: jest
.fn()
.mockResolvedValueOnce({
uuid: updatePasswordRequest.uuid, uuid: updatePasswordRequest.uuid,
password: bcrypt.hashSync(updatePasswordRequest.password, 10), password: bcrypt.hashSync(updatePasswordRequest.password, 10),
})
.mockImplementation(() => {
throw new Error('Error');
}), }),
}; };
@ -66,5 +72,10 @@ describe('UpdatePasswordUseCase', () => {
bcrypt.compareSync(updatePasswordRequest.password, newAuth.password), bcrypt.compareSync(updatePasswordRequest.password, newAuth.password),
).toBeTruthy(); ).toBeTruthy();
}); });
it('should throw an error if auth does not exist', async () => {
await expect(
updatePasswordUseCase.execute(updatePasswordCommand),
).rejects.toBeInstanceOf(Error);
});
}); });
}); });

View File

@ -18,23 +18,28 @@ const existingUsername = {
type: Type.EMAIL, type: Type.EMAIL,
}; };
const updateUsernameRequest: UpdateUsernameRequest = { const updateUsernameRequest: UpdateUsernameRequest =
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91', new UpdateUsernameRequest();
username: 'johnny.doe@email.com', updateUsernameRequest.uuid = 'bb281075-1b98-4456-89d6-c643d3044a91';
type: Type.EMAIL, updateUsernameRequest.username = 'johnny.doe@email.com';
}; updateUsernameRequest.type = Type.EMAIL;
const newUsernameRequest: UpdateUsernameRequest = { const newUsernameRequest: UpdateUsernameRequest = new UpdateUsernameRequest();
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91', newUsernameRequest.uuid = 'bb281075-1b98-4456-89d6-c643d3044a91';
username: '+33611223344', newUsernameRequest.username = '+33611223344';
type: Type.PHONE, newUsernameRequest.type = Type.PHONE;
};
const invalidUpdateUsernameRequest: UpdateUsernameRequest = { const invalidUpdateUsernameRequest: UpdateUsernameRequest =
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91', new UpdateUsernameRequest();
username: '', invalidUpdateUsernameRequest.uuid = 'bb281075-1b98-4456-89d6-c643d3044a91';
type: Type.EMAIL, invalidUpdateUsernameRequest.username = '';
}; invalidUpdateUsernameRequest.type = Type.EMAIL;
const unknownUsernameRequest: UpdateUsernameRequest =
new UpdateUsernameRequest();
unknownUsernameRequest.uuid = 'bb281075-1b98-4456-89d6-c643d3044a91';
unknownUsernameRequest.username = 'unknown@email.com';
unknownUsernameRequest.type = Type.EMAIL;
const updateUsernameCommand: UpdateUsernameCommand = new UpdateUsernameCommand( const updateUsernameCommand: UpdateUsernameCommand = new UpdateUsernameCommand(
updateUsernameRequest, updateUsernameRequest,
@ -47,13 +52,25 @@ const newUsernameCommand: UpdateUsernameCommand = new UpdateUsernameCommand(
const invalidUpdateUsernameCommand: UpdateUsernameCommand = const invalidUpdateUsernameCommand: UpdateUsernameCommand =
new UpdateUsernameCommand(invalidUpdateUsernameRequest); new UpdateUsernameCommand(invalidUpdateUsernameRequest);
const unknownUpdateUsernameCommand: UpdateUsernameCommand =
new UpdateUsernameCommand(unknownUsernameRequest);
const mockUsernameRepository = { const mockUsernameRepository = {
findOne: jest.fn().mockResolvedValue(existingUsername), findOne: jest.fn().mockResolvedValue(existingUsername),
updateWhere: jest updateWhere: jest
.fn() .fn()
.mockResolvedValueOnce(updateUsernameRequest) .mockImplementationOnce(() => {
.mockResolvedValueOnce(newUsernameRequest) return Promise.resolve(updateUsernameRequest);
.mockResolvedValueOnce(invalidUpdateUsernameRequest), })
.mockImplementationOnce(() => {
return Promise.resolve(newUsernameRequest);
})
.mockImplementationOnce(() => {
throw new Error('Error');
})
.mockImplementationOnce(() => {
return Promise.resolve(invalidUpdateUsernameRequest);
}),
}; };
const mockAddUsernameCommand = { const mockAddUsernameCommand = {
@ -116,6 +133,12 @@ describe('UpdateUsernameUseCase', () => {
expect(newUsername.type).toBe(newUsernameRequest.type); expect(newUsername.type).toBe(newUsernameRequest.type);
}); });
it('should throw an error if username does not exist', async () => {
await expect(
updateUsernameUseCase.execute(unknownUpdateUsernameCommand),
).rejects.toBeInstanceOf(Error);
});
it('should throw an exception if username is invalid', async () => { it('should throw an exception if username is invalid', async () => {
await expect( await expect(
updateUsernameUseCase.execute(invalidUpdateUsernameCommand), updateUsernameUseCase.execute(invalidUpdateUsernameCommand),

View File

@ -10,6 +10,7 @@ import { UsernameRepository } from '../../adapters/secondaries/username.reposito
import { Type } from '../../domain/dtos/type.enum'; import { Type } from '../../domain/dtos/type.enum';
import { NotFoundException, UnauthorizedException } from '@nestjs/common'; import { NotFoundException, UnauthorizedException } from '@nestjs/common';
import { DatabaseException } from '../../../database/src/exceptions/DatabaseException'; import { DatabaseException } from '../../../database/src/exceptions/DatabaseException';
import { ValidateAuthRequest } from '../../domain/dtos/validate-auth.request';
const mockAuthRepository = { const mockAuthRepository = {
findOne: jest findOne: jest
@ -70,8 +71,15 @@ describe('ValidateAuthUseCase', () => {
describe('execute', () => { describe('execute', () => {
it('should validate an auth and returns entity object', async () => { it('should validate an auth and returns entity object', async () => {
const validateAuthRequest: ValidateAuthRequest =
new ValidateAuthRequest();
validateAuthRequest.username = 'john.doe@email.com';
validateAuthRequest.password = 'John123';
const auth: Auth = await validateAuthUseCase.execute( const auth: Auth = await validateAuthUseCase.execute(
new ValidateAuthQuery('john.doe@email.com', 'John123'), new ValidateAuthQuery(
validateAuthRequest.username,
validateAuthRequest.password,
),
); );
expect(auth.uuid).toBe('bb281075-1b98-4456-89d6-c643d3044a91'); expect(auth.uuid).toBe('bb281075-1b98-4456-89d6-c643d3044a91');