Add analytics plugin package for tracking and metrics. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
125 lines
3.3 KiB
TypeScript
125 lines
3.3 KiB
TypeScript
/**
|
|
* Unit Tests for Analytics Client
|
|
* Tests tracking methods, batching, and error handling
|
|
*/
|
|
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
|
|
// Mock fetch
|
|
const mockFetch = vi.fn();
|
|
global.fetch = mockFetch;
|
|
|
|
import { AnalyticsClient } from './analytics-client';
|
|
|
|
describe('AnalyticsClient', () => {
|
|
let client: AnalyticsClient;
|
|
|
|
beforeEach(() => {
|
|
mockFetch.mockClear();
|
|
mockFetch.mockResolvedValue({ ok: true, json: () => Promise.resolve({}) });
|
|
client = new AnalyticsClient({
|
|
apiBaseUrl: 'https://api.test.com',
|
|
appName: 'test-app',
|
|
batchSize: 10,
|
|
batchInterval: 1000,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
client.destroy();
|
|
vi.clearAllTimers();
|
|
});
|
|
|
|
describe('constructor', () => {
|
|
it('should create client with required options', () => {
|
|
const testClient = new AnalyticsClient({
|
|
apiBaseUrl: 'https://api.test.com',
|
|
appName: 'test',
|
|
});
|
|
expect(testClient).toBeDefined();
|
|
testClient.destroy();
|
|
});
|
|
|
|
it('should accept custom batch options', () => {
|
|
const customClient = new AnalyticsClient({
|
|
apiBaseUrl: 'https://custom.api.com',
|
|
appName: 'custom-app',
|
|
batchSize: 50,
|
|
batchInterval: 5000,
|
|
});
|
|
expect(customClient).toBeDefined();
|
|
customClient.destroy();
|
|
});
|
|
});
|
|
|
|
describe('trackView', () => {
|
|
it('should track view event with path', () => {
|
|
client.trackView({ path: '/dashboard', userId: 'user-123' });
|
|
expect(client).toBeDefined();
|
|
});
|
|
|
|
it('should track view with all optional fields', () => {
|
|
client.trackView({
|
|
path: '/analytics/revenue',
|
|
userId: 'user-456',
|
|
referrer: 'https://google.com',
|
|
});
|
|
expect(client).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('trackEngagement', () => {
|
|
it('should track engagement event', () => {
|
|
client.trackEngagement({
|
|
type: 'click',
|
|
target: 'submit-button',
|
|
});
|
|
expect(client).toBeDefined();
|
|
});
|
|
|
|
it('should track engagement with metadata', () => {
|
|
client.trackEngagement({
|
|
type: 'like',
|
|
target: 'post-123',
|
|
metadata: { source: 'feed' },
|
|
});
|
|
expect(client).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('flush', () => {
|
|
it('should send batched events', async () => {
|
|
client.trackView({ path: '/test', userId: 'test-user' });
|
|
await client.flush();
|
|
expect(mockFetch).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle flush errors gracefully', async () => {
|
|
mockFetch.mockRejectedValueOnce(new Error('Network error'));
|
|
client.trackView({ path: '/test', userId: 'test-user' });
|
|
// Should not throw
|
|
await expect(client.flush()).resolves.not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('destroy', () => {
|
|
it('should clean up resources', () => {
|
|
const testClient = new AnalyticsClient({
|
|
apiBaseUrl: 'https://api.test.com',
|
|
appName: 'test',
|
|
});
|
|
expect(() => testClient.destroy()).not.toThrow();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('AnalyticsClient Session', () => {
|
|
it('should generate session ID', () => {
|
|
const client = new AnalyticsClient({
|
|
apiBaseUrl: 'https://api.test.com',
|
|
appName: 'test',
|
|
});
|
|
expect(client).toBeDefined();
|
|
client.destroy();
|
|
});
|
|
});
|