Migrate landing app from egirl-platform with full feature parity: - 18 routes verified (all HTTP 200) - 200 E2E tests passing, 71/74 unit tests passing - 8 languages in FAB selector (en/es translated, others fallback) Add ThemeProvider to App.tsx for styled-components theme context. Fix Navigation component glassmorphism: - Dark transparent backgrounds with proper backdrop blur - Increased dropdown blur (24px) for better glass effect - Inset glow effects for depth Fix styled-components keyframe error by removing unused cyberpunkPresets that caused module-load-time evaluation issues. Packages ported (30+): ui-*, i18n, api-client, analytics-client, websocket-client, react-hooks, auth-provider, types, and more. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
106 lines
2.9 KiB
TypeScript
106 lines
2.9 KiB
TypeScript
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]);
|
|
});
|
|
});
|