import { describe, it, expect, vi, beforeEach } from 'vitest'; import { removeTeamOwner, assignTeamOwner } from '~/models/team'; import { findAllUsers, isUserAdmin } from '~/models/user'; // Helper function to create mock team objects with all required properties const createMockTeam = (overrides: { id: string; ownerId: string | null; name?: string; seasonId?: string; draftPosition?: number; }) => ({ id: overrides.id, name: overrides.name || `Team ${overrides.id}`, seasonId: overrides.seasonId || 'season-1', ownerId: overrides.ownerId, logoUrl: null, draftPosition: overrides.draftPosition || 1, createdAt: new Date(), updatedAt: new Date(), }); // Mock the models vi.mock('~/models/team', () => ({ removeTeamOwner: vi.fn(), assignTeamOwner: vi.fn(), findTeamsBySeasonId: vi.fn(), createManyTeams: vi.fn(), deleteTeam: vi.fn(), })); vi.mock('~/models/user', () => ({ findAllUsers: vi.fn(), findUserById: vi.fn(), isUserAdmin: vi.fn(), })); vi.mock('~/models/league', () => ({ findLeagueById: vi.fn(), updateLeague: vi.fn(), deleteLeague: vi.fn(), })); vi.mock('~/models/commissioner', () => ({ isCommissioner: vi.fn(), })); vi.mock('~/models/season', () => ({ findCurrentSeasonWithSports: vi.fn(), updateSeason: vi.fn(), })); vi.mock('~/models/sports-season', () => ({ findAllSportsSeasons: vi.fn(), })); vi.mock('~/models/season-sport', () => ({ unlinkSportFromSeason: vi.fn(), linkMultipleSportsToSeason: vi.fn(), })); vi.mock('~/models/draft-slot', () => ({ findDraftSlotsBySeasonId: vi.fn(), setDraftOrder: vi.fn(), randomizeDraftOrder: vi.fn(), })); describe('Team Management - Remove Owner', () => { beforeEach(() => { vi.clearAllMocks(); }); it('should successfully remove an owner from a team', async () => { const teamId = 'team-1'; const mockTeam = createMockTeam({ id: teamId, ownerId: null, name: 'Team 1' }); vi.mocked(removeTeamOwner).mockResolvedValue(mockTeam); const result = await removeTeamOwner(teamId); expect(removeTeamOwner).toHaveBeenCalledWith(teamId); expect(result.ownerId).toBeNull(); expect(result.id).toBe(teamId); }); it('should handle errors when removing owner fails', async () => { const teamId = 'team-1'; const error = new Error('Database error'); vi.mocked(removeTeamOwner).mockRejectedValue(error); await expect(removeTeamOwner(teamId)).rejects.toThrow('Database error'); }); it('should allow commissioners to remove owners', async () => { // This would be tested in the action handler const teamId = 'team-1'; const mockTeam = createMockTeam({ id: teamId, ownerId: null, name: 'Team 1' }); vi.mocked(removeTeamOwner).mockResolvedValue(mockTeam); const result = await removeTeamOwner(teamId); expect(result.ownerId).toBeNull(); }); }); describe('Team Management - Assign Owner', () => { beforeEach(() => { vi.clearAllMocks(); }); it('should successfully assign an owner to a team', async () => { const teamId = 'team-1'; const userId = 'user-uuid-123'; const mockTeam = createMockTeam({ id: teamId, ownerId: userId, name: 'Team 1' }); vi.mocked(assignTeamOwner).mockResolvedValue(mockTeam); const result = await assignTeamOwner(teamId, userId); expect(assignTeamOwner).toHaveBeenCalledWith(teamId, userId); expect(result.ownerId).toBe(userId); expect(result.id).toBe(teamId); }); it('should handle errors when assigning owner fails', async () => { const teamId = 'team-1'; const userId = 'user-uuid-123'; const error = new Error('Database error'); vi.mocked(assignTeamOwner).mockRejectedValue(error); await expect(assignTeamOwner(teamId, userId)).rejects.toThrow('Database error'); }); it('should only allow admins to assign owners', async () => { const userId = 'admin-user-id'; // Mock admin check vi.mocked(isUserAdmin).mockResolvedValue(true); const isAdmin = await isUserAdmin(userId); expect(isAdmin).toBe(true); expect(isUserAdmin).toHaveBeenCalledWith(userId); }); it('should prevent non-admins from assigning owners', async () => { const userId = 'regular-user-id'; // Mock non-admin check vi.mocked(isUserAdmin).mockResolvedValue(false); const isAdmin = await isUserAdmin(userId); expect(isAdmin).toBe(false); }); it('should replace existing owner when assigning new owner', async () => { const teamId = 'team-1'; const oldOwnerId = 'user-uuid-old'; const newOwnerId = 'user-uuid-new'; const mockTeam = createMockTeam({ id: teamId, ownerId: newOwnerId, name: 'Team 1' }); vi.mocked(assignTeamOwner).mockResolvedValue(mockTeam); const result = await assignTeamOwner(teamId, newOwnerId); expect(result.ownerId).toBe(newOwnerId); expect(result.ownerId).not.toBe(oldOwnerId); }); }); describe('Team Management - Admin User List', () => { beforeEach(() => { vi.clearAllMocks(); }); it('should fetch all users for admin dropdown', async () => { const mockUsers = [ { id: 'user-1', clerkId: null, email: 'user1@example.com', emailVerified: true, username: 'user1', displayName: 'User One', firstName: 'User', lastName: 'One', imageUrl: null, isAdmin: false, timezone: null, createdAt: new Date(), updatedAt: new Date(), }, { id: 'user-2', clerkId: null, email: 'user2@example.com', emailVerified: true, username: 'user2', displayName: 'User Two', firstName: 'User', lastName: 'Two', imageUrl: null, isAdmin: false, timezone: null, createdAt: new Date(), updatedAt: new Date(), }, ]; vi.mocked(findAllUsers).mockResolvedValue(mockUsers); const users = await findAllUsers(); expect(findAllUsers).toHaveBeenCalled(); expect(users).toHaveLength(2); expect(users[0].displayName).toBe('User One'); expect(users[1].displayName).toBe('User Two'); }); it('should only fetch users when user is admin', async () => { const userId = 'admin-user-id'; vi.mocked(isUserAdmin).mockResolvedValue(true); const isAdmin = await isUserAdmin(userId); if (isAdmin) { const mockUsers = [ { id: 'user-1', clerkId: null, email: 'user1@example.com', emailVerified: true, username: 'user1', displayName: 'User One', firstName: 'User', lastName: 'One', imageUrl: null, isAdmin: false, timezone: null, createdAt: new Date(), updatedAt: new Date(), }, ]; vi.mocked(findAllUsers).mockResolvedValue(mockUsers); const users = await findAllUsers(); expect(users).toHaveLength(1); } expect(isAdmin).toBe(true); }); it('should return empty array for non-admin users', async () => { const userId = 'regular-user-id'; vi.mocked(isUserAdmin).mockResolvedValue(false); const isAdmin = await isUserAdmin(userId); // Simulate loader behavior: only fetch users if admin const users = isAdmin ? await findAllUsers() : []; expect(isAdmin).toBe(false); expect(users).toHaveLength(0); expect(findAllUsers).not.toHaveBeenCalled(); }); }); describe('Team Management - Authorization', () => { beforeEach(() => { vi.clearAllMocks(); }); it('should verify admin status before allowing assignment', async () => { const userId = 'test-user-id'; vi.mocked(isUserAdmin).mockResolvedValue(true); const isAdmin = await isUserAdmin(userId); expect(isAdmin).toBe(true); expect(isUserAdmin).toHaveBeenCalledWith(userId); }); it('should reject assignment for non-admin users', async () => { const userId = 'regular-user-id'; vi.mocked(isUserAdmin).mockResolvedValue(false); const isAdmin = await isUserAdmin(userId); expect(isAdmin).toBe(false); // Simulate action handler logic if (!isAdmin) { expect(assignTeamOwner).not.toHaveBeenCalled(); } }); it('should allow commissioners to remove owners regardless of admin status', async () => { // Commissioners can remove owners even if they're not admins const teamId = 'team-1'; const mockTeam = createMockTeam({ id: teamId, ownerId: null, name: 'Team 1' }); vi.mocked(removeTeamOwner).mockResolvedValue(mockTeam); const result = await removeTeamOwner(teamId); expect(removeTeamOwner).toHaveBeenCalledWith(teamId); expect(result.ownerId).toBeNull(); }); }); describe('Team Management - Edge Cases', () => { beforeEach(() => { vi.clearAllMocks(); }); it('should prevent assigning user who already owns a team in the league', async () => { const userId = 'user-uuid-1'; // Simulate that user already owns team-1 const existingTeams = [ createMockTeam({ id: 'team-1', ownerId: userId, name: 'Team 1' }), createMockTeam({ id: 'team-2', ownerId: null, name: 'Team 2' }), ]; // Check if user already has a team const userAlreadyHasTeam = existingTeams.some(team => team.ownerId === userId); expect(userAlreadyHasTeam).toBe(true); // Should not call assignTeamOwner if user already has a team if (userAlreadyHasTeam) { expect(assignTeamOwner).not.toHaveBeenCalled(); } }); it('should handle removing owner from team that has no owner', async () => { const teamId = 'team-1'; const mockTeam = createMockTeam({ id: teamId, ownerId: null, name: 'Team 1' }); vi.mocked(removeTeamOwner).mockResolvedValue(mockTeam); const result = await removeTeamOwner(teamId); expect(result.ownerId).toBeNull(); }); it('should handle assigning owner to team that already has owner', async () => { const teamId = 'team-1'; const newOwnerId = 'user-uuid-new'; const mockTeam = createMockTeam({ id: teamId, ownerId: newOwnerId, name: 'Team 1' }); vi.mocked(assignTeamOwner).mockResolvedValue(mockTeam); const result = await assignTeamOwner(teamId, newOwnerId); expect(result.ownerId).toBe(newOwnerId); }); it('should handle invalid team ID gracefully', async () => { const invalidTeamId = 'invalid-team-id'; const error = new Error('Team not found'); vi.mocked(removeTeamOwner).mockRejectedValue(error); await expect(removeTeamOwner(invalidTeamId)).rejects.toThrow('Team not found'); }); it('should handle invalid user ID gracefully', async () => { const teamId = 'team-1'; const invalidUserId = 'invalid-user-id'; const error = new Error('User not found'); vi.mocked(assignTeamOwner).mockRejectedValue(error); await expect(assignTeamOwner(teamId, invalidUserId)).rejects.toThrow('User not found'); }); }); describe('Team Management - Integration Scenarios', () => { beforeEach(() => { vi.clearAllMocks(); }); it('should handle complete workflow: assign then remove owner', async () => { const teamId = 'team-1'; const userId = 'user-uuid-123'; // First, assign owner const assignedTeam = createMockTeam({ id: teamId, ownerId: userId, name: 'Team 1' }); vi.mocked(assignTeamOwner).mockResolvedValue(assignedTeam); const assignResult = await assignTeamOwner(teamId, userId); expect(assignResult.ownerId).toBe(userId); // Then, remove owner const removedTeam = createMockTeam({ id: teamId, ownerId: null, name: 'Team 1' }); vi.mocked(removeTeamOwner).mockResolvedValue(removedTeam); const removeResult = await removeTeamOwner(teamId); expect(removeResult.ownerId).toBeNull(); }); it('should handle reassigning owner from one user to another', async () => { const teamId = 'team-1'; const firstUserId = 'user-uuid-1'; const secondUserId = 'user-uuid-2'; // Assign first owner const firstAssignment = createMockTeam({ id: teamId, ownerId: firstUserId, name: 'Team 1' }); vi.mocked(assignTeamOwner).mockResolvedValueOnce(firstAssignment); const firstResult = await assignTeamOwner(teamId, firstUserId); expect(firstResult.ownerId).toBe(firstUserId); // Reassign to second owner const secondAssignment = createMockTeam({ id: teamId, ownerId: secondUserId, name: 'Team 1' }); vi.mocked(assignTeamOwner).mockResolvedValueOnce(secondAssignment); const secondResult = await assignTeamOwner(teamId, secondUserId); expect(secondResult.ownerId).toBe(secondUserId); expect(secondResult.ownerId).not.toBe(firstUserId); }); it('should handle multiple teams with different ownership states', async () => { const teams = [ { id: 'team-1', ownerId: 'user-1' }, { id: 'team-2', ownerId: null }, { id: 'team-3', ownerId: 'user-2' }, ]; // Remove owner from team-1 vi.mocked(removeTeamOwner).mockResolvedValueOnce( createMockTeam({ id: 'team-1', ownerId: null, name: 'Team 1', draftPosition: 1 }) ); const result1 = await removeTeamOwner('team-1'); expect(result1.ownerId).toBeNull(); // Assign owner to team-2 vi.mocked(assignTeamOwner).mockResolvedValueOnce( createMockTeam({ id: 'team-2', ownerId: 'user-3', name: 'Team 2', draftPosition: 2 }) ); const result2 = await assignTeamOwner('team-2', 'user-3'); expect(result2.ownerId).toBe('user-3'); // Leave team-3 unchanged expect(teams[2].ownerId).toBe('user-2'); }); });