first commit
This commit is contained in:
@@ -0,0 +1,365 @@
|
||||
/**
|
||||
* Copyright 2025 LY Corporation
|
||||
*
|
||||
* LY Corporation licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { faker } from '@faker-js/faker';
|
||||
import {
|
||||
BadRequestException,
|
||||
InternalServerErrorException,
|
||||
} from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { getMockProvider } from '@/test-utils/util-functions';
|
||||
import { TenantService } from '../tenant/tenant.service';
|
||||
import { UserDto } from '../user/dtos';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { AuthService } from './auth.service';
|
||||
import {
|
||||
EmailUserSignUpRequestDto,
|
||||
EmailVerificationCodeRequestDto,
|
||||
EmailVerificationMailingRequestDto,
|
||||
InvitationUserSignUpRequestDto,
|
||||
OAuthUserSignUpRequestDto,
|
||||
} from './dtos/requests';
|
||||
|
||||
const MockAuthService = {
|
||||
sendEmailCode: jest.fn(),
|
||||
verifyEmailCode: jest.fn(),
|
||||
signUpEmailUser: jest.fn(),
|
||||
signUpInvitationUser: jest.fn(),
|
||||
signUpOAuthUser: jest.fn(),
|
||||
signIn: jest.fn(),
|
||||
signInByOAuth: jest.fn(),
|
||||
refreshToken: jest.fn(),
|
||||
getOAuthLoginURL: jest.fn(),
|
||||
};
|
||||
|
||||
const MockTenantService = {
|
||||
findOne: jest.fn(),
|
||||
};
|
||||
|
||||
describe('AuthController', () => {
|
||||
let authController: AuthController;
|
||||
let authService: jest.Mocked<AuthService>;
|
||||
let _tenantService: jest.Mocked<TenantService>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
providers: [
|
||||
getMockProvider(AuthService, MockAuthService),
|
||||
getMockProvider(TenantService, MockTenantService),
|
||||
],
|
||||
controllers: [AuthController],
|
||||
}).compile();
|
||||
|
||||
authController = module.get(AuthController);
|
||||
authService = module.get(AuthService);
|
||||
_tenantService = module.get(TenantService);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(authController).toBeDefined();
|
||||
});
|
||||
describe('sendCode', () => {
|
||||
it('should send email verification code successfully', async () => {
|
||||
const mockTimestamp = DateTime.utc().toISO();
|
||||
const dto = new EmailVerificationMailingRequestDto();
|
||||
dto.email = faker.internet.email();
|
||||
|
||||
authService.sendEmailCode.mockResolvedValue(mockTimestamp);
|
||||
|
||||
const result = await authController.sendCode(dto);
|
||||
|
||||
expect(authService.sendEmailCode).toHaveBeenCalledWith(dto);
|
||||
expect(authService.sendEmailCode).toHaveBeenCalledTimes(1);
|
||||
expect(result).toEqual({ expiredAt: mockTimestamp });
|
||||
});
|
||||
|
||||
it('should handle sendEmailCode errors', async () => {
|
||||
const dto = new EmailVerificationMailingRequestDto();
|
||||
dto.email = faker.internet.email();
|
||||
const error = new InternalServerErrorException(
|
||||
'Email service unavailable',
|
||||
);
|
||||
|
||||
authService.sendEmailCode.mockRejectedValue(error);
|
||||
|
||||
await expect(authController.sendCode(dto)).rejects.toThrow(
|
||||
InternalServerErrorException,
|
||||
);
|
||||
expect(authService.sendEmailCode).toHaveBeenCalledWith(dto);
|
||||
});
|
||||
|
||||
it('should handle invalid email format', async () => {
|
||||
const dto = new EmailVerificationMailingRequestDto();
|
||||
dto.email = 'invalid-email';
|
||||
const error = new BadRequestException('Invalid email format');
|
||||
|
||||
authService.sendEmailCode.mockRejectedValue(error);
|
||||
|
||||
await expect(authController.sendCode(dto)).rejects.toThrow(
|
||||
BadRequestException,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('verifyEmailCode', () => {
|
||||
it('should verify email code successfully', async () => {
|
||||
const dto = new EmailVerificationCodeRequestDto();
|
||||
dto.code = faker.string.alphanumeric(6);
|
||||
dto.email = faker.internet.email();
|
||||
|
||||
authService.verifyEmailCode.mockResolvedValue(undefined);
|
||||
|
||||
await authController.verifyEmailCode(dto);
|
||||
|
||||
expect(authService.verifyEmailCode).toHaveBeenCalledWith(dto);
|
||||
expect(authService.verifyEmailCode).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should handle invalid verification code', async () => {
|
||||
const dto = new EmailVerificationCodeRequestDto();
|
||||
dto.code = 'invalid-code';
|
||||
dto.email = faker.internet.email();
|
||||
const error = new BadRequestException('Invalid verification code');
|
||||
|
||||
authService.verifyEmailCode.mockRejectedValue(error);
|
||||
|
||||
await expect(authController.verifyEmailCode(dto)).rejects.toThrow(
|
||||
BadRequestException,
|
||||
);
|
||||
expect(authService.verifyEmailCode).toHaveBeenCalledWith(dto);
|
||||
});
|
||||
|
||||
it('should handle expired verification code', async () => {
|
||||
const dto = new EmailVerificationCodeRequestDto();
|
||||
dto.code = faker.string.alphanumeric(6);
|
||||
dto.email = faker.internet.email();
|
||||
const error = new BadRequestException('Verification code expired');
|
||||
|
||||
authService.verifyEmailCode.mockRejectedValue(error);
|
||||
|
||||
await expect(authController.verifyEmailCode(dto)).rejects.toThrow(
|
||||
BadRequestException,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('signUpEmailUser', () => {
|
||||
it('should sign up email user successfully', async () => {
|
||||
const dto = new EmailUserSignUpRequestDto();
|
||||
dto.email = faker.internet.email();
|
||||
dto.password = faker.internet.password();
|
||||
|
||||
authService.signUpEmailUser.mockResolvedValue(undefined as any);
|
||||
|
||||
const result = await authController.signUpEmailUser(dto);
|
||||
|
||||
expect(authService.signUpEmailUser).toHaveBeenCalledWith(dto);
|
||||
expect(authService.signUpEmailUser).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle email already exists error', async () => {
|
||||
const dto = new EmailUserSignUpRequestDto();
|
||||
dto.email = faker.internet.email();
|
||||
dto.password = faker.internet.password();
|
||||
const error = new BadRequestException('Email already exists');
|
||||
|
||||
authService.signUpEmailUser.mockRejectedValue(error);
|
||||
|
||||
await expect(authController.signUpEmailUser(dto)).rejects.toThrow(
|
||||
BadRequestException,
|
||||
);
|
||||
expect(authService.signUpEmailUser).toHaveBeenCalledWith(dto);
|
||||
});
|
||||
|
||||
it('should handle weak password error', async () => {
|
||||
const dto = new EmailUserSignUpRequestDto();
|
||||
dto.email = faker.internet.email();
|
||||
dto.password = '123'; // Weak password
|
||||
const error = new BadRequestException('Password is too weak');
|
||||
|
||||
authService.signUpEmailUser.mockRejectedValue(error);
|
||||
|
||||
await expect(authController.signUpEmailUser(dto)).rejects.toThrow(
|
||||
BadRequestException,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('signUpInvitationUser', () => {
|
||||
it('should sign up invitation user successfully', async () => {
|
||||
const dto = new InvitationUserSignUpRequestDto();
|
||||
dto.code = faker.string.alphanumeric(8);
|
||||
dto.email = faker.internet.email();
|
||||
dto.password = faker.internet.password();
|
||||
|
||||
authService.signUpInvitationUser.mockResolvedValue(undefined as any);
|
||||
|
||||
const result = await authController.signUpInvitationUser(dto);
|
||||
|
||||
expect(authService.signUpInvitationUser).toHaveBeenCalledWith(dto);
|
||||
expect(authService.signUpInvitationUser).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle invalid invitation code', async () => {
|
||||
const dto = new InvitationUserSignUpRequestDto();
|
||||
dto.code = 'invalid-code';
|
||||
dto.email = faker.internet.email();
|
||||
dto.password = faker.internet.password();
|
||||
const error = new BadRequestException('Invalid invitation code');
|
||||
|
||||
authService.signUpInvitationUser.mockRejectedValue(error);
|
||||
|
||||
await expect(authController.signUpInvitationUser(dto)).rejects.toThrow(
|
||||
BadRequestException,
|
||||
);
|
||||
expect(authService.signUpInvitationUser).toHaveBeenCalledWith(dto);
|
||||
});
|
||||
|
||||
it('should handle expired invitation', async () => {
|
||||
const dto = new InvitationUserSignUpRequestDto();
|
||||
dto.code = faker.string.alphanumeric(8);
|
||||
dto.email = faker.internet.email();
|
||||
dto.password = faker.internet.password();
|
||||
const error = new BadRequestException('Invitation has expired');
|
||||
|
||||
authService.signUpInvitationUser.mockRejectedValue(error);
|
||||
|
||||
await expect(authController.signUpInvitationUser(dto)).rejects.toThrow(
|
||||
BadRequestException,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('signInEmail', () => {
|
||||
it('should sign in email user successfully', () => {
|
||||
const user = new UserDto();
|
||||
user.id = faker.number.int();
|
||||
user.email = faker.internet.email();
|
||||
user.name = faker.person.fullName();
|
||||
const mockTokens = {
|
||||
accessToken: faker.string.alphanumeric(32),
|
||||
refreshToken: faker.string.alphanumeric(32),
|
||||
};
|
||||
|
||||
authService.signIn.mockReturnValue(mockTokens as any);
|
||||
|
||||
const result = authController.signInEmail(user);
|
||||
|
||||
expect(authService.signIn).toHaveBeenCalledWith(user);
|
||||
expect(authService.signIn).toHaveBeenCalledTimes(1);
|
||||
expect(result).toEqual(mockTokens);
|
||||
});
|
||||
});
|
||||
|
||||
describe('refreshToken', () => {
|
||||
it('should refresh token successfully', () => {
|
||||
const user = new UserDto();
|
||||
user.id = faker.number.int();
|
||||
user.email = faker.internet.email();
|
||||
user.name = faker.person.fullName();
|
||||
const mockTokens = {
|
||||
accessToken: faker.string.alphanumeric(32),
|
||||
refreshToken: faker.string.alphanumeric(32),
|
||||
};
|
||||
|
||||
authService.refreshToken.mockReturnValue(mockTokens as any);
|
||||
|
||||
const result = authController.refreshToken(user);
|
||||
|
||||
expect(authService.refreshToken).toHaveBeenCalledWith(user);
|
||||
expect(authService.refreshToken).toHaveBeenCalledTimes(1);
|
||||
expect(result).toEqual(mockTokens);
|
||||
});
|
||||
});
|
||||
|
||||
describe('signUpOAuthUser', () => {
|
||||
it('should sign up OAuth user successfully', async () => {
|
||||
const dto = new OAuthUserSignUpRequestDto();
|
||||
dto.email = faker.internet.email();
|
||||
dto.projectName = faker.company.name();
|
||||
dto.roleName = faker.person.jobTitle();
|
||||
|
||||
authService.signUpOAuthUser.mockResolvedValue(undefined);
|
||||
|
||||
const result = await authController.signUpOAuthUser(dto);
|
||||
|
||||
expect(authService.signUpOAuthUser).toHaveBeenCalledWith(dto);
|
||||
expect(authService.signUpOAuthUser).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle OAuth provider error', async () => {
|
||||
const dto = new OAuthUserSignUpRequestDto();
|
||||
dto.email = faker.internet.email();
|
||||
dto.projectName = faker.company.name();
|
||||
dto.roleName = faker.person.jobTitle();
|
||||
const error = new InternalServerErrorException('OAuth provider error');
|
||||
|
||||
authService.signUpOAuthUser.mockRejectedValue(error);
|
||||
|
||||
await expect(authController.signUpOAuthUser(dto)).rejects.toThrow(
|
||||
InternalServerErrorException,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('redirectToLoginURL', () => {
|
||||
it('should return OAuth login URL', async () => {
|
||||
const callbackUrl = faker.internet.url();
|
||||
const mockUrl = faker.internet.url();
|
||||
|
||||
authService.getOAuthLoginURL.mockResolvedValue(mockUrl);
|
||||
|
||||
const result = await authController.redirectToLoginURL(callbackUrl);
|
||||
|
||||
expect(authService.getOAuthLoginURL).toHaveBeenCalledWith(callbackUrl);
|
||||
expect(authService.getOAuthLoginURL).toHaveBeenCalledTimes(1);
|
||||
expect(result).toEqual({ url: mockUrl });
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleCallback', () => {
|
||||
it('should handle OAuth callback successfully', async () => {
|
||||
const query = { code: faker.string.alphanumeric(32) };
|
||||
const mockTokens = {
|
||||
accessToken: faker.string.alphanumeric(32),
|
||||
refreshToken: faker.string.alphanumeric(32),
|
||||
};
|
||||
|
||||
authService.signInByOAuth.mockResolvedValue(mockTokens);
|
||||
|
||||
const result = await authController.handleCallback(query);
|
||||
|
||||
expect(authService.signInByOAuth).toHaveBeenCalledWith(query.code);
|
||||
expect(authService.signInByOAuth).toHaveBeenCalledTimes(1);
|
||||
expect(result).toEqual(mockTokens);
|
||||
});
|
||||
|
||||
it('should handle OAuth authentication failure', async () => {
|
||||
const query = { code: 'invalid-code' };
|
||||
const error = new BadRequestException('OAuth authentication failed');
|
||||
|
||||
authService.signInByOAuth.mockRejectedValue(error);
|
||||
|
||||
await expect(authController.handleCallback(query)).rejects.toThrow(
|
||||
BadRequestException,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user