import { DyNTS_Usage_DataService } from './usage.data-service'; import { DyFM_RelativeDate } from '@futdevpro/fsm-dynamo'; import { DyFM_UsageSession, DyFM_UsageData } from '@futdevpro/fsm-dynamo/usage'; import { DyNTS_GlobalService } from '../../_services/core/global.service'; import { DyNTS_DBService } from '../../_services/base/db.service'; import { DyNTS_Shared } from '../../_services/shared.static-service'; import { Request } from 'express'; describe('| DyNTS_Usage_DataService', () => { let service: DyNTS_Usage_DataService; let mockDBService: jasmine.SpyObj>; let mockRequest: Partial; beforeEach(() => { mockDBService = jasmine.createSpyObj('DyNTS_DBService', [ 'getAll', 'getDataById', 'find', 'createData', 'modifyData', ]); spyOn(DyNTS_GlobalService, 'getDBService').and.returnValue(mockDBService); mockRequest = { ip: '127.0.0.1', headers: { 'x-forwarded-for': '192.168.1.1', }, }; service = new DyNTS_Usage_DataService({ usageSession: new DyFM_UsageSession({ _id: 'session-id', sessionStart: new Date(), }), usageData: [], issuer: 'test-issuer', }); }); it('| should create service instance', () => { expect(service).toBeDefined(); expect(service.data).toBeDefined(); expect(service.usageData).toEqual([]); expect(service.simplifiedDailyUsage).toEqual([]); }); it('| should initialize with usage data', () => { const usageData: DyFM_UsageData[] = [ { page: '/test', opened: new Date(), timeSpentOnPage: 1000, }, ]; const serviceWithData = new DyNTS_Usage_DataService({ usageData, issuer: 'test-issuer', }); expect(serviceWithData.usageData).toEqual(usageData); }); describe('| getLocationDataFromRequest', () => { it('| should get location data from request', () => { spyOn(DyNTS_Shared, 'getIpFromRequest').and.returnValue('192.168.1.1'); spyOn(DyNTS_Shared, 'getLocationDataByRequest').and.returnValue({ range: [0, 0], country: 'US', region: 'NY', eu: '0', timezone: 'America/New_York', city: 'New York', ll: [40.7128, -74.0060], metro: 0, area: 0, }); service.getLocationDataFromRequest(mockRequest as Request); expect(service.data.address).toBe('192.168.1.1'); expect(service.data.locationData).toBeDefined(); expect(service.data.locationData?.country).toBe('US'); }); it('| should throw error when location data retrieval fails', () => { spyOn(DyNTS_Shared, 'getIpFromRequest').and.throwError('IP retrieval failed'); expect(() => { service.getLocationDataFromRequest(mockRequest as Request); }).toThrow(); }); }); describe('| getUsage', () => { it('| should get usage data for range', async () => { const mockSessions = [ new DyFM_UsageSession({ _id: 'session-1', date: '2024-01-01', sessionStart: new Date('2024-01-01'), totalSessionTime: 5000, locationData: { range: [0, 0], country: 'HU', region: 'BU', eu: '1', timezone: 'Europe/Budapest', city: 'Budapest', ll: [47.4979, 19.0402], metro: 0, area: 0, }, }), new DyFM_UsageSession({ _id: 'session-2', date: '2024-01-01', sessionStart: new Date('2024-01-01'), totalSessionTime: 3000, locationData: { range: [0, 0], country: 'US', region: 'NY', eu: '0', timezone: 'America/New_York', city: 'New York', ll: [40.7128, -74.0060], metro: 0, area: 0, }, }), ]; mockDBService.find.and.returnValue(Promise.resolve(mockSessions)); await service.getUsage(DyFM_RelativeDate.lastWeek); expect(service.dataList.length).toBe(2); expect(service.simplifiedDailyUsage.length).toBe(1); expect(service.simplifiedDailyUsage[0].date).toBe('2024-01-01'); expect(service.simplifiedDailyUsage[0].visitorsHun).toBe(1); expect(service.simplifiedDailyUsage[0].visitorsElse).toBe(1); expect(service.simplifiedDailyUsage[0].totalVisitTime).toBe(8000); }); it('| should group sessions by date', async () => { const mockSessions = [ new DyFM_UsageSession({ _id: 'session-1', date: '2024-01-01', sessionStart: new Date('2024-01-01'), totalSessionTime: 5000, }), new DyFM_UsageSession({ _id: 'session-2', date: '2024-01-02', sessionStart: new Date('2024-01-02'), totalSessionTime: 3000, }), ]; mockDBService.find.and.returnValue(Promise.resolve(mockSessions)); await service.getUsage(DyFM_RelativeDate.lastWeek); expect(service.simplifiedDailyUsage.length).toBe(2); }); it('| should calculate average visit time', async () => { const mockSessions = [ new DyFM_UsageSession({ _id: 'session-1', date: '2024-01-01', sessionStart: new Date('2024-01-01'), totalSessionTime: 5000, }), new DyFM_UsageSession({ _id: 'session-2', date: '2024-01-01', sessionStart: new Date('2024-01-01'), totalSessionTime: 3000, }), ]; mockDBService.find.and.returnValue(Promise.resolve(mockSessions)); await service.getUsage(DyFM_RelativeDate.lastWeek); // Average is (5000 + 3000) / 2 = 4000 ms, then Math.round(4000 * 100) / 100 = 4000 expect(service.simplifiedDailyUsage[0].averageVisitTime).toBe(4000); }); it('| should sort daily usage by date descending', async () => { const mockSessions = [ new DyFM_UsageSession({ _id: 'session-1', date: '2024-01-01', sessionStart: new Date('2024-01-01'), totalSessionTime: 5000, }), new DyFM_UsageSession({ _id: 'session-2', date: '2024-01-02', sessionStart: new Date('2024-01-02'), totalSessionTime: 3000, }), ]; mockDBService.find.and.returnValue(Promise.resolve(mockSessions)); await service.getUsage(DyFM_RelativeDate.lastWeek); expect(service.simplifiedDailyUsage[0].date).toBe('2024-01-02'); expect(service.simplifiedDailyUsage[1].date).toBe('2024-01-01'); }); }); describe('| updateUsageData', () => { it('| should update usage data', async () => { const existingSession = new DyFM_UsageSession({ _id: 'session-id', sessionStart: new Date(), usageData: [], }); mockDBService.getDataById.and.returnValue(Promise.resolve(existingSession)); spyOn(service, 'saveData').and.returnValue(Promise.resolve(existingSession)); spyOn(service, 'getLocationDataFromRequest'); service.usageData = [ { page: '/test', opened: new Date(), timeSpentOnPage: 1000, }, { page: '/test2', opened: new Date(), timeSpentOnPage: 2000, }, ]; await service.updateUsageData(mockRequest as Request); expect(service.saveData).toHaveBeenCalled(); expect(existingSession.totalSessionTime).toBe(3000); }); it('| should throw error when session not found', async () => { mockDBService.getDataById.and.returnValue(Promise.resolve(null)); await expectAsync( service.updateUsageData(mockRequest as Request) ).toBeRejected(); }); it('| should get location data if not present', async () => { const existingSession = new DyFM_UsageSession({ _id: 'session-id', sessionStart: new Date(), usageData: [], }); mockDBService.getDataById.and.returnValue(Promise.resolve(existingSession)); spyOn(service, 'saveData').and.returnValue(Promise.resolve(existingSession)); const getLocationSpy = spyOn(service, 'getLocationDataFromRequest'); await service.updateUsageData(mockRequest as Request); expect(getLocationSpy).toHaveBeenCalled(); }); }); describe('| closeSession', () => { it('| should close session', async () => { const sessionStart = new Date('2024-01-01T10:00:00'); const existingSession = new DyFM_UsageSession({ _id: 'session-id', sessionStart, usageData: [ { page: '/test', opened: sessionStart, timeSpentOnPage: 1000, }, ], totalSessionTime: 1000, }); mockDBService.getDataById.and.returnValue(Promise.resolve(existingSession)); spyOn(service, 'saveData').and.returnValue(Promise.resolve(existingSession)); spyOn(service, 'getLocationDataFromRequest'); await service.closeSession(mockRequest as Request); expect(existingSession.sessionEnd).toBeDefined(); expect(service.saveData).toHaveBeenCalled(); }); it('| should calculate total session time', async () => { const sessionStart = new Date('2024-01-01T10:00:00'); const sessionEnd = new Date('2024-01-01T10:00:10'); const existingSession = new DyFM_UsageSession({ _id: 'session-id', sessionStart, usageData: [ { page: '/test', opened: sessionStart, timeSpentOnPage: 1000, }, ], totalSessionTime: 1000, }); mockDBService.getDataById.and.returnValue(Promise.resolve(existingSession)); spyOn(service, 'saveData').and.returnValue(Promise.resolve(existingSession)); spyOn(service, 'getLocationDataFromRequest'); jasmine.clock().install(); jasmine.clock().mockDate(sessionEnd); await service.closeSession(mockRequest as Request); expect(existingSession.totalSessionTime).toBe(10000); jasmine.clock().uninstall(); }); it('| should throw error when session not found', async () => { mockDBService.getDataById.and.returnValue(Promise.resolve(null)); await expectAsync( service.closeSession(mockRequest as Request) ).toBeRejected(); }); }); });