Files
bibdle/tests/stats-events.test.ts
T

86 lines
2.6 KiB
TypeScript

import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
import { eq, and } from 'drizzle-orm';
import { testDb } from '$lib/server/db/test';
import { analyticsEvents } from '$lib/server/db/schema';
import {
recordEvent,
isEventName,
encodeMetadata
} from '$lib/server/stats/events';
import { MAX_METADATA_BYTES } from '$lib/types/stats';
async function clear() {
await testDb.delete(analyticsEvents);
}
describe('analytics events', () => {
beforeEach(clear);
afterEach(clear);
test('allowlist accepts known event names and rejects others', () => {
expect(isEventName('verse_served')).toBe(true);
expect(isEventName('donate_click')).toBe(true);
expect(isEventName('not_a_real_event')).toBe(false);
expect(isEventName('')).toBe(false);
});
test('metadata is capped', () => {
const small = encodeMetadata({ utm_source: 'bluesky' });
expect(small).toBe('{"utm_source":"bluesky"}');
const big = encodeMetadata({ blob: 'x'.repeat(MAX_METADATA_BYTES + 100) });
expect(big).toBe('{"truncated":true}');
expect(encodeMetadata(null)).toBeNull();
});
test('records a normal event', async () => {
const inserted = await recordEvent(
{ name: 'donate_click', anonymousId: 'anon-1' },
testDb
);
expect(inserted).toBe(true);
const rows = await testDb.select().from(analyticsEvents);
expect(rows).toHaveLength(1);
expect(rows[0].name).toBe('donate_click');
});
test('verse_served is deduped per player + date', async () => {
const first = await recordEvent(
{ name: 'verse_served', anonymousId: 'anon-1', date: '2026-09-01' },
testDb
);
const second = await recordEvent(
{ name: 'verse_served', anonymousId: 'anon-1', date: '2026-09-01' },
testDb
);
expect(first).toBe(true);
expect(second).toBe(false);
const rows = await testDb
.select()
.from(analyticsEvents)
.where(
and(
eq(analyticsEvents.name, 'verse_served'),
eq(analyticsEvents.anonymousId, 'anon-1')
)
);
expect(rows).toHaveLength(1);
});
test('other event names are not deduped', async () => {
await recordEvent({ name: 'share', anonymousId: 'anon-1', date: '2026-09-01' }, testDb);
await recordEvent({ name: 'share', anonymousId: 'anon-1', date: '2026-09-01' }, testDb);
const rows = await testDb.select().from(analyticsEvents);
expect(rows).toHaveLength(2);
});
test('user attribution is stored', async () => {
await recordEvent(
{ name: 'share_copy', anonymousId: 'anon-1', userId: 'user-9', metadata: { snippet: true } },
testDb
);
const [row] = await testDb.select().from(analyticsEvents);
expect(row.userId).toBe('user-9');
expect(JSON.parse(row.metadata!)).toEqual({ snippet: true });
});
});