add tests
This commit is contained in:
30
apps/api/src/domain/admin/AdminModule.test.ts
Normal file
30
apps/api/src/domain/admin/AdminModule.test.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AdminController } from './AdminController';
|
||||
import { AdminModule } from './AdminModule';
|
||||
import { AdminService } from './AdminService';
|
||||
|
||||
describe('AdminModule', () => {
|
||||
let module: TestingModule;
|
||||
|
||||
beforeEach(async () => {
|
||||
module = await Test.createTestingModule({
|
||||
imports: [AdminModule],
|
||||
}).compile();
|
||||
});
|
||||
|
||||
it('should compile the module', () => {
|
||||
expect(module).toBeDefined();
|
||||
});
|
||||
|
||||
it('should provide AdminController', () => {
|
||||
const controller = module.get<AdminController>(AdminController);
|
||||
expect(controller).toBeDefined();
|
||||
expect(controller).toBeInstanceOf(AdminController);
|
||||
});
|
||||
|
||||
it('should provide AdminService', () => {
|
||||
const service = module.get<AdminService>(AdminService);
|
||||
expect(service).toBeDefined();
|
||||
expect(service).toBeInstanceOf(AdminService);
|
||||
});
|
||||
});
|
||||
40
apps/api/src/domain/admin/RequireSystemAdmin.test.ts
Normal file
40
apps/api/src/domain/admin/RequireSystemAdmin.test.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { SetMetadata } from '@nestjs/common';
|
||||
import { RequireSystemAdmin, REQUIRE_SYSTEM_ADMIN_METADATA_KEY } from './RequireSystemAdmin';
|
||||
|
||||
// Mock SetMetadata
|
||||
vi.mock('@nestjs/common', () => ({
|
||||
SetMetadata: vi.fn(() => () => {}),
|
||||
}));
|
||||
|
||||
describe('RequireSystemAdmin', () => {
|
||||
it('should return a method decorator', () => {
|
||||
const decorator = RequireSystemAdmin();
|
||||
expect(typeof decorator).toBe('function');
|
||||
});
|
||||
|
||||
it('should call SetMetadata with correct key and value', () => {
|
||||
RequireSystemAdmin();
|
||||
|
||||
expect(SetMetadata).toHaveBeenCalledWith(REQUIRE_SYSTEM_ADMIN_METADATA_KEY, {
|
||||
required: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a decorator that can be used as both method and class decorator', () => {
|
||||
const decorator = RequireSystemAdmin();
|
||||
|
||||
// Test as method decorator
|
||||
const mockTarget = {};
|
||||
const mockPropertyKey = 'testMethod';
|
||||
const mockDescriptor = { value: () => {} };
|
||||
|
||||
const result = decorator(mockTarget, mockPropertyKey, mockDescriptor);
|
||||
|
||||
// The decorator should return the descriptor
|
||||
expect(result).toBe(mockDescriptor);
|
||||
});
|
||||
|
||||
it('should have correct metadata key', () => {
|
||||
expect(REQUIRE_SYSTEM_ADMIN_METADATA_KEY).toBe('gridpilot:requireSystemAdmin');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,680 @@
|
||||
import { AdminUser } from '@core/admin/domain/entities/AdminUser';
|
||||
import { AuthorizationService } from '@core/admin/domain/services/AuthorizationService';
|
||||
import { Result } from '@core/shared/domain/Result';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { GetDashboardStatsUseCase } from './GetDashboardStatsUseCase';
|
||||
|
||||
// Mock dependencies
|
||||
const mockAdminUserRepo = {
|
||||
findById: vi.fn(),
|
||||
list: vi.fn(),
|
||||
};
|
||||
|
||||
describe('GetDashboardStatsUseCase', () => {
|
||||
describe('TDD - Test First', () => {
|
||||
let useCase: GetDashboardStatsUseCase;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
useCase = new GetDashboardStatsUseCase(mockAdminUserRepo as never);
|
||||
});
|
||||
|
||||
describe('execute', () => {
|
||||
it('should return error when actor is not found', async () => {
|
||||
// Arrange
|
||||
mockAdminUserRepo.findById.mockResolvedValue(null);
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('AUTHORIZATION_ERROR');
|
||||
expect(error.details.message).toBe('Actor not found');
|
||||
});
|
||||
|
||||
it('should return error when actor is not authorized to view dashboard', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('AUTHORIZATION_ERROR');
|
||||
expect(error.details.message).toBe('User is not authorized to view dashboard');
|
||||
});
|
||||
|
||||
it('should return empty stats when no users exist', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const stats = result.unwrap();
|
||||
expect(stats.totalUsers).toBe(0);
|
||||
expect(stats.activeUsers).toBe(0);
|
||||
expect(stats.suspendedUsers).toBe(0);
|
||||
expect(stats.deletedUsers).toBe(0);
|
||||
expect(stats.systemAdmins).toBe(0);
|
||||
expect(stats.recentLogins).toBe(0);
|
||||
expect(stats.newUsersToday).toBe(0);
|
||||
expect(stats.userGrowth).toEqual([]);
|
||||
expect(stats.roleDistribution).toEqual([]);
|
||||
expect(stats.statusDistribution).toEqual({
|
||||
active: 0,
|
||||
suspended: 0,
|
||||
deleted: 0,
|
||||
});
|
||||
expect(stats.activityTimeline).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return correct stats when users exist', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
const user1 = AdminUser.create({
|
||||
id: 'user-1',
|
||||
email: 'user1@example.com',
|
||||
displayName: 'User 1',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
const user2 = AdminUser.create({
|
||||
id: 'user-2',
|
||||
email: 'user2@example.com',
|
||||
displayName: 'User 2',
|
||||
roles: ['admin'],
|
||||
status: 'suspended',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
const user3 = AdminUser.create({
|
||||
id: 'user-3',
|
||||
email: 'user3@example.com',
|
||||
displayName: 'User 3',
|
||||
roles: ['owner'],
|
||||
status: 'deleted',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [user1, user2, user3] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const stats = result.unwrap();
|
||||
expect(stats.totalUsers).toBe(3);
|
||||
expect(stats.activeUsers).toBe(1);
|
||||
expect(stats.suspendedUsers).toBe(1);
|
||||
expect(stats.deletedUsers).toBe(1);
|
||||
expect(stats.systemAdmins).toBe(2); // actor + user3
|
||||
expect(stats.recentLogins).toBe(0); // no recent logins
|
||||
expect(stats.newUsersToday).toBe(3); // all created today
|
||||
expect(stats.userGrowth).toHaveLength(7);
|
||||
expect(stats.roleDistribution).toHaveLength(3);
|
||||
expect(stats.statusDistribution).toEqual({
|
||||
active: 1,
|
||||
suspended: 1,
|
||||
deleted: 1,
|
||||
});
|
||||
expect(stats.activityTimeline).toHaveLength(7);
|
||||
});
|
||||
|
||||
it('should count recent logins correctly', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
const recentLoginUser = AdminUser.create({
|
||||
id: 'user-1',
|
||||
email: 'user1@example.com',
|
||||
displayName: 'User 1',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: new Date(Date.now() - 86400000 * 2), // 2 days ago
|
||||
updatedAt: new Date(Date.now() - 86400000 * 2),
|
||||
lastLoginAt: new Date(Date.now() - 3600000), // 1 hour ago
|
||||
});
|
||||
|
||||
const oldLoginUser = AdminUser.create({
|
||||
id: 'user-2',
|
||||
email: 'user2@example.com',
|
||||
displayName: 'User 2',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: new Date(Date.now() - 86400000 * 2),
|
||||
updatedAt: new Date(Date.now() - 86400000 * 2),
|
||||
lastLoginAt: new Date(Date.now() - 86400000 * 2), // 2 days ago
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [recentLoginUser, oldLoginUser] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const stats = result.unwrap();
|
||||
expect(stats.recentLogins).toBe(1);
|
||||
});
|
||||
|
||||
it('should count new users today correctly', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
const todayUser = AdminUser.create({
|
||||
id: 'user-1',
|
||||
email: 'user1@example.com',
|
||||
displayName: 'User 1',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
const yesterdayUser = AdminUser.create({
|
||||
id: 'user-2',
|
||||
email: 'user2@example.com',
|
||||
displayName: 'User 2',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: new Date(Date.now() - 86400000),
|
||||
updatedAt: new Date(Date.now() - 86400000),
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [todayUser, yesterdayUser] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const stats = result.unwrap();
|
||||
expect(stats.newUsersToday).toBe(1);
|
||||
});
|
||||
|
||||
it('should calculate role distribution correctly', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
const user1 = AdminUser.create({
|
||||
id: 'user-1',
|
||||
email: 'user1@example.com',
|
||||
displayName: 'User 1',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
const user2 = AdminUser.create({
|
||||
id: 'user-2',
|
||||
email: 'user2@example.com',
|
||||
displayName: 'User 2',
|
||||
roles: ['admin'],
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
const user3 = AdminUser.create({
|
||||
id: 'user-3',
|
||||
email: 'user3@example.com',
|
||||
displayName: 'User 3',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [user1, user2, user3] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const stats = result.unwrap();
|
||||
expect(stats.roleDistribution).toHaveLength(3);
|
||||
expect(stats.roleDistribution).toContainEqual({
|
||||
label: 'Owner',
|
||||
value: 2,
|
||||
color: 'text-purple-500',
|
||||
});
|
||||
expect(stats.roleDistribution).toContainEqual({
|
||||
label: 'Admin',
|
||||
value: 1,
|
||||
color: 'text-blue-500',
|
||||
});
|
||||
expect(stats.roleDistribution).toContainEqual({
|
||||
label: 'User',
|
||||
value: 1,
|
||||
color: 'text-gray-500',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle users with multiple roles', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
const user1 = AdminUser.create({
|
||||
id: 'user-1',
|
||||
email: 'user1@example.com',
|
||||
displayName: 'User 1',
|
||||
roles: ['user', 'admin'],
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [user1] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const stats = result.unwrap();
|
||||
expect(stats.roleDistribution).toHaveLength(2);
|
||||
expect(stats.roleDistribution).toContainEqual({
|
||||
label: 'User',
|
||||
value: 1,
|
||||
color: 'text-gray-500',
|
||||
});
|
||||
expect(stats.roleDistribution).toContainEqual({
|
||||
label: 'Admin',
|
||||
value: 1,
|
||||
color: 'text-blue-500',
|
||||
});
|
||||
});
|
||||
|
||||
it('should calculate user growth for last 7 days', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
const today = new Date();
|
||||
const yesterday = new Date(today);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
const twoDaysAgo = new Date(today);
|
||||
twoDaysAgo.setDate(twoDaysAgo.getDate() - 2);
|
||||
|
||||
const user1 = AdminUser.create({
|
||||
id: 'user-1',
|
||||
email: 'user1@example.com',
|
||||
displayName: 'User 1',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: today,
|
||||
updatedAt: today,
|
||||
});
|
||||
|
||||
const user2 = AdminUser.create({
|
||||
id: 'user-2',
|
||||
email: 'user2@example.com',
|
||||
displayName: 'User 2',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: yesterday,
|
||||
updatedAt: yesterday,
|
||||
});
|
||||
|
||||
const user3 = AdminUser.create({
|
||||
id: 'user-3',
|
||||
email: 'user3@example.com',
|
||||
displayName: 'User 3',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: twoDaysAgo,
|
||||
updatedAt: twoDaysAgo,
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [user1, user2, user3] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const stats = result.unwrap();
|
||||
expect(stats.userGrowth).toHaveLength(7);
|
||||
|
||||
// Check that today has 1 user
|
||||
const todayEntry = stats.userGrowth[6];
|
||||
expect(todayEntry.value).toBe(1);
|
||||
|
||||
// Check that yesterday has 1 user
|
||||
const yesterdayEntry = stats.userGrowth[5];
|
||||
expect(yesterdayEntry.value).toBe(1);
|
||||
|
||||
// Check that two days ago has 1 user
|
||||
const twoDaysAgoEntry = stats.userGrowth[4];
|
||||
expect(twoDaysAgoEntry.value).toBe(1);
|
||||
});
|
||||
|
||||
it('should calculate activity timeline for last 7 days', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
const today = new Date();
|
||||
const yesterday = new Date(today);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
const newUser = AdminUser.create({
|
||||
id: 'user-1',
|
||||
email: 'user1@example.com',
|
||||
displayName: 'User 1',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: today,
|
||||
updatedAt: today,
|
||||
});
|
||||
|
||||
const recentLoginUser = AdminUser.create({
|
||||
id: 'user-2',
|
||||
email: 'user2@example.com',
|
||||
displayName: 'User 2',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
createdAt: yesterday,
|
||||
updatedAt: yesterday,
|
||||
lastLoginAt: new Date(Date.now() - 3600000), // 1 hour ago
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [newUser, recentLoginUser] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const stats = result.unwrap();
|
||||
expect(stats.activityTimeline).toHaveLength(7);
|
||||
|
||||
// Check today's entry
|
||||
const todayEntry = stats.activityTimeline[6];
|
||||
expect(todayEntry.newUsers).toBe(1);
|
||||
expect(todayEntry.logins).toBe(1);
|
||||
|
||||
// Check yesterday's entry
|
||||
const yesterdayEntry = stats.activityTimeline[5];
|
||||
expect(yesterdayEntry.newUsers).toBe(0);
|
||||
expect(yesterdayEntry.logins).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle repository errors gracefully', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockRejectedValue(new Error('Database connection failed'));
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('REPOSITORY_ERROR');
|
||||
expect(error.details.message).toBe('Database connection failed');
|
||||
});
|
||||
|
||||
it('should handle non-Error exceptions', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockRejectedValue('String error');
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('REPOSITORY_ERROR');
|
||||
expect(error.details.message).toBe('Failed to get dashboard stats');
|
||||
});
|
||||
|
||||
it('should work with owner role', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
});
|
||||
|
||||
it('should work with admin role', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['admin'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
});
|
||||
|
||||
it('should reject user role', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['user'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('AUTHORIZATION_ERROR');
|
||||
});
|
||||
|
||||
it('should handle suspended actor', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'suspended',
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('AUTHORIZATION_ERROR');
|
||||
});
|
||||
|
||||
it('should handle deleted actor', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'deleted',
|
||||
});
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users: [] });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
const error = result.unwrapErr();
|
||||
expect(error.code).toBe('AUTHORIZATION_ERROR');
|
||||
});
|
||||
|
||||
it('should handle large number of users efficiently', async () => {
|
||||
// Arrange
|
||||
const actor = AdminUser.create({
|
||||
id: 'actor-1',
|
||||
email: 'actor@example.com',
|
||||
displayName: 'Actor',
|
||||
roles: ['owner'],
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
const users = Array.from({ length: 1000 }, (_, i) =>
|
||||
AdminUser.create({
|
||||
id: `user-${i}`,
|
||||
email: `user${i}@example.com`,
|
||||
displayName: `User ${i}`,
|
||||
roles: i % 3 === 0 ? ['owner'] : i % 3 === 1 ? ['admin'] : ['user'],
|
||||
status: i % 4 === 0 ? 'suspended' : i % 4 === 1 ? 'deleted' : 'active',
|
||||
createdAt: new Date(Date.now() - i * 3600000),
|
||||
updatedAt: new Date(Date.now() - i * 3600000),
|
||||
lastLoginAt: i % 10 === 0 ? new Date(Date.now() - i * 3600000) : undefined,
|
||||
})
|
||||
);
|
||||
|
||||
mockAdminUserRepo.findById.mockResolvedValue(actor);
|
||||
mockAdminUserRepo.list.mockResolvedValue({ users });
|
||||
|
||||
// Act
|
||||
const result = await useCase.execute({ actorId: 'actor-1' });
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const stats = result.unwrap();
|
||||
expect(stats.totalUsers).toBe(1000);
|
||||
expect(stats.activeUsers).toBe(500);
|
||||
expect(stats.suspendedUsers).toBe(250);
|
||||
expect(stats.deletedUsers).toBe(250);
|
||||
expect(stats.systemAdmins).toBe(334); // owner + admin
|
||||
expect(stats.recentLogins).toBe(100); // 10% of users
|
||||
expect(stats.userGrowth).toHaveLength(7);
|
||||
expect(stats.roleDistribution).toHaveLength(3);
|
||||
expect(stats.activityTimeline).toHaveLength(7);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user