94 lines
3.2 KiB
TypeScript
94 lines
3.2 KiB
TypeScript
import {
|
|
CROSS_TAB_CHANNEL_NAME,
|
|
CROSS_TAB_STORAGE_KEY,
|
|
CrossTabInvalidationMessage,
|
|
encodeInvalidationMessage,
|
|
isCrossTabInvalidationMessage,
|
|
isStorageInvalidationEvent,
|
|
} from '../../frontend/src/app/core/services/auth-session-events.pure';
|
|
|
|
describe('auth-session-events.pure', () => {
|
|
describe('encodeInvalidationMessage', () => {
|
|
it('produces a session-invalidated message with origin and timestamp', () => {
|
|
const before = Date.now();
|
|
const msg = encodeInvalidationMessage('tab-A');
|
|
const after = Date.now();
|
|
expect(msg.type).toBe('session-invalidated');
|
|
expect(msg.origin).toBe('tab-A');
|
|
expect(msg.ts).toBeGreaterThanOrEqual(before);
|
|
expect(msg.ts).toBeLessThanOrEqual(after);
|
|
});
|
|
});
|
|
|
|
describe('isCrossTabInvalidationMessage', () => {
|
|
it('accepts a properly shaped message', () => {
|
|
const msg: CrossTabInvalidationMessage = {
|
|
type: 'session-invalidated',
|
|
origin: 'x',
|
|
ts: 1,
|
|
};
|
|
expect(isCrossTabInvalidationMessage(msg)).toBe(true);
|
|
});
|
|
|
|
it('rejects non-objects', () => {
|
|
expect(isCrossTabInvalidationMessage(null)).toBe(false);
|
|
expect(isCrossTabInvalidationMessage(undefined)).toBe(false);
|
|
expect(isCrossTabInvalidationMessage('string')).toBe(false);
|
|
expect(isCrossTabInvalidationMessage(42)).toBe(false);
|
|
});
|
|
|
|
it('rejects objects with wrong type or missing fields', () => {
|
|
expect(isCrossTabInvalidationMessage({ type: 'other', origin: 'a', ts: 1 })).toBe(false);
|
|
expect(isCrossTabInvalidationMessage({ type: 'session-invalidated', origin: 1, ts: 1 })).toBe(
|
|
false,
|
|
);
|
|
expect(isCrossTabInvalidationMessage({ type: 'session-invalidated', origin: 'a' })).toBe(
|
|
false,
|
|
);
|
|
expect(
|
|
isCrossTabInvalidationMessage({ type: 'session-invalidated', origin: 'a', ts: 'now' }),
|
|
).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('isStorageInvalidationEvent', () => {
|
|
it('accepts a well-formed storage event for the namespaced key', () => {
|
|
const ev = {
|
|
key: CROSS_TAB_STORAGE_KEY,
|
|
newValue: JSON.stringify(encodeInvalidationMessage('tab-X')),
|
|
};
|
|
expect(isStorageInvalidationEvent(ev)).toBe(true);
|
|
});
|
|
|
|
it('rejects events with a different key', () => {
|
|
const ev = {
|
|
key: 'other.key',
|
|
newValue: JSON.stringify(encodeInvalidationMessage('tab-X')),
|
|
};
|
|
expect(isStorageInvalidationEvent(ev)).toBe(false);
|
|
});
|
|
|
|
it('rejects events with no newValue (cleared key)', () => {
|
|
const ev = { key: CROSS_TAB_STORAGE_KEY, newValue: null };
|
|
expect(isStorageInvalidationEvent(ev)).toBe(false);
|
|
});
|
|
|
|
it('rejects malformed JSON payloads', () => {
|
|
const ev = { key: CROSS_TAB_STORAGE_KEY, newValue: 'not-json' };
|
|
expect(isStorageInvalidationEvent(ev)).toBe(false);
|
|
});
|
|
|
|
it('rejects nullish events', () => {
|
|
expect(isStorageInvalidationEvent(null)).toBe(false);
|
|
expect(isStorageInvalidationEvent(undefined)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('constant exports', () => {
|
|
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');
|
|
});
|
|
});
|
|
});
|