feat: complete login and user management flow
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
function createPrismaMock() {
|
||||
const roles = new Map<string, { id: string; code: string; name: string; scope: string }>();
|
||||
return {
|
||||
user: {
|
||||
create: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'user-1', ...data, tenant: null, roles: [{ role: roles.get('platform_admin') ?? roles.get('enterprise_admin') }] })),
|
||||
findMany: jest.fn().mockResolvedValue([]),
|
||||
findFirst: jest.fn(),
|
||||
findUnique: jest.fn(),
|
||||
update: jest.fn(),
|
||||
},
|
||||
role: {
|
||||
upsert: jest.fn().mockImplementation(({ where, create, update }) => {
|
||||
const role = { id: `role-${where.code}`, ...create, ...update };
|
||||
roles.set(where.code, role);
|
||||
return Promise.resolve(role);
|
||||
}),
|
||||
findMany: jest.fn(),
|
||||
create: jest.fn(),
|
||||
},
|
||||
userRole: {
|
||||
upsert: jest.fn(),
|
||||
deleteMany: jest.fn(),
|
||||
create: jest.fn(),
|
||||
},
|
||||
permission: { findMany: jest.fn(), create: jest.fn() },
|
||||
rolePermission: { upsert: jest.fn() },
|
||||
operationLog: { create: jest.fn() },
|
||||
$transaction: jest.fn((callback) => callback({
|
||||
user: {
|
||||
update: jest.fn().mockResolvedValue({ id: 'user-1', username: 'u', roles: [] }),
|
||||
},
|
||||
userRole: {
|
||||
deleteMany: jest.fn(),
|
||||
create: jest.fn(),
|
||||
},
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
describe('UsersService', () => {
|
||||
it('requires enterprise admins to be linked to a tenant', async () => {
|
||||
const service = new UsersService(createPrismaMock() as never);
|
||||
await expect(service.create({
|
||||
displayName: '企业管理员',
|
||||
email: 'tenant@example.com',
|
||||
password: 'secret1',
|
||||
roleCode: 'enterprise_admin',
|
||||
})).rejects.toBeInstanceOf(BadRequestException);
|
||||
});
|
||||
|
||||
it('rejects platform admins linked to tenants', async () => {
|
||||
const service = new UsersService(createPrismaMock() as never);
|
||||
await expect(service.create({
|
||||
tenantId: 'tenant-1',
|
||||
displayName: '平台管理员',
|
||||
email: 'admin@example.com',
|
||||
password: 'secret1',
|
||||
roleCode: 'platform_admin',
|
||||
})).rejects.toThrow('platform_admin must not be linked to a tenant');
|
||||
});
|
||||
|
||||
it('creates platform admins and writes operation logs', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
const service = new UsersService(prisma as never);
|
||||
await service.create({
|
||||
displayName: '平台管理员',
|
||||
email: 'admin@example.com',
|
||||
phone: '13800000000',
|
||||
password: 'secret1',
|
||||
roleCode: 'platform_admin',
|
||||
operatorId: 'operator-1',
|
||||
});
|
||||
expect(prisma.user.create).toHaveBeenCalledWith(expect.objectContaining({
|
||||
data: expect.objectContaining({
|
||||
email: 'admin@example.com',
|
||||
phone: '13800000000',
|
||||
status: 'active',
|
||||
}),
|
||||
}));
|
||||
expect(prisma.operationLog.create).toHaveBeenCalledWith(expect.objectContaining({
|
||||
data: expect.objectContaining({ action: 'user.created', resource: 'user' }),
|
||||
}));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user