- 添加用户登录、注册、密码重置功能 - 支持用户名/邮箱/手机号多种登录方式 - 集成GitHub OAuth第三方登录 - 实现bcrypt密码加密存储 - 添加基于角色的权限控制 - 包含完整的数据验证和错误处理
174 lines
5.0 KiB
TypeScript
174 lines
5.0 KiB
TypeScript
/**
|
|
* 登录业务服务测试
|
|
*/
|
|
|
|
import { Test, TestingModule } from '@nestjs/testing';
|
|
import { LoginService } from './login.service';
|
|
import { LoginCoreService } from '../../core/login_core/login_core.service';
|
|
|
|
describe('LoginService', () => {
|
|
let service: LoginService;
|
|
let loginCoreService: jest.Mocked<LoginCoreService>;
|
|
|
|
const mockUser = {
|
|
id: BigInt(1),
|
|
username: 'testuser',
|
|
email: 'test@example.com',
|
|
phone: '+8613800138000',
|
|
password_hash: '$2b$12$hashedpassword',
|
|
nickname: '测试用户',
|
|
github_id: null as string | null,
|
|
avatar_url: null as string | null,
|
|
role: 1,
|
|
created_at: new Date(),
|
|
updated_at: new Date()
|
|
};
|
|
|
|
beforeEach(async () => {
|
|
const mockLoginCoreService = {
|
|
login: jest.fn(),
|
|
register: jest.fn(),
|
|
githubOAuth: jest.fn(),
|
|
sendPasswordResetCode: jest.fn(),
|
|
resetPassword: jest.fn(),
|
|
changePassword: jest.fn(),
|
|
};
|
|
|
|
const module: TestingModule = await Test.createTestingModule({
|
|
providers: [
|
|
LoginService,
|
|
{
|
|
provide: LoginCoreService,
|
|
useValue: mockLoginCoreService,
|
|
},
|
|
],
|
|
}).compile();
|
|
|
|
service = module.get<LoginService>(LoginService);
|
|
loginCoreService = module.get(LoginCoreService);
|
|
});
|
|
|
|
it('should be defined', () => {
|
|
expect(service).toBeDefined();
|
|
});
|
|
|
|
describe('login', () => {
|
|
it('should return success response for valid login', async () => {
|
|
loginCoreService.login.mockResolvedValue({
|
|
user: mockUser,
|
|
isNewUser: false
|
|
});
|
|
|
|
const result = await service.login({
|
|
identifier: 'testuser',
|
|
password: 'password123'
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.data?.user.username).toBe('testuser');
|
|
expect(result.data?.access_token).toBeDefined();
|
|
});
|
|
|
|
it('should return error response for failed login', async () => {
|
|
loginCoreService.login.mockRejectedValue(new Error('登录失败'));
|
|
|
|
const result = await service.login({
|
|
identifier: 'testuser',
|
|
password: 'wrongpassword'
|
|
});
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.message).toBe('登录失败');
|
|
expect(result.error_code).toBe('LOGIN_FAILED');
|
|
});
|
|
});
|
|
|
|
describe('register', () => {
|
|
it('should return success response for valid registration', async () => {
|
|
loginCoreService.register.mockResolvedValue({
|
|
user: mockUser,
|
|
isNewUser: true
|
|
});
|
|
|
|
const result = await service.register({
|
|
username: 'testuser',
|
|
password: 'password123',
|
|
nickname: '测试用户'
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.data?.user.username).toBe('testuser');
|
|
expect(result.data?.is_new_user).toBe(true);
|
|
});
|
|
|
|
it('should return error response for failed registration', async () => {
|
|
loginCoreService.register.mockRejectedValue(new Error('用户名已存在'));
|
|
|
|
const result = await service.register({
|
|
username: 'existinguser',
|
|
password: 'password123',
|
|
nickname: '测试用户'
|
|
});
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.message).toBe('用户名已存在');
|
|
expect(result.error_code).toBe('REGISTER_FAILED');
|
|
});
|
|
});
|
|
|
|
describe('githubOAuth', () => {
|
|
it('should return success response for GitHub OAuth', async () => {
|
|
loginCoreService.githubOAuth.mockResolvedValue({
|
|
user: mockUser,
|
|
isNewUser: true
|
|
});
|
|
|
|
const result = await service.githubOAuth({
|
|
github_id: 'github123',
|
|
username: 'githubuser',
|
|
nickname: 'GitHub用户'
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.data?.user.username).toBe('testuser');
|
|
expect(result.data?.is_new_user).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('sendPasswordResetCode', () => {
|
|
it('should return success response with verification code', async () => {
|
|
loginCoreService.sendPasswordResetCode.mockResolvedValue('123456');
|
|
|
|
const result = await service.sendPasswordResetCode('test@example.com');
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.data?.verification_code).toBe('123456');
|
|
});
|
|
});
|
|
|
|
describe('resetPassword', () => {
|
|
it('should return success response for password reset', async () => {
|
|
loginCoreService.resetPassword.mockResolvedValue(mockUser);
|
|
|
|
const result = await service.resetPassword({
|
|
identifier: 'test@example.com',
|
|
verificationCode: '123456',
|
|
newPassword: 'newpassword123'
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.message).toBe('密码重置成功');
|
|
});
|
|
});
|
|
|
|
describe('changePassword', () => {
|
|
it('should return success response for password change', async () => {
|
|
loginCoreService.changePassword.mockResolvedValue(mockUser);
|
|
|
|
const result = await service.changePassword(BigInt(1), 'oldpassword', 'newpassword123');
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.message).toBe('密码修改成功');
|
|
});
|
|
});
|
|
}); |