532 lines
14 KiB
TypeScript
532 lines
14 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { UserRole } from '../value-objects/UserRole';
|
|
import { AdminUser } from './AdminUser';
|
|
|
|
describe('AdminUser', () => {
|
|
describe('TDD - Test First', () => {
|
|
it('should create a valid admin user', () => {
|
|
// Arrange & Act
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'admin@example.com',
|
|
displayName: 'Admin User',
|
|
roles: ['owner'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert
|
|
expect(user.id.value).toBe('user-123');
|
|
expect(user.email.value).toBe('admin@example.com');
|
|
expect(user.displayName).toBe('Admin User');
|
|
expect(user.roles).toHaveLength(1);
|
|
expect(user.roles[0]!.value).toBe('owner');
|
|
expect(user.status.value).toBe('active');
|
|
});
|
|
|
|
it('should validate email format', () => {
|
|
// Arrange & Act
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'invalid-email',
|
|
displayName: 'Test User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert - Email should be created but validation happens in value object
|
|
expect(user.email.value).toBe('invalid-email');
|
|
});
|
|
|
|
it('should detect system admin (owner)', () => {
|
|
// Arrange
|
|
const owner = AdminUser.create({
|
|
id: 'owner-1',
|
|
email: 'owner@example.com',
|
|
displayName: 'Owner',
|
|
roles: ['owner'],
|
|
status: 'active',
|
|
});
|
|
|
|
const admin = AdminUser.create({
|
|
id: 'admin-1',
|
|
email: 'admin@example.com',
|
|
displayName: 'Admin',
|
|
roles: ['admin'],
|
|
status: 'active',
|
|
});
|
|
|
|
const user = AdminUser.create({
|
|
id: 'user-1',
|
|
email: 'user@example.com',
|
|
displayName: 'User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert
|
|
expect(owner.isSystemAdmin()).toBe(true);
|
|
expect(admin.isSystemAdmin()).toBe(true);
|
|
expect(user.isSystemAdmin()).toBe(false);
|
|
});
|
|
|
|
it('should handle multiple roles', () => {
|
|
// Arrange & Act
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'multi@example.com',
|
|
displayName: 'Multi Role',
|
|
roles: ['owner', 'admin'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert
|
|
expect(user.roles).toHaveLength(2);
|
|
expect(user.roles.map(r => r.value)).toContain('owner');
|
|
expect(user.roles.map(r => r.value)).toContain('admin');
|
|
});
|
|
|
|
it('should handle suspended status', () => {
|
|
// Arrange & Act
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'suspended@example.com',
|
|
displayName: 'Suspended User',
|
|
roles: ['user'],
|
|
status: 'suspended',
|
|
});
|
|
|
|
// Assert
|
|
expect(user.status.value).toBe('suspended');
|
|
expect(user.isActive()).toBe(false);
|
|
});
|
|
|
|
it('should handle optional fields', () => {
|
|
// Arrange & Act
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'minimal@example.com',
|
|
displayName: 'Minimal User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert
|
|
expect(user.primaryDriverId).toBeUndefined();
|
|
expect(user.lastLoginAt).toBeUndefined();
|
|
});
|
|
|
|
it('should handle all optional fields', () => {
|
|
// Arrange
|
|
const now = new Date();
|
|
|
|
// Act
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'full@example.com',
|
|
displayName: 'Full User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
primaryDriverId: 'driver-456',
|
|
lastLoginAt: now,
|
|
});
|
|
|
|
// Assert
|
|
expect(user.primaryDriverId).toBe('driver-456');
|
|
expect(user.lastLoginAt).toEqual(now);
|
|
});
|
|
|
|
it('should handle createdAt and updatedAt', () => {
|
|
// Arrange & Act
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert
|
|
expect(user.createdAt).toBeInstanceOf(Date);
|
|
expect(user.updatedAt).toBeInstanceOf(Date);
|
|
});
|
|
|
|
it('should handle role assignment with validation', () => {
|
|
// Arrange & Act
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert - Should accept any role string (validation happens in value object)
|
|
expect(user.roles).toHaveLength(1);
|
|
expect(user.roles[0]!.value).toBe('user');
|
|
});
|
|
|
|
it('should handle status changes', () => {
|
|
// Arrange
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Act - Use domain method to change status
|
|
user.suspend();
|
|
|
|
// Assert
|
|
expect(user.status.value).toBe('suspended');
|
|
});
|
|
|
|
it('should check if user is active', () => {
|
|
// Arrange
|
|
const activeUser = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'active@example.com',
|
|
displayName: 'Active User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
const suspendedUser = AdminUser.create({
|
|
id: 'user-456',
|
|
email: 'suspended@example.com',
|
|
displayName: 'Suspended User',
|
|
roles: ['user'],
|
|
status: 'suspended',
|
|
});
|
|
|
|
// Assert
|
|
expect(activeUser.isActive()).toBe(true);
|
|
expect(suspendedUser.isActive()).toBe(false);
|
|
});
|
|
|
|
it('should handle role management', () => {
|
|
// Arrange
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Act
|
|
user.addRole(UserRole.fromString('admin'));
|
|
|
|
// Assert
|
|
expect(user.roles).toHaveLength(2);
|
|
expect(user.hasRole('admin')).toBe(true);
|
|
});
|
|
|
|
it('should handle display name updates', () => {
|
|
// Arrange
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'test@example.com',
|
|
displayName: 'Old Name',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Act
|
|
user.updateDisplayName('New Name');
|
|
|
|
// Assert
|
|
expect(user.displayName).toBe('New Name');
|
|
});
|
|
|
|
it('should handle login recording', () => {
|
|
// Arrange
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
const beforeLogin = user.lastLoginAt;
|
|
|
|
// Act
|
|
user.recordLogin();
|
|
|
|
// Assert
|
|
expect(user.lastLoginAt).toBeDefined();
|
|
expect(user.lastLoginAt).not.toEqual(beforeLogin);
|
|
});
|
|
|
|
it('should handle summary generation', () => {
|
|
// Arrange
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
roles: ['owner'],
|
|
status: 'active',
|
|
lastLoginAt: new Date(),
|
|
});
|
|
|
|
// Act
|
|
const summary = user.toSummary();
|
|
|
|
// Assert
|
|
expect(summary.id).toBe('user-123');
|
|
expect(summary.email).toBe('test@example.com');
|
|
expect(summary.displayName).toBe('Test User');
|
|
expect(summary.roles).toEqual(['owner']);
|
|
expect(summary.status).toBe('active');
|
|
expect(summary.isSystemAdmin).toBe(true);
|
|
expect(summary.lastLoginAt).toBeDefined();
|
|
});
|
|
|
|
it('should handle equality comparison', () => {
|
|
// Arrange
|
|
const user1 = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
const user2 = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
const user3 = AdminUser.create({
|
|
id: 'user-456',
|
|
email: 'other@example.com',
|
|
displayName: 'Other User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert
|
|
expect(user1.equals(user2)).toBe(true);
|
|
expect(user1.equals(user3)).toBe(false);
|
|
expect(user1.equals(undefined)).toBe(false);
|
|
});
|
|
|
|
it('should handle management permissions', () => {
|
|
// Arrange
|
|
const owner = AdminUser.create({
|
|
id: 'owner-1',
|
|
email: 'owner@example.com',
|
|
displayName: 'Owner',
|
|
roles: ['owner'],
|
|
status: 'active',
|
|
});
|
|
|
|
const admin = AdminUser.create({
|
|
id: 'admin-1',
|
|
email: 'admin@example.com',
|
|
displayName: 'Admin',
|
|
roles: ['admin'],
|
|
status: 'active',
|
|
});
|
|
|
|
const user = AdminUser.create({
|
|
id: 'user-1',
|
|
email: 'user@example.com',
|
|
displayName: 'User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert - Owner can manage everyone
|
|
expect(owner.canManage(admin)).toBe(true);
|
|
expect(owner.canManage(user)).toBe(true);
|
|
expect(owner.canManage(owner)).toBe(true); // Can manage self
|
|
|
|
// Admin can manage users but not admins/owners
|
|
expect(admin.canManage(user)).toBe(true);
|
|
expect(admin.canManage(admin)).toBe(false);
|
|
expect(admin.canManage(owner)).toBe(false);
|
|
|
|
// User cannot manage anyone except self
|
|
expect(user.canManage(user)).toBe(true);
|
|
expect(user.canManage(admin)).toBe(false);
|
|
expect(user.canManage(owner)).toBe(false);
|
|
});
|
|
|
|
it('should handle role modification permissions', () => {
|
|
// Arrange
|
|
const owner = AdminUser.create({
|
|
id: 'owner-1',
|
|
email: 'owner@example.com',
|
|
displayName: 'Owner',
|
|
roles: ['owner'],
|
|
status: 'active',
|
|
});
|
|
|
|
const admin = AdminUser.create({
|
|
id: 'admin-1',
|
|
email: 'admin@example.com',
|
|
displayName: 'Admin',
|
|
roles: ['admin'],
|
|
status: 'active',
|
|
});
|
|
|
|
const user = AdminUser.create({
|
|
id: 'user-1',
|
|
email: 'user@example.com',
|
|
displayName: 'User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert - Only owner can modify roles
|
|
expect(owner.canModifyRoles(user)).toBe(true);
|
|
expect(owner.canModifyRoles(admin)).toBe(true);
|
|
expect(owner.canModifyRoles(owner)).toBe(false); // Cannot modify own roles
|
|
|
|
expect(admin.canModifyRoles(user)).toBe(false);
|
|
expect(user.canModifyRoles(user)).toBe(false);
|
|
});
|
|
|
|
it('should handle status change permissions', () => {
|
|
// Arrange
|
|
const owner = AdminUser.create({
|
|
id: 'owner-1',
|
|
email: 'owner@example.com',
|
|
displayName: 'Owner',
|
|
roles: ['owner'],
|
|
status: 'active',
|
|
});
|
|
|
|
const admin = AdminUser.create({
|
|
id: 'admin-1',
|
|
email: 'admin@example.com',
|
|
displayName: 'Admin',
|
|
roles: ['admin'],
|
|
status: 'active',
|
|
});
|
|
|
|
const user = AdminUser.create({
|
|
id: 'user-1',
|
|
email: 'user@example.com',
|
|
displayName: 'User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert - Owner can change anyone's status
|
|
expect(owner.canChangeStatus(user)).toBe(true);
|
|
expect(owner.canChangeStatus(admin)).toBe(true);
|
|
expect(owner.canChangeStatus(owner)).toBe(false); // Cannot change own status
|
|
|
|
// Admin can change user status but not admin/owner
|
|
expect(admin.canChangeStatus(user)).toBe(true);
|
|
expect(admin.canChangeStatus(admin)).toBe(false);
|
|
expect(admin.canChangeStatus(owner)).toBe(false);
|
|
|
|
// User cannot change status
|
|
expect(user.canChangeStatus(user)).toBe(false);
|
|
expect(user.canChangeStatus(admin)).toBe(false);
|
|
expect(user.canChangeStatus(owner)).toBe(false);
|
|
});
|
|
|
|
it('should handle deletion permissions', () => {
|
|
// Arrange
|
|
const owner = AdminUser.create({
|
|
id: 'owner-1',
|
|
email: 'owner@example.com',
|
|
displayName: 'Owner',
|
|
roles: ['owner'],
|
|
status: 'active',
|
|
});
|
|
|
|
const admin = AdminUser.create({
|
|
id: 'admin-1',
|
|
email: 'admin@example.com',
|
|
displayName: 'Admin',
|
|
roles: ['admin'],
|
|
status: 'active',
|
|
});
|
|
|
|
const user = AdminUser.create({
|
|
id: 'user-1',
|
|
email: 'user@example.com',
|
|
displayName: 'User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert - Owner can delete anyone except self
|
|
expect(owner.canDelete(user)).toBe(true);
|
|
expect(owner.canDelete(admin)).toBe(true);
|
|
expect(owner.canDelete(owner)).toBe(false); // Cannot delete self
|
|
|
|
// Admin can delete users but not admins/owners
|
|
expect(admin.canDelete(user)).toBe(true);
|
|
expect(admin.canDelete(admin)).toBe(false);
|
|
expect(admin.canDelete(owner)).toBe(false);
|
|
|
|
// User cannot delete anyone
|
|
expect(user.canDelete(user)).toBe(false);
|
|
expect(user.canDelete(admin)).toBe(false);
|
|
expect(user.canDelete(owner)).toBe(false);
|
|
});
|
|
|
|
it('should handle authority comparison', () => {
|
|
// Arrange
|
|
const owner = AdminUser.create({
|
|
id: 'owner-1',
|
|
email: 'owner@example.com',
|
|
displayName: 'Owner',
|
|
roles: ['owner'],
|
|
status: 'active',
|
|
});
|
|
|
|
const admin = AdminUser.create({
|
|
id: 'admin-1',
|
|
email: 'admin@example.com',
|
|
displayName: 'Admin',
|
|
roles: ['admin'],
|
|
status: 'active',
|
|
});
|
|
|
|
const user = AdminUser.create({
|
|
id: 'user-1',
|
|
email: 'user@example.com',
|
|
displayName: 'User',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Assert
|
|
expect(owner.hasHigherAuthorityThan(admin)).toBe(true);
|
|
expect(owner.hasHigherAuthorityThan(user)).toBe(true);
|
|
expect(admin.hasHigherAuthorityThan(user)).toBe(true);
|
|
expect(admin.hasHigherAuthorityThan(owner)).toBe(false);
|
|
expect(user.hasHigherAuthorityThan(admin)).toBe(false);
|
|
});
|
|
|
|
it('should handle role display names', () => {
|
|
// Arrange
|
|
const user = AdminUser.create({
|
|
id: 'user-123',
|
|
email: 'test@example.com',
|
|
displayName: 'Test User',
|
|
roles: ['owner', 'admin'],
|
|
status: 'active',
|
|
});
|
|
|
|
// Act
|
|
const displayNames = user.getRoleDisplayNames();
|
|
|
|
// Assert
|
|
expect(displayNames).toContain('Owner');
|
|
expect(displayNames).toContain('Admin');
|
|
});
|
|
});
|
|
}); |