import { adminPlayerApiErrorMessage, extractFieldErrors, isLastAdminError, lastAdminMessage, removePlayer, replacePlayer, toggleEnabled, toggleRole, } from '../../frontend/src/app/features/admin/admin-players.pure'; import { AdminUser } from '../../frontend/src/app/core/services/admin.service'; describe('admin-players.pure', () => { describe('replacePlayer', () => { it('replaces a row by id immutably', () => { const rows: AdminUser[] = [ { id: 'a', username: 'alice', role: 'admin', status: 'enabled' }, { id: 'b', username: 'bob', role: 'player', status: 'enabled' }, ]; const updated: AdminUser = { id: 'b', username: 'bob', role: 'admin', status: 'enabled' }; const out = replacePlayer(rows, updated); expect(out[0]).toEqual(rows[0]); expect(out[1]).toEqual(updated); expect(out).not.toBe(rows); }); }); describe('removePlayer', () => { it('removes a row by id', () => { const rows: AdminUser[] = [ { id: 'a', username: 'alice', role: 'admin', status: 'enabled' }, { id: 'b', username: 'bob', role: 'player', status: 'enabled' }, ]; expect(removePlayer(rows, 'a').map((u) => u.id)).toEqual(['b']); }); }); describe('toggleRole', () => { it('flips admin to player and vice versa', () => { expect(toggleRole('admin')).toBe('player'); expect(toggleRole('player')).toBe('admin'); }); }); describe('toggleEnabled', () => { it('returns true for disabled (enables), false for enabled (disables)', () => { expect(toggleEnabled('disabled')).toBe(true); expect(toggleEnabled('enabled')).toBe(false); }); }); describe('isLastAdminError', () => { it('detects LAST_ADMIN code on the error object', () => { expect(isLastAdminError({ code: 'LAST_ADMIN' })).toBe(true); expect(isLastAdminError({ error: { code: 'LAST_ADMIN' } })).toBe(true); expect(isLastAdminError({ response: { data: { code: 'LAST_ADMIN' } } })).toBe(true); expect(isLastAdminError({ code: 'NOT_FOUND' })).toBe(false); expect(isLastAdminError(null)).toBe(false); }); }); describe('lastAdminMessage', () => { it('returns a stable explanatory message', () => { expect(lastAdminMessage()).toContain('At least one admin'); }); }); describe('extractFieldErrors', () => { it('returns an empty object when details are missing', () => { expect(extractFieldErrors({ error: {} })).toEqual({}); expect(extractFieldErrors(null)).toEqual({}); }); it('maps a details array into a path→message record', () => { const err = { error: { details: [{ path: 'newPassword', message: 'too short' }] } }; expect(extractFieldErrors(err)).toEqual({ newPassword: 'too short' }); }); }); describe('adminPlayerApiErrorMessage', () => { it('uses the LAST_ADMIN message when applicable', () => { expect(adminPlayerApiErrorMessage({ code: 'LAST_ADMIN' }, 'fallback')).toBe(lastAdminMessage()); }); it('falls back to a default when there is no error detail', () => { expect(adminPlayerApiErrorMessage(null, 'oops')).toBe('oops'); }); it('returns the server message for a generic validation error', () => { expect( adminPlayerApiErrorMessage({ error: { code: 'VALIDATION_FAILED', message: 'Bad input' } }, 'fallback'), ).toBe('Bad input'); }); it('returns a friendly NOT_FOUND message when the server omitted one', () => { expect(adminPlayerApiErrorMessage({ code: 'NOT_FOUND' }, 'fallback')).toBe('User not found.'); }); }); });