AI Implementation feature(913): Admin Area Players Management 1.00 (#57)
This commit was merged in pull request #57.
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
import {
|
||||
CROSS_TAB_CHANNEL_NAME,
|
||||
CROSS_TAB_STORAGE_KEY,
|
||||
CROSS_TAB_ROLE_CHANNEL_NAME,
|
||||
CROSS_TAB_ROLE_STORAGE_KEY,
|
||||
CrossTabInvalidationMessage,
|
||||
CrossTabRoleChangeMessage,
|
||||
applyRoleChangeToUser,
|
||||
encodeInvalidationMessage,
|
||||
encodeRoleChangeMessage,
|
||||
isCrossTabInvalidationMessage,
|
||||
isCrossTabRoleChangeMessage,
|
||||
isStorageInvalidationEvent,
|
||||
isStorageRoleChangeEvent,
|
||||
} from '../../frontend/src/app/core/services/auth-session-events.pure';
|
||||
|
||||
describe('auth-session-events.pure', () => {
|
||||
@@ -88,6 +95,105 @@ describe('auth-session-events.pure', () => {
|
||||
it('exposes a stable channel name and storage key', () => {
|
||||
expect(CROSS_TAB_CHANNEL_NAME).toBe('hipctf.auth.v1');
|
||||
expect(CROSS_TAB_STORAGE_KEY).toBe('hipctf.auth.invalidate.v1');
|
||||
expect(CROSS_TAB_ROLE_CHANNEL_NAME).toBe('hipctf.auth.role.v1');
|
||||
expect(CROSS_TAB_ROLE_STORAGE_KEY).toBe('hipctf.role.invalidate.v1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('encodeRoleChangeMessage', () => {
|
||||
it('produces a role-changed message with userId and newRole', () => {
|
||||
const before = Date.now();
|
||||
const msg = encodeRoleChangeMessage('tab-A', 'user-1', 'player');
|
||||
const after = Date.now();
|
||||
expect(msg.type).toBe('role-changed');
|
||||
expect(msg.origin).toBe('tab-A');
|
||||
expect(msg.userId).toBe('user-1');
|
||||
expect(msg.newRole).toBe('player');
|
||||
expect(msg.ts).toBeGreaterThanOrEqual(before);
|
||||
expect(msg.ts).toBeLessThanOrEqual(after);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isCrossTabRoleChangeMessage', () => {
|
||||
it('accepts a properly shaped message', () => {
|
||||
const msg: CrossTabRoleChangeMessage = {
|
||||
type: 'role-changed',
|
||||
origin: 'x',
|
||||
ts: 1,
|
||||
userId: 'u1',
|
||||
newRole: 'player',
|
||||
};
|
||||
expect(isCrossTabRoleChangeMessage(msg)).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects a session-invalidated message (does not double-fire)', () => {
|
||||
const msg: CrossTabInvalidationMessage = { type: 'session-invalidated', origin: 'x', ts: 1 };
|
||||
expect(isCrossTabRoleChangeMessage(msg)).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects objects with wrong/missing fields', () => {
|
||||
expect(isCrossTabRoleChangeMessage({ type: 'role-changed', origin: 'a', ts: 1, userId: 'u', newRole: 'super' })).toBe(
|
||||
false,
|
||||
);
|
||||
expect(isCrossTabRoleChangeMessage({ type: 'role-changed', origin: 'a', ts: 1, userId: 1, newRole: 'admin' })).toBe(
|
||||
false,
|
||||
);
|
||||
expect(isCrossTabRoleChangeMessage({ type: 'role-changed', origin: 'a', ts: 'now', userId: 'u', newRole: 'admin' })).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects non-objects', () => {
|
||||
expect(isCrossTabRoleChangeMessage(null)).toBe(false);
|
||||
expect(isCrossTabRoleChangeMessage(undefined)).toBe(false);
|
||||
expect(isCrossTabRoleChangeMessage('string')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isStorageRoleChangeEvent', () => {
|
||||
it('accepts a well-formed storage event for the role key', () => {
|
||||
const ev = {
|
||||
key: CROSS_TAB_ROLE_STORAGE_KEY,
|
||||
newValue: JSON.stringify(encodeRoleChangeMessage('tab-X', 'u1', 'player')),
|
||||
};
|
||||
expect(isStorageRoleChangeEvent(ev)).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects events with a different key', () => {
|
||||
const ev = {
|
||||
key: 'something.else',
|
||||
newValue: JSON.stringify(encodeRoleChangeMessage('tab-X', 'u1', 'player')),
|
||||
};
|
||||
expect(isStorageRoleChangeEvent(ev)).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects malformed JSON payloads', () => {
|
||||
const ev = { key: CROSS_TAB_ROLE_STORAGE_KEY, newValue: 'not-json' };
|
||||
expect(isStorageRoleChangeEvent(ev)).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects nullish events', () => {
|
||||
expect(isStorageRoleChangeEvent(null)).toBe(false);
|
||||
expect(isStorageRoleChangeEvent(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('applyRoleChangeToUser', () => {
|
||||
it('returns a new user with the updated role when they differ', () => {
|
||||
const u = { id: 'u1', role: 'admin' as const };
|
||||
const out = applyRoleChangeToUser(u, 'player');
|
||||
expect(out).toEqual({ id: 'u1', role: 'player' });
|
||||
expect(out).not.toBe(u);
|
||||
});
|
||||
|
||||
it('returns the same user object (no-op) when role already matches', () => {
|
||||
const u = { id: 'u1', role: 'player' as const };
|
||||
const out = applyRoleChangeToUser(u, 'player');
|
||||
expect(out).toBe(u);
|
||||
});
|
||||
|
||||
it('returns the input untouched for null users', () => {
|
||||
expect(applyRoleChangeToUser(null, 'admin')).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user