import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from '../auth.service';
import { JwtService } from '@app/jwt';
import { RedisService } from '../../../libs/redis/redis.service';
import { I18nContext, I18nService } from 'nestjs-i18n';
import { encry, User } from '@app/models';
import { getRepositoryToken } from '@nestjs/typeorm';
import { HttpException } from '@nestjs/common';
import { TokenService } from '../token.service';
import { ConfigService } from '@nestjs/config';
jest.mock('uuid', () => ({
v7: jest.fn(() => 'mocked-uuid-v7'),
}));
describe('AuthService', () => {
let service: AuthService;
const userRepository = {
findOne: jest.fn()
};
const jwtService = {
signAsync: jest.fn(),
verify: jest.fn(),
};
const redisService = {
getUserToken: jest.fn(),
delUserToken: jest.fn(),
setUserToken: jest.fn(),
};
const i18nService = {
translate: jest.fn(),
};
const tokenService = {
revokeToken: jest.fn(),
revokeByUid: jest.fn(),
createToken: jest.fn(),
getLastToken: jest.fn(),
accessTokenAlive: jest.fn(),
issueToken: jest.fn(),
getUserTokenCount: jest.fn(),
getTokenByJti: jest.fn(),
}
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
AuthService,
{
provide: getRepositoryToken(User),
useValue: userRepository,
},
{
provide: JwtService,
useValue: jwtService,
},
{
provide: RedisService,
useValue: redisService,
},
{
provide: I18nService,
useValue: i18nService,
},
{
provide: TokenService,
useValue: tokenService
},
{
provide: ConfigService,
useValue:{
get: jest.fn()
}
}
],
}).compile();
jest.spyOn(I18nContext, 'current').mockReturnValue({
lang: ''
} as any)
service = module.get<AuthService>(AuthService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('getToken', () => {
it('should return a token from Redis', async () => {
jest.spyOn(redisService, 'getUserToken').mockResolvedValue('test-token');
const token = await service.getToken('123');
expect(token).toBe('test-token');
expect(redisService.getUserToken).toHaveBeenCalledWith('user:123:token');
});
});
describe('kickOut', () => {
it('should delete a token from Redis', async () => {
jest.spyOn(redisService, 'delUserToken').mockResolvedValue(true);
await service.kickOut(1);
expect(tokenService.revokeByUid).toHaveBeenCalledWith(1);
});
});
describe('logout', () => {
it('should delete a token from Redis after verifying it', async () => {
jest.spyOn(jwtService, 'verify').mockResolvedValue({
payload: {
email: 'test@example.com',
id: 1,
jti: 'test-jti',
}
});
jest.spyOn(tokenService, 'getTokenByJti').mockResolvedValue('access-token');
jest.spyOn(tokenService, 'revokeToken').mockResolvedValue(undefined);
await service.logout('test-token');
expect(jwtService.verify).toHaveBeenCalledWith('test-token');
expect(tokenService.getTokenByJti).toHaveBeenCalledWith(1, 'test-jti', 'at');
expect(tokenService.revokeToken).toHaveBeenCalledWith('access-token');
});
});
describe('login', () => {
it('should throw an exception if user does not exist', async () => {
userRepository.findOne.mockResolvedValue(null)
jest.spyOn(i18nService, 'translate').mockReturnValue('User does not exist');
await expect(
service.login({ email: 'test@example.com', password: 'password' })
).rejects.toThrow(HttpException);
expect(i18nService.translate).toHaveBeenCalledWith('exception.auth.userNotExists', expect.any(Object));
});
it('should throw an exception if password is incorrect', async () => {
userRepository.findOne.mockResolvedValue({
email: 'test@example.com',
password: 'hashed-password',
salt: 'salt',
} as User)
jest.spyOn(i18nService, 'translate').mockReturnValue('Password or email error');
await expect(
service.login({ email: 'test@example.com', password: 'password' })
).rejects.toThrow(HttpException);
expect(i18nService.translate).toHaveBeenCalledWith('exception.auth.passwordOrEmailError', expect.any(Object));
});
it('should return a token if login is successful', async () => {
userRepository.findOne.mockResolvedValue({
id: 1,
email: 'test@example.com',
password: encry('hashed-password', 'salt'),
salt: 'salt',
} as User)
jest.spyOn(jwtService, 'signAsync').mockResolvedValue('test-token');
jest.spyOn(redisService, 'setUserToken').mockResolvedValue(true);
await service.login({ email: 'test@example.com', password: 'hashed-password' });
expect(tokenService.createToken).toHaveBeenCalledWith(1, 'test@example.com');
});
});
});