import { TestBed } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; import { AdminUsersFacade } from './admin-users.facade'; import { ADMIN_USERS_GATEWAY } from '../services/admin-users-gateway.token'; import { AdminUsersGateway } from '../services/admin-users-gateway.interface'; import { AdminUser, AdminUserRoleRecord } from '../models/admin-user.model'; function user(overrides: Partial = {}): AdminUser { return { id: 'u1', name: 'Alice', email: 'a@example.com', roleId: 'role1', scope: 'marketplace', status: 'active', ...overrides } as AdminUser; } describe('AdminUsersFacade', () => { let facade: AdminUsersFacade; let gateway: jasmine.SpyObj; beforeEach(() => { gateway = jasmine.createSpyObj('AdminUsersGateway', [ 'loadUsers', 'loadRoles', 'loadInvitations', 'loadSessions', 'loadAudit', 'setUserRole', 'setUserStatus', 'inviteUser', 'revokeInvitation', 'revokeSession', ]); TestBed.configureTestingModule({ providers: [{ provide: ADMIN_USERS_GATEWAY, useValue: gateway }] }); facade = TestBed.inject(AdminUsersFacade); }); it('loadAll populates users, roles, and invitations independently', () => { gateway.loadUsers.and.returnValue(of([user()])); gateway.loadRoles.and.returnValue(of([{ id: 'role1', name: 'Manager' } as AdminUserRoleRecord])); gateway.loadInvitations.and.returnValue(of([])); facade.loadAll(); expect(facade.users().length).toBe(1); expect(facade.roles().length).toBe(1); }); it('a users-load failure clears users and sets error, without blocking roles/invitations', () => { gateway.loadUsers.and.returnValue(throwError(() => new Error('x'))); gateway.loadRoles.and.returnValue(of([{ id: 'role1', name: 'Manager' } as AdminUserRoleRecord])); gateway.loadInvitations.and.returnValue(of([])); facade.loadAll(); expect(facade.users()).toEqual([]); expect(facade.error()).toBeTrue(); expect(facade.roles().length).toBe(1); }); describe('roleName', () => { it('resolves a known role id to its display name', () => { gateway.loadUsers.and.returnValue(of([])); gateway.loadRoles.and.returnValue(of([{ id: 'role1', name: 'Manager' } as AdminUserRoleRecord])); gateway.loadInvitations.and.returnValue(of([])); facade.loadAll(); expect(facade.roleName('role1')).toBe('Manager'); }); it('falls back to the raw id when the role is unknown, rather than showing blank', () => { expect(facade.roleName('mystery-role')).toBe('mystery-role'); }); }); describe('invite', () => { it('does not call the gateway for a whitespace-only email', () => { facade.invite(' ', 'role1', 'marketplace'); expect(gateway.inviteUser).not.toHaveBeenCalled(); }); it('trims the email before sending it', () => { gateway.inviteUser.and.returnValue(of({} as any)); gateway.loadUsers.and.returnValue(of([])); gateway.loadRoles.and.returnValue(of([])); gateway.loadInvitations.and.returnValue(of([])); facade.invite(' a@example.com ', 'role1', 'marketplace'); expect(gateway.inviteUser).toHaveBeenCalledWith('a@example.com', 'role1', 'marketplace'); }); it('sets mutationError on failure', () => { gateway.inviteUser.and.returnValue(throwError(() => new Error('x'))); facade.invite('a@example.com', 'role1', 'marketplace'); expect(facade.mutationError()).toBe('common.errorDescription'); }); }); describe('sessions dialog', () => { it('openSessions sets the target and loads that user\'s sessions', () => { gateway.loadSessions.and.returnValue(of([{ id: 's1' } as any])); facade.openSessions(user()); expect(facade.sessionsTarget()?.id).toBe('u1'); expect(facade.sessions().length).toBe(1); }); it('closeSessions clears the target', () => { gateway.loadSessions.and.returnValue(of([])); facade.openSessions(user()); facade.closeSessions(); expect(facade.sessionsTarget()).toBeNull(); }); it('revokeSession reloads sessions for the currently open user, not a stale one', () => { gateway.loadSessions.and.returnValue(of([])); gateway.revokeSession.and.returnValue(of(undefined)); facade.openSessions(user({ id: 'u1' })); facade.revokeSession('s1'); expect(gateway.loadSessions).toHaveBeenCalledWith('u1'); }); it('revokeSession does nothing extra when no sessions dialog is open', () => { gateway.revokeSession.and.returnValue(of(undefined)); facade.revokeSession('s1'); expect(gateway.loadSessions).not.toHaveBeenCalled(); }); }); describe('audit dialog', () => { it('openAudit loads entries for the target user', () => { gateway.loadAudit.and.returnValue(of([{ id: 'a1' } as any])); facade.openAudit(user()); expect(facade.audit().length).toBe(1); }); it('closeAudit clears the target', () => { gateway.loadAudit.and.returnValue(of([])); facade.openAudit(user()); facade.closeAudit(); expect(facade.auditTarget()).toBeNull(); }); }); });