forked from datawhale/whale-town-end
- 新增JWT认证守卫(JwtAuthGuard)和当前用户装饰器(CurrentUser) - 添加JWT使用示例和完整的认证流程文档 - 实现Zulip用户管理服务,支持用户查询、验证和管理 - 实现Zulip用户注册服务,支持新用户创建和注册流程 - 添加完整的单元测试覆盖 - 新增真实环境测试脚本,验证Zulip API集成 - 更新.gitignore,排除.kiro目录 主要功能: - JWT令牌验证和用户信息提取 - 用户存在性检查和信息获取 - Zulip API集成和错误处理 - 完整的测试覆盖和文档
188 lines
5.5 KiB
TypeScript
188 lines
5.5 KiB
TypeScript
/**
|
|
* Zulip用户注册服务测试
|
|
*
|
|
* 功能描述:
|
|
* - 测试UserRegistrationService的核心功能
|
|
* - 测试用户注册流程和验证逻辑
|
|
* - 测试错误处理和边界情况
|
|
*
|
|
* @author angjustinl
|
|
* @version 1.0.0
|
|
* @since 2025-01-06
|
|
*/
|
|
|
|
import { Test, TestingModule } from '@nestjs/testing';
|
|
import { UserRegistrationService, UserRegistrationRequest } from './user_registration.service';
|
|
import { IZulipConfigService } from '../interfaces/zulip-core.interfaces';
|
|
|
|
describe('UserRegistrationService', () => {
|
|
let service: UserRegistrationService;
|
|
let mockConfigService: jest.Mocked<IZulipConfigService>;
|
|
|
|
beforeEach(async () => {
|
|
// 创建模拟的配置服务
|
|
mockConfigService = {
|
|
getZulipConfig: jest.fn().mockReturnValue({
|
|
zulipServerUrl: 'https://test.zulip.com',
|
|
zulipBotEmail: 'bot@test.com',
|
|
zulipBotApiKey: 'test-api-key',
|
|
}),
|
|
getMapIdByStream: jest.fn(),
|
|
getStreamByMap: jest.fn(),
|
|
getMapConfig: jest.fn(),
|
|
hasMap: jest.fn(),
|
|
getAllMapIds: jest.fn(),
|
|
getMapConfigByStream: jest.fn(),
|
|
getAllStreams: jest.fn(),
|
|
hasStream: jest.fn(),
|
|
findObjectByTopic: jest.fn(),
|
|
getObjectsInMap: jest.fn(),
|
|
getTopicByObject: jest.fn(),
|
|
findNearbyObject: jest.fn(),
|
|
reloadConfig: jest.fn(),
|
|
validateConfig: jest.fn(),
|
|
getAllMapConfigs: jest.fn(),
|
|
getConfigStats: jest.fn(),
|
|
getConfigFilePath: jest.fn(),
|
|
configFileExists: jest.fn(),
|
|
enableConfigWatcher: jest.fn(),
|
|
disableConfigWatcher: jest.fn(),
|
|
isConfigWatcherEnabled: jest.fn(),
|
|
getFullConfiguration: jest.fn(),
|
|
updateConfigValue: jest.fn(),
|
|
exportMapConfig: jest.fn(),
|
|
} as jest.Mocked<IZulipConfigService>;
|
|
|
|
const module: TestingModule = await Test.createTestingModule({
|
|
providers: [
|
|
UserRegistrationService,
|
|
{
|
|
provide: 'ZULIP_CONFIG_SERVICE',
|
|
useValue: mockConfigService,
|
|
},
|
|
],
|
|
}).compile();
|
|
|
|
service = module.get<UserRegistrationService>(UserRegistrationService);
|
|
});
|
|
|
|
it('应该正确初始化服务', () => {
|
|
expect(service).toBeDefined();
|
|
});
|
|
|
|
describe('registerUser - 用户注册', () => {
|
|
it('应该成功注册有效用户', async () => {
|
|
const request: UserRegistrationRequest = {
|
|
email: 'test@example.com',
|
|
fullName: 'Test User',
|
|
password: 'password123',
|
|
};
|
|
|
|
const result = await service.registerUser(request);
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.email).toBe(request.email);
|
|
expect(result.userId).toBeDefined();
|
|
expect(result.apiKey).toBeDefined();
|
|
expect(result.error).toBeUndefined();
|
|
});
|
|
|
|
it('应该拒绝无效邮箱', async () => {
|
|
const request: UserRegistrationRequest = {
|
|
email: 'invalid-email',
|
|
fullName: 'Test User',
|
|
};
|
|
|
|
const result = await service.registerUser(request);
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toContain('邮箱格式无效');
|
|
});
|
|
|
|
it('应该拒绝空邮箱', async () => {
|
|
const request: UserRegistrationRequest = {
|
|
email: '',
|
|
fullName: 'Test User',
|
|
};
|
|
|
|
const result = await service.registerUser(request);
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toContain('邮箱不能为空');
|
|
});
|
|
|
|
it('应该拒绝空用户名', async () => {
|
|
const request: UserRegistrationRequest = {
|
|
email: 'test@example.com',
|
|
fullName: '',
|
|
};
|
|
|
|
const result = await service.registerUser(request);
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toContain('用户全名不能为空');
|
|
});
|
|
|
|
it('应该拒绝过短的用户名', async () => {
|
|
const request: UserRegistrationRequest = {
|
|
email: 'test@example.com',
|
|
fullName: 'A',
|
|
};
|
|
|
|
const result = await service.registerUser(request);
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toContain('用户全名至少需要2个字符');
|
|
});
|
|
|
|
it('应该拒绝过长的用户名', async () => {
|
|
const request: UserRegistrationRequest = {
|
|
email: 'test@example.com',
|
|
fullName: 'A'.repeat(101), // 101个字符
|
|
};
|
|
|
|
const result = await service.registerUser(request);
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toContain('用户全名不能超过100个字符');
|
|
});
|
|
|
|
it('应该拒绝过短的密码', async () => {
|
|
const request: UserRegistrationRequest = {
|
|
email: 'test@example.com',
|
|
fullName: 'Test User',
|
|
password: '123', // 只有3个字符
|
|
};
|
|
|
|
const result = await service.registerUser(request);
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toContain('密码至少需要6个字符');
|
|
});
|
|
|
|
it('应该接受没有密码的注册', async () => {
|
|
const request: UserRegistrationRequest = {
|
|
email: 'test@example.com',
|
|
fullName: 'Test User',
|
|
// 不提供密码
|
|
};
|
|
|
|
const result = await service.registerUser(request);
|
|
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
it('应该拒绝过长的短名称', async () => {
|
|
const request: UserRegistrationRequest = {
|
|
email: 'test@example.com',
|
|
fullName: 'Test User',
|
|
shortName: 'A'.repeat(51), // 51个字符
|
|
};
|
|
|
|
const result = await service.registerUser(request);
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toContain('短名称不能超过50个字符');
|
|
});
|
|
});
|
|
}); |