test(handler): add tests for LocalStorageHandler

This commit is contained in:
Tiara Rodney 2026-03-14 04:57:32 +01:00
parent 6fd8c22ceb
commit 37fd6194c7
No known key found for this signature in database
GPG key ID: 5CD8EC1D46106723

View file

@ -0,0 +1,158 @@
import {expect, jest, test, beforeEach, afterEach} from '@jest/globals';
import { LocalStorageHandler } from '../../src/handler';
import { LogRecord } from '../../src/log-record';
import { DEBUG, WARNING, ERROR } from '../../src/log-level';
// mock localStorage for Node/Jest environment
const store: {[key: string]: string} = {};
const localStorageMock = {
getItem: (key: string): string | null => store[key] ?? null,
setItem: (key: string, value: string) => { store[key] = value },
removeItem: (key: string) => { delete store[key] },
};
function clearStore() {
for (const key of Object.keys(store)) { delete store[key] }
}
function makeRecord(level: number, msg: string): LogRecord {
return new LogRecord('test', { level, msg });
}
beforeEach(() => {
clearStore();
(globalThis as any).localStorage = localStorageMock;
});
afterEach(() => {
clearStore();
delete (globalThis as any).localStorage;
});
describe('LocalStorageHandler', () => {
describe('constructor', () => {
test('uses default key and limits', () => {
const h = new LocalStorageHandler();
expect(h.getEntries()).toEqual([]);
});
test('throws when localStorage is unavailable', () => {
delete (globalThis as any).localStorage;
expect(() => new LocalStorageHandler()).toThrow(
'requires a browser environment'
);
});
test('accepts custom options', () => {
const h = new LocalStorageHandler({
key: 'custom-log',
maxEntries: 50,
maxBytes: 4096,
});
h.emit(makeRecord(DEBUG, 'test'));
expect(store['custom-log']).toBeDefined();
expect(store['esm-logging']).toBeUndefined();
});
});
describe('emit', () => {
test('stores formatted log entry', () => {
const h = new LocalStorageHandler();
h.emit(makeRecord(WARNING, 'hello'));
const entries = h.getEntries();
expect(entries.length).toBe(1);
expect(entries[0]).toContain('hello');
});
test('appends multiple entries', () => {
const h = new LocalStorageHandler();
h.emit(makeRecord(DEBUG, 'first'));
h.emit(makeRecord(DEBUG, 'second'));
h.emit(makeRecord(DEBUG, 'third'));
expect(h.getEntries().length).toBe(3);
});
test('persists across handler instances with same key', () => {
const h1 = new LocalStorageHandler({ key: 'shared' });
h1.emit(makeRecord(DEBUG, 'from h1'));
const h2 = new LocalStorageHandler({ key: 'shared' });
const entries = h2.getEntries();
expect(entries.length).toBe(1);
expect(entries[0]).toContain('from h1');
});
});
describe('rotation by entry count', () => {
test('discards oldest entries when maxEntries exceeded', () => {
const h = new LocalStorageHandler({ maxEntries: 3 });
h.emit(makeRecord(DEBUG, 'msg-1'));
h.emit(makeRecord(DEBUG, 'msg-2'));
h.emit(makeRecord(DEBUG, 'msg-3'));
h.emit(makeRecord(DEBUG, 'msg-4'));
const entries = h.getEntries();
expect(entries.length).toBe(3);
expect(entries[0]).toContain('msg-2');
expect(entries[2]).toContain('msg-4');
});
test('maxEntries of 1 keeps only the latest', () => {
const h = new LocalStorageHandler({ maxEntries: 1 });
h.emit(makeRecord(DEBUG, 'old'));
h.emit(makeRecord(DEBUG, 'new'));
const entries = h.getEntries();
expect(entries.length).toBe(1);
expect(entries[0]).toContain('new');
});
});
describe('rotation by byte size', () => {
test('discards oldest entries when maxBytes exceeded', () => {
const h = new LocalStorageHandler({ maxEntries: 0, maxBytes: 100 });
// emit entries until we exceed the limit
for (let i = 0; i < 20; i++) {
h.emit(makeRecord(DEBUG, `message-${i}`));
}
const entries = h.getEntries();
const serialized = JSON.stringify(entries);
expect(serialized.length).toBeLessThanOrEqual(100);
expect(entries.length).toBeGreaterThan(0);
});
});
describe('getEntries', () => {
test('returns empty array when no entries', () => {
const h = new LocalStorageHandler();
expect(h.getEntries()).toEqual([]);
});
test('returns empty array on corrupt data', () => {
store['esm-logging'] = 'not valid json{{{';
const h = new LocalStorageHandler();
expect(h.getEntries()).toEqual([]);
});
});
describe('clearEntries', () => {
test('removes all stored entries', () => {
const h = new LocalStorageHandler();
h.emit(makeRecord(DEBUG, 'to be cleared'));
expect(h.getEntries().length).toBe(1);
h.clearEntries();
expect(h.getEntries()).toEqual([]);
});
});
describe('close', () => {
test('sets closed to true', () => {
const h = new LocalStorageHandler();
expect(h.closed).toBe(false);
h.close();
expect(h.closed).toBe(true);
});
});
});