import { describe, it, expect } from 'vitest'; import { AdminUsersViewDataBuilder } from './AdminUsersViewDataBuilder'; import type { UserListResponse } from '@/lib/types/admin'; describe('AdminUsersViewDataBuilder', () => { describe('happy paths', () => { it('should transform UserListResponse DTO to AdminUsersViewData correctly', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'admin@example.com', displayName: 'Admin User', roles: ['admin', 'owner'], status: 'active', isSystemAdmin: true, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', lastLoginAt: '2024-01-20T10:00:00.000Z', primaryDriverId: 'driver-123', }, { id: 'user-2', email: 'user@example.com', displayName: 'Regular User', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-05T00:00:00.000Z', updatedAt: '2024-01-10T08:00:00.000Z', lastLoginAt: '2024-01-18T14:00:00.000Z', primaryDriverId: 'driver-456', }, ], total: 2, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users).toHaveLength(2); expect(result.users[0]).toEqual({ id: 'user-1', email: 'admin@example.com', displayName: 'Admin User', roles: ['admin', 'owner'], status: 'active', isSystemAdmin: true, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', lastLoginAt: '2024-01-20T10:00:00.000Z', primaryDriverId: 'driver-123', }); expect(result.users[1]).toEqual({ id: 'user-2', email: 'user@example.com', displayName: 'Regular User', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-05T00:00:00.000Z', updatedAt: '2024-01-10T08:00:00.000Z', lastLoginAt: '2024-01-18T14:00:00.000Z', primaryDriverId: 'driver-456', }); expect(result.total).toBe(2); expect(result.page).toBe(1); expect(result.limit).toBe(10); expect(result.totalPages).toBe(1); }); it('should calculate derived fields correctly', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', }, { id: 'user-2', email: 'user2@example.com', displayName: 'User 2', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-02T00:00:00.000Z', updatedAt: '2024-01-16T12:00:00.000Z', }, { id: 'user-3', email: 'user3@example.com', displayName: 'User 3', roles: ['admin'], status: 'suspended', isSystemAdmin: true, createdAt: '2024-01-03T00:00:00.000Z', updatedAt: '2024-01-17T12:00:00.000Z', }, { id: 'user-4', email: 'user4@example.com', displayName: 'User 4', roles: ['member'], status: 'deleted', isSystemAdmin: false, createdAt: '2024-01-04T00:00:00.000Z', updatedAt: '2024-01-18T12:00:00.000Z', }, ], total: 4, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); // activeUserCount should count only users with status 'active' expect(result.activeUserCount).toBe(2); // adminCount should count only system admins expect(result.adminCount).toBe(1); }); it('should handle empty users list', () => { const userListResponse: UserListResponse = { users: [], total: 0, page: 1, limit: 10, totalPages: 0, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users).toHaveLength(0); expect(result.total).toBe(0); expect(result.activeUserCount).toBe(0); expect(result.adminCount).toBe(0); }); it('should handle users without optional fields', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', // lastLoginAt and primaryDriverId are optional }, ], total: 1, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users[0].lastLoginAt).toBeUndefined(); expect(result.users[0].primaryDriverId).toBeUndefined(); }); }); describe('date formatting', () => { it('should handle ISO date strings correctly', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', lastLoginAt: '2024-01-20T10:00:00.000Z', }, ], total: 1, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users[0].createdAt).toBe('2024-01-01T00:00:00.000Z'); expect(result.users[0].updatedAt).toBe('2024-01-15T12:00:00.000Z'); expect(result.users[0].lastLoginAt).toBe('2024-01-20T10:00:00.000Z'); }); it('should handle Date objects and convert to ISO strings', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: new Date('2024-01-01T00:00:00.000Z'), updatedAt: new Date('2024-01-15T12:00:00.000Z'), lastLoginAt: new Date('2024-01-20T10:00:00.000Z'), }, ], total: 1, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users[0].createdAt).toBe('2024-01-01T00:00:00.000Z'); expect(result.users[0].updatedAt).toBe('2024-01-15T12:00:00.000Z'); expect(result.users[0].lastLoginAt).toBe('2024-01-20T10:00:00.000Z'); }); it('should handle Date objects for lastLoginAt when present', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', lastLoginAt: new Date('2024-01-20T10:00:00.000Z'), }, ], total: 1, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users[0].lastLoginAt).toBe('2024-01-20T10:00:00.000Z'); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: ['admin', 'owner'], status: 'active', isSystemAdmin: true, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', lastLoginAt: '2024-01-20T10:00:00.000Z', primaryDriverId: 'driver-123', }, ], total: 1, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users[0].id).toBe(userListResponse.users[0].id); expect(result.users[0].email).toBe(userListResponse.users[0].email); expect(result.users[0].displayName).toBe(userListResponse.users[0].displayName); expect(result.users[0].roles).toEqual(userListResponse.users[0].roles); expect(result.users[0].status).toBe(userListResponse.users[0].status); expect(result.users[0].isSystemAdmin).toBe(userListResponse.users[0].isSystemAdmin); expect(result.users[0].createdAt).toBe(userListResponse.users[0].createdAt); expect(result.users[0].updatedAt).toBe(userListResponse.users[0].updatedAt); expect(result.users[0].lastLoginAt).toBe(userListResponse.users[0].lastLoginAt); expect(result.users[0].primaryDriverId).toBe(userListResponse.users[0].primaryDriverId); expect(result.total).toBe(userListResponse.total); expect(result.page).toBe(userListResponse.page); expect(result.limit).toBe(userListResponse.limit); expect(result.totalPages).toBe(userListResponse.totalPages); }); it('should not modify the input DTO', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', }, ], total: 1, page: 1, limit: 10, totalPages: 1, }; const originalResponse = { ...userListResponse }; AdminUsersViewDataBuilder.build(userListResponse); expect(userListResponse).toEqual(originalResponse); }); }); describe('edge cases', () => { it('should handle users with multiple roles', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: ['admin', 'owner', 'steward', 'member'], status: 'active', isSystemAdmin: true, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', }, ], total: 1, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users[0].roles).toEqual(['admin', 'owner', 'steward', 'member']); }); it('should handle users with different statuses', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', }, { id: 'user-2', email: 'user2@example.com', displayName: 'User 2', roles: ['member'], status: 'suspended', isSystemAdmin: false, createdAt: '2024-01-02T00:00:00.000Z', updatedAt: '2024-01-16T12:00:00.000Z', }, { id: 'user-3', email: 'user3@example.com', displayName: 'User 3', roles: ['member'], status: 'deleted', isSystemAdmin: false, createdAt: '2024-01-03T00:00:00.000Z', updatedAt: '2024-01-17T12:00:00.000Z', }, ], total: 3, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users[0].status).toBe('active'); expect(result.users[1].status).toBe('suspended'); expect(result.users[2].status).toBe('deleted'); expect(result.activeUserCount).toBe(1); }); it('should handle pagination metadata correctly', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', }, ], total: 100, page: 5, limit: 20, totalPages: 5, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.total).toBe(100); expect(result.page).toBe(5); expect(result.limit).toBe(20); expect(result.totalPages).toBe(5); }); it('should handle users with empty roles array', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1', roles: [], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', }, ], total: 1, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users[0].roles).toEqual([]); }); it('should handle users with special characters in display name', () => { const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: 'user1@example.com', displayName: 'User 1 & 2 (Admin)', roles: ['admin'], status: 'active', isSystemAdmin: true, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', }, ], total: 1, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users[0].displayName).toBe('User 1 & 2 (Admin)'); }); it('should handle users with very long email addresses', () => { const longEmail = 'verylongemailaddresswithmanycharacters@example.com'; const userListResponse: UserListResponse = { users: [ { id: 'user-1', email: longEmail, displayName: 'User 1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z', }, ], total: 1, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.users[0].email).toBe(longEmail); }); }); describe('derived fields calculation', () => { it('should calculate activeUserCount correctly with mixed statuses', () => { const userListResponse: UserListResponse = { users: [ { id: '1', email: '1@e.com', displayName: '1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '2', email: '2@e.com', displayName: '2', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '3', email: '3@e.com', displayName: '3', roles: ['member'], status: 'suspended', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '4', email: '4@e.com', displayName: '4', roles: ['member'], status: 'deleted', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, ], total: 4, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.activeUserCount).toBe(2); }); it('should calculate adminCount correctly with mixed roles', () => { const userListResponse: UserListResponse = { users: [ { id: '1', email: '1@e.com', displayName: '1', roles: ['admin'], status: 'active', isSystemAdmin: true, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '2', email: '2@e.com', displayName: '2', roles: ['admin', 'owner'], status: 'active', isSystemAdmin: true, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '3', email: '3@e.com', displayName: '3', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '4', email: '4@e.com', displayName: '4', roles: ['owner'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, ], total: 4, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.adminCount).toBe(2); }); it('should handle all active users', () => { const userListResponse: UserListResponse = { users: [ { id: '1', email: '1@e.com', displayName: '1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '2', email: '2@e.com', displayName: '2', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '3', email: '3@e.com', displayName: '3', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, ], total: 3, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.activeUserCount).toBe(3); }); it('should handle no active users', () => { const userListResponse: UserListResponse = { users: [ { id: '1', email: '1@e.com', displayName: '1', roles: ['member'], status: 'suspended', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '2', email: '2@e.com', displayName: '2', roles: ['member'], status: 'deleted', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, ], total: 2, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.activeUserCount).toBe(0); }); it('should handle all system admins', () => { const userListResponse: UserListResponse = { users: [ { id: '1', email: '1@e.com', displayName: '1', roles: ['admin'], status: 'active', isSystemAdmin: true, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '2', email: '2@e.com', displayName: '2', roles: ['admin'], status: 'active', isSystemAdmin: true, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '3', email: '3@e.com', displayName: '3', roles: ['admin'], status: 'active', isSystemAdmin: true, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, ], total: 3, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.adminCount).toBe(3); }); it('should handle no system admins', () => { const userListResponse: UserListResponse = { users: [ { id: '1', email: '1@e.com', displayName: '1', roles: ['member'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, { id: '2', email: '2@e.com', displayName: '2', roles: ['owner'], status: 'active', isSystemAdmin: false, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-15T12:00:00.000Z' }, ], total: 2, page: 1, limit: 10, totalPages: 1, }; const result = AdminUsersViewDataBuilder.build(userListResponse); expect(result.adminCount).toBe(0); }); }); });