lotr-sut/sut/frontend/test/services/analyticsService.test.ts
Fellowship Scholar f6a5823439 init commit
2026-03-29 20:07:56 +00:00

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();
});
});
});