feat: 开发user、auth相关接口,初始化后台管理项目admin
This commit is contained in:
293
apps/api/test/modules/user/user.service.integration.spec.ts
Normal file
293
apps/api/test/modules/user/user.service.integration.spec.ts
Normal file
@@ -0,0 +1,293 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { UserService } from '../../../src/modules/user/user.service';
|
||||
import { User } from '../../../src/modules/user/user.entity';
|
||||
import { UserModule } from '../../../src/modules/user/user.module';
|
||||
import { CreateUserDto } from '../../../src/modules/user/dto/create-user.dto';
|
||||
import { getDatabaseConfig } from '../../../src/database/database.config';
|
||||
import { ConflictException } from '@nestjs/common';
|
||||
|
||||
describe('UserService (集成测试)', () => {
|
||||
let service: UserService;
|
||||
let repository: Repository<User>;
|
||||
let module: TestingModule;
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.setTimeout(30000); // 设置超时为 30 秒
|
||||
// 创建测试模块,使用真实数据库连接
|
||||
module = await Test.createTestingModule({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
envFilePath: ['.env.development', '.env'],
|
||||
}),
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
useFactory: (configService: ConfigService) => {
|
||||
const config = getDatabaseConfig(configService);
|
||||
// 使用测试数据库(如果配置了),否则使用开发数据库
|
||||
const testDatabase =
|
||||
configService.get<string>('DB_DATABASE') ||
|
||||
(config.database as string);
|
||||
return {
|
||||
...config,
|
||||
database: testDatabase,
|
||||
synchronize: true, // 测试环境允许同步
|
||||
dropSchema: false, // 不删除现有数据
|
||||
} as typeof config;
|
||||
},
|
||||
inject: [ConfigService],
|
||||
}),
|
||||
UserModule,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<UserService>(UserService);
|
||||
repository = module.get<Repository<User>>(getRepositoryToken(User));
|
||||
|
||||
// 清理测试数据(可选)
|
||||
await repository.clear();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// 测试结束后清理
|
||||
// await repository.clear();
|
||||
await module.close();
|
||||
});
|
||||
|
||||
describe('create - 集成测试', () => {
|
||||
it('应该成功在数据库中创建用户', async () => {
|
||||
const createUserDto: CreateUserDto = {
|
||||
username: 'test_user_1',
|
||||
password: 'password123',
|
||||
email: 'test1@example.com',
|
||||
nickname: '测试用户1',
|
||||
};
|
||||
|
||||
const result = await service.create(createUserDto);
|
||||
console.log('regitser result', result);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.userId).toBeDefined();
|
||||
expect(result.username).toBe(createUserDto.username);
|
||||
expect(result.email).toBe(createUserDto.email);
|
||||
expect(result.nickname).toBe(createUserDto.nickname);
|
||||
expect(result.status).toBe('active');
|
||||
expect(result.role).toBe('user'); // 默认角色
|
||||
expect(result.passwordHash).toBeDefined();
|
||||
expect(result.passwordHash).not.toBe(createUserDto.password); // 密码应该被加密
|
||||
|
||||
// 验证数据确实保存到数据库
|
||||
const savedUser = await repository.findOne({
|
||||
where: { userId: result.userId },
|
||||
});
|
||||
expect(savedUser).toBeDefined();
|
||||
expect(savedUser?.username).toBe(createUserDto.username);
|
||||
expect(savedUser?.email).toBe(createUserDto.email);
|
||||
|
||||
// 清理
|
||||
await repository.remove(result);
|
||||
});
|
||||
|
||||
it('应该使用默认角色和状态', async () => {
|
||||
const createUserDto: CreateUserDto = {
|
||||
username: 'test_user_2',
|
||||
password: 'password123',
|
||||
email: 'test2@example.com',
|
||||
// 不提供 role
|
||||
};
|
||||
|
||||
const result = await service.create(createUserDto);
|
||||
|
||||
expect(result.role).toBe('user'); // 默认角色
|
||||
expect(result.status).toBe('active'); // 默认状态
|
||||
|
||||
// 清理
|
||||
// await repository.remove(result);
|
||||
});
|
||||
|
||||
it('应该支持可选字段', async () => {
|
||||
const createUserDto: CreateUserDto = {
|
||||
username: 'test_user_3',
|
||||
password: 'password123',
|
||||
email: 'test3@example.com',
|
||||
nickname: '测试用户3',
|
||||
avatarUrl: 'https://example.com/avatar.jpg',
|
||||
phone: '13800138000',
|
||||
};
|
||||
|
||||
const result = await service.create(createUserDto);
|
||||
|
||||
expect(result.nickname).toBe(createUserDto.nickname);
|
||||
expect(result.avatarUrl).toBe(createUserDto.avatarUrl);
|
||||
expect(result.phone).toBe(createUserDto.phone);
|
||||
|
||||
// 清理
|
||||
// await repository.remove(result);
|
||||
});
|
||||
|
||||
it('应该抛出 ConflictException 当用户名已存在时', async () => {
|
||||
const createUserDto: CreateUserDto = {
|
||||
username: 'duplicate_username',
|
||||
password: 'password123',
|
||||
email: 'unique@example.com',
|
||||
};
|
||||
|
||||
// 先创建一个用户
|
||||
await service.create(createUserDto);
|
||||
|
||||
// 尝试创建相同用户名的用户
|
||||
const duplicateDto: CreateUserDto = {
|
||||
username: 'duplicate_username',
|
||||
password: 'password456',
|
||||
email: 'another@example.com',
|
||||
};
|
||||
|
||||
await expect(service.create(duplicateDto)).rejects.toThrow(
|
||||
ConflictException,
|
||||
);
|
||||
await expect(service.create(duplicateDto)).rejects.toThrow(
|
||||
'用户名',
|
||||
);
|
||||
|
||||
// 清理
|
||||
// const user = await repository.findOne({ where: { username: 'duplicate_username' } });
|
||||
// if (user) await repository.remove(user);
|
||||
});
|
||||
|
||||
it('应该抛出 ConflictException 当邮箱已存在时', async () => {
|
||||
const createUserDto: CreateUserDto = {
|
||||
username: 'unique_username',
|
||||
password: 'password123',
|
||||
email: 'duplicate@example.com',
|
||||
};
|
||||
|
||||
// 先创建一个用户
|
||||
await service.create(createUserDto);
|
||||
|
||||
// 尝试创建相同邮箱的用户
|
||||
const duplicateDto: CreateUserDto = {
|
||||
username: 'another_username',
|
||||
password: 'password456',
|
||||
email: 'duplicate@example.com',
|
||||
};
|
||||
|
||||
await expect(service.create(duplicateDto)).rejects.toThrow(
|
||||
ConflictException,
|
||||
);
|
||||
await expect(service.create(duplicateDto)).rejects.toThrow('邮箱');
|
||||
|
||||
// 清理
|
||||
// const user = await repository.findOne({ where: { email: 'duplicate@example.com' } });
|
||||
// if (user) await repository.remove(user);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findAll - 集成测试', () => {
|
||||
it('应该返回所有用户列表', async () => {
|
||||
// 先创建几个测试用户
|
||||
const users: CreateUserDto[] = [
|
||||
{
|
||||
username: 'findall_user_1',
|
||||
password: 'password123',
|
||||
email: 'findall1@example.com',
|
||||
nickname: '查询测试用户1',
|
||||
},
|
||||
{
|
||||
username: 'findall_user_2',
|
||||
password: 'password123',
|
||||
email: 'findall2@example.com',
|
||||
nickname: '查询测试用户2',
|
||||
},
|
||||
{
|
||||
username: 'findall_user_3',
|
||||
password: 'password123',
|
||||
email: 'findall3@example.com',
|
||||
nickname: '查询测试用户3',
|
||||
role: 'admin',
|
||||
},
|
||||
];
|
||||
|
||||
const createdUsers: User[] = [];
|
||||
for (const userDto of users) {
|
||||
const user = await service.create(userDto);
|
||||
createdUsers.push(user);
|
||||
}
|
||||
|
||||
// 查询所有用户
|
||||
const result = await service.findAll();
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.length).toBeGreaterThanOrEqual(users.length);
|
||||
|
||||
// 验证创建的用户都在列表中
|
||||
const usernames = result.map((u) => u.username);
|
||||
users.forEach((userDto) => {
|
||||
expect(usernames).toContain(userDto.username);
|
||||
});
|
||||
|
||||
// 验证排序(按创建时间倒序)
|
||||
if (result.length > 1) {
|
||||
for (let i = 0; i < result.length - 1; i++) {
|
||||
expect(
|
||||
result[i].createdAt.getTime(),
|
||||
).toBeGreaterThanOrEqual(result[i + 1].createdAt.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
// 清理
|
||||
// await repository.remove(createdUsers);
|
||||
});
|
||||
|
||||
it('应该返回空数组当没有用户时', async () => {
|
||||
// 清理所有用户
|
||||
await repository.clear();
|
||||
|
||||
const result = await service.findAll();
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.length).toBe(0);
|
||||
});
|
||||
|
||||
it('应该包含用户的所有字段', async () => {
|
||||
// 创建一个完整信息的用户
|
||||
const createUserDto: CreateUserDto = {
|
||||
username: 'full_info_user',
|
||||
password: 'password123',
|
||||
email: 'fullinfo@example.com',
|
||||
nickname: '完整信息用户',
|
||||
avatarUrl: 'https://example.com/avatar.jpg',
|
||||
phone: '13800138000',
|
||||
role: 'admin',
|
||||
};
|
||||
|
||||
await service.create(createUserDto);
|
||||
|
||||
// 查询所有用户
|
||||
const result = await service.findAll();
|
||||
|
||||
const foundUser = result.find(
|
||||
(u) => u.username === createUserDto.username,
|
||||
);
|
||||
|
||||
expect(foundUser).toBeDefined();
|
||||
expect(foundUser?.userId).toBeDefined();
|
||||
expect(foundUser?.username).toBe(createUserDto.username);
|
||||
expect(foundUser?.email).toBe(createUserDto.email);
|
||||
expect(foundUser?.nickname).toBe(createUserDto.nickname);
|
||||
expect(foundUser?.avatarUrl).toBe(createUserDto.avatarUrl);
|
||||
expect(foundUser?.phone).toBe(createUserDto.phone);
|
||||
expect(foundUser?.role).toBe(createUserDto.role);
|
||||
expect(foundUser?.status).toBe('active');
|
||||
expect(foundUser?.createdAt).toBeDefined();
|
||||
expect(foundUser?.updatedAt).toBeDefined();
|
||||
|
||||
// 清理
|
||||
// if (foundUser) await repository.remove(foundUser);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user