feat: Admin Area Players Management
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
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.');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -57,3 +57,15 @@ describe('formatChangePasswordError', () => {
|
||||
expect(formatChangePasswordError({ code: null, message: null })).toBe('Failed to change password');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ChangePasswordModalComponent admin-reset field errors', () => {
|
||||
it('maps a fieldErrors record to per-path messages', () => {
|
||||
const errors: Record<string, string> = {
|
||||
newPassword: 'Password too short',
|
||||
confirmPassword: 'Confirmation does not match',
|
||||
};
|
||||
expect(errors['newPassword']).toBe('Password too short');
|
||||
expect(errors['confirmPassword']).toBe('Confirmation does not match');
|
||||
expect(errors['confirmNewPassword']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user