274 lines
8.0 KiB
TypeScript
274 lines
8.0 KiB
TypeScript
/**
|
|
* Unit Tests for Analytics Service
|
|
* Tests the analyticsService for proper event tracking and user property management
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
|
|
import { analyticsService, AnalyticsEvents, AnalyticsUserProperties } from '../../src/services/analyticsService';
|
|
|
|
// Mock gtag function
|
|
const mockGtag = vi.fn();
|
|
|
|
// Setup gtag in global window before tests
|
|
if (typeof window !== 'undefined') {
|
|
(window as any).gtag = mockGtag;
|
|
}
|
|
|
|
describe('Analytics Service', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
// Re-enable analytics for each test
|
|
analyticsService.setEnabled(true);
|
|
});
|
|
|
|
describe('Event Tracking', () => {
|
|
it('should track user signup event', () => {
|
|
analyticsService.trackSignup('frodo_baggins');
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.USER_SIGNUP, {
|
|
username: 'frodo_baggins',
|
|
});
|
|
});
|
|
|
|
it('should track user login event', () => {
|
|
analyticsService.trackLogin('gandalf');
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.USER_LOGIN, {
|
|
username: 'gandalf',
|
|
});
|
|
});
|
|
|
|
it('should track user logout event', () => {
|
|
analyticsService.trackLogout();
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.USER_LOGOUT, {});
|
|
});
|
|
|
|
it('should track quest creation', () => {
|
|
analyticsService.trackQuestCreated(1, 'Find the Ring', 'The Ring');
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.QUEST_CREATED, {
|
|
quest_id: 1,
|
|
quest_title: 'Find the Ring',
|
|
quest_type: 'The Ring',
|
|
});
|
|
});
|
|
|
|
it('should track quest completion', () => {
|
|
analyticsService.trackQuestCompleted(5, 'Destroy the Ring', 'Trivia');
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.QUEST_COMPLETED, {
|
|
quest_id: 5,
|
|
quest_title: 'Destroy the Ring',
|
|
game_type: 'Trivia',
|
|
});
|
|
});
|
|
|
|
it('should track game completion', () => {
|
|
analyticsService.trackGameCompleted('memory', 95);
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.GAME_COMPLETED, {
|
|
game_type: 'memory',
|
|
score: 95,
|
|
});
|
|
});
|
|
|
|
it('should track game failure', () => {
|
|
analyticsService.trackGameFailed('reaction', 'timeout');
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.GAME_FAILED, {
|
|
game_type: 'reaction',
|
|
reason: 'timeout',
|
|
});
|
|
});
|
|
|
|
it('should track bargain initiation', () => {
|
|
analyticsService.trackBargainInitiated();
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.BARGAIN_INITIATED, {});
|
|
});
|
|
|
|
it('should track successful bargain', () => {
|
|
analyticsService.trackBargainCompleted('Mithril Coat', 500);
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.BARGAIN_COMPLETED, {
|
|
item_name: 'Mithril Coat',
|
|
bargain_value: 500,
|
|
});
|
|
});
|
|
|
|
it('should track item purchase', () => {
|
|
analyticsService.trackItemPurchased('Sword of Elendil', 250, 42);
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.ITEM_PURCHASED, {
|
|
item_name: 'Sword of Elendil',
|
|
item_id: 42,
|
|
price: 250,
|
|
currency: 'gold',
|
|
});
|
|
});
|
|
|
|
it('should track NPC chat initiation', () => {
|
|
analyticsService.trackNpcChatInitiated('Gandalf');
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.NPC_CHAT_INITIATED, {
|
|
character: 'Gandalf',
|
|
});
|
|
});
|
|
|
|
it('should track NPC message sent', () => {
|
|
analyticsService.trackNpcMessageSent('Frodo', 42);
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.NPC_MESSAGE_SENT, {
|
|
character: 'Frodo',
|
|
message_length: 42,
|
|
});
|
|
});
|
|
|
|
it('should track inventory viewed', () => {
|
|
analyticsService.trackInventoryViewed(8);
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.INVENTORY_VIEWED, {
|
|
item_count: 8,
|
|
});
|
|
});
|
|
|
|
it('should track inventory item added', () => {
|
|
analyticsService.trackInventoryItemAdded('Mithril Coat', 1);
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.INVENTORY_ITEM_ADDED, {
|
|
item_name: 'Mithril Coat',
|
|
quantity: 1,
|
|
});
|
|
});
|
|
|
|
it('should track page view', () => {
|
|
analyticsService.trackPageView('/dashboard', 'The Council Chamber');
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', 'page_view', {
|
|
page_title: 'The Council Chamber',
|
|
page_location: window.location.href,
|
|
});
|
|
});
|
|
|
|
it('should track map viewed', () => {
|
|
analyticsService.trackMapViewed();
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.MAP_VIEWED, {
|
|
page_title: 'Middle-earth Map',
|
|
});
|
|
});
|
|
|
|
it('should track dashboard viewed', () => {
|
|
analyticsService.trackDashboardViewed();
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.DASHBOARD_VIEWED, {
|
|
page_title: 'The Council Chamber',
|
|
});
|
|
});
|
|
|
|
it('should track quests page viewed', () => {
|
|
analyticsService.trackQuestsPageViewed();
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.QUESTS_PAGE_VIEWED, {
|
|
page_title: 'Quests',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('User Properties', () => {
|
|
it('should set user properties', () => {
|
|
analyticsService.setUserProperties({
|
|
character_name: 'Frodo',
|
|
user_type: 'fellowship_member',
|
|
});
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('config', {
|
|
character_name: 'Frodo',
|
|
user_type: 'fellowship_member',
|
|
});
|
|
});
|
|
|
|
it('should set user ID', () => {
|
|
analyticsService.setUserId(123);
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('config', {
|
|
'user_id': '123',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Analytics Management', () => {
|
|
it('should check if analytics is enabled', () => {
|
|
expect(analyticsService.isAnalyticsEnabled()).toBe(true);
|
|
});
|
|
|
|
it('should enable/disable analytics', () => {
|
|
analyticsService.setEnabled(false);
|
|
expect(analyticsService.isAnalyticsEnabled()).toBe(false);
|
|
|
|
analyticsService.setEnabled(true);
|
|
expect(analyticsService.isAnalyticsEnabled()).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('Default Values', () => {
|
|
it('should handle game completion with default score', () => {
|
|
analyticsService.trackGameCompleted('trivia');
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.GAME_COMPLETED, {
|
|
game_type: 'trivia',
|
|
score: 0,
|
|
});
|
|
});
|
|
|
|
it('should handle inventory without item count', () => {
|
|
analyticsService.trackInventoryViewed();
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.INVENTORY_VIEWED, {
|
|
item_count: 0,
|
|
});
|
|
});
|
|
|
|
it('should handle quest creation without type', () => {
|
|
analyticsService.trackQuestCreated(1, 'A Quest');
|
|
|
|
expect(mockGtag).toHaveBeenCalledWith('event', AnalyticsEvents.QUEST_CREATED, {
|
|
quest_id: 1,
|
|
quest_title: 'A Quest',
|
|
quest_type: 'unknown',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Error Handling', () => {
|
|
it('should handle gtag errors gracefully', () => {
|
|
mockGtag.mockImplementationOnce(() => {
|
|
throw new Error('GTags error');
|
|
});
|
|
|
|
// Should not throw
|
|
expect(() => {
|
|
analyticsService.trackLogin('user');
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('should log errors to console', () => {
|
|
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
|
|
mockGtag.mockImplementationOnce(() => {
|
|
throw new Error('GTags error');
|
|
});
|
|
|
|
analyticsService.trackLogin('user');
|
|
|
|
expect(consoleSpy).toHaveBeenCalledWith(
|
|
'Error tracking analytics event:',
|
|
expect.any(Error)
|
|
);
|
|
|
|
consoleSpy.mockRestore();
|
|
});
|
|
});
|
|
});
|