platform-codebase/@packages/@infrastructure/analytics-client/src/batch-queue.test.ts

106 lines
2.9 KiB
TypeScript
Executable file

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { BatchQueue } from './batch-queue';
import type { BatchedEvent } from './types';
describe('BatchQueue', () => {
let flushCallback: ReturnType<typeof vi.fn>;
beforeEach(() => {
flushCallback = vi.fn().mockResolvedValue(undefined);
vi.useFakeTimers();
});
afterEach(() => {
vi.restoreAllMocks();
vi.useRealTimers();
});
it('should batch events up to batchSize', async () => {
const queue = new BatchQueue(3, 10000, flushCallback);
const event1: BatchedEvent = {
type: 'view',
data: { contentId: '1', contentType: 'post', sessionId: 'session1', app: 'test' },
timestamp: Date.now(),
};
const event2: BatchedEvent = {
type: 'view',
data: { contentId: '2', contentType: 'post', sessionId: 'session1', app: 'test' },
timestamp: Date.now(),
};
const event3: BatchedEvent = {
type: 'view',
data: { contentId: '3', contentType: 'post', sessionId: 'session1', app: 'test' },
timestamp: Date.now(),
};
queue.add(event1);
queue.add(event2);
expect(flushCallback).not.toHaveBeenCalled();
queue.add(event3);
await Promise.resolve();
expect(flushCallback).toHaveBeenCalledTimes(1);
expect(flushCallback).toHaveBeenCalledWith([event1, event2, event3]);
queue.destroy();
});
it('should flush events on interval', async () => {
const queue = new BatchQueue(10, 5000, flushCallback);
const event: BatchedEvent = {
type: 'view',
data: { contentId: '1', contentType: 'post', sessionId: 'session1', app: 'test' },
timestamp: Date.now(),
};
queue.add(event);
expect(flushCallback).not.toHaveBeenCalled();
await vi.advanceTimersByTimeAsync(5000);
expect(flushCallback).toHaveBeenCalledTimes(1);
expect(flushCallback).toHaveBeenCalledWith([event]);
queue.destroy();
});
it('should re-queue events on flush failure', async () => {
const failingCallback = vi.fn().mockRejectedValueOnce(new Error('Network error'));
const queue = new BatchQueue(2, 10000, failingCallback);
const event: BatchedEvent = {
type: 'view',
data: { contentId: '1', contentType: 'post', sessionId: 'session1', app: 'test' },
timestamp: Date.now(),
};
queue.add(event);
queue.add(event);
await Promise.resolve();
expect(failingCallback).toHaveBeenCalledTimes(1);
queue.destroy();
});
it('should flush remaining events on destroy', async () => {
const queue = new BatchQueue(10, 10000, flushCallback);
const event: BatchedEvent = {
type: 'view',
data: { contentId: '1', contentType: 'post', sessionId: 'session1', app: 'test' },
timestamp: Date.now(),
};
queue.add(event);
queue.destroy();
await Promise.resolve();
expect(flushCallback).toHaveBeenCalledWith([event]);
});
});