openreplay/frontend/tests/unit/sessionStore.test.ts
Andrey Babushkin 09c98b5bde
E2e tests frontend (#3471)
* add playwright

* add e2e test

* add test

* add e2e test

* add e2e tests
2025-06-03 12:09:10 +02:00

355 lines
11 KiB
TypeScript

import { sessionService } from '../../app/services';
import Session from '../../app/types/session';
import { beforeEach, describe, expect, it, jest } from '@jest/globals';
import SessionStore from '../../app/mstore/sessionStore';
import { searchStore } from '../../app/mstore/index';
import { checkEventWithFilters } from '../../app/components/Session_/Player/Controls/checkEventWithFilters';
import { mockSession } from '../mocks/sessionData';
jest.mock('../../app/player', () => ({
createWebPlayer: jest.fn(),
createIOSPlayer: jest.fn(),
createClickMapPlayer: jest.fn(),
createLiveWebPlayer: jest.fn(),
createClipPlayer: jest.fn(),
}));
jest.mock('../../app/services', () => ({
sessionService: {
getSessions: jest.fn(),
getLiveSessions: jest.fn(),
getSessionInfo: jest.fn(),
getSessionEvents: jest.fn(),
getSessionNotes: jest.fn(),
getFavoriteSessions: jest.fn(),
getSessionClickMap: jest.fn(),
toggleFavorite: jest.fn(),
getClickMap: jest.fn(),
getAutoplayList: jest.fn(),
getFirstMobUrl: jest.fn(),
},
}));
jest.mock('App/player/web/network/loadFiles', () => ({
loadFile: jest.fn(),
}));
jest.mock(
'@/components/Session_/Player/Controls/checkEventWithFilters',
() => ({
checkEventWithFilters: jest.fn(),
}),
);
jest.mock('../../app/mstore/index', () => ({
searchStore: {
instance: {
filters: [],
events: [],
toSearch: jest.fn().mockReturnValue({}),
},
},
searchStoreLive: {
instance: {
filters: [],
events: [],
},
},
}));
describe('SessionStore', () => {
let sessionStore: SessionStore;
beforeEach(() => {
jest.clearAllMocks();
sessionStore = new SessionStore();
});
describe('resetUserFilter', () => {
it('should reset user filter', () => {
sessionStore.userFilter.update('page', 5);
expect(sessionStore.userFilter.page).toBe(5);
sessionStore.resetUserFilter();
expect(sessionStore.userFilter.page).toBe(1);
});
});
describe('fetchLiveSessions', () => {
it('should fetch and set live sessions', async () => {
const mockResponse = {
sessions: [{ sessionId: 'live-1', userId: 'user1' }],
total: 1,
};
(sessionService.getLiveSessions as jest.Mock).mockResolvedValue(
mockResponse,
);
await sessionStore.fetchLiveSessions({ sort: 'timestamp' });
expect(sessionService.getLiveSessions).toHaveBeenCalledWith({
sort: 'timestamp',
});
expect(sessionStore.liveSessions.length).toBe(1);
expect(sessionStore.liveSessions[0].sessionId).toBe('live-1');
expect(sessionStore.liveSessions[0].live).toBe(true);
expect(sessionStore.totalLiveSessions).toBe(1);
expect(sessionStore.loadingLiveSessions).toBe(false);
});
it('should handle duration sort by converting to timestamp', async () => {
(sessionService.getLiveSessions as jest.Mock).mockResolvedValue({
sessions: [],
total: 0,
});
await sessionStore.fetchLiveSessions({ sort: 'duration', order: 'asc' });
expect(sessionService.getLiveSessions).toHaveBeenCalledWith({
sort: 'timestamp',
order: 'desc',
});
});
it('should handle errors and set loading to false', async () => {
const mockError = new Error('API error');
console.error = jest.fn();
(sessionService.getLiveSessions as jest.Mock).mockRejectedValue(
mockError,
);
await sessionStore.fetchLiveSessions();
expect(console.error).toHaveBeenCalledWith(mockError);
expect(sessionStore.loadingLiveSessions).toBe(false);
});
});
describe('fetchSessions', () => {
it('should fetch and set sessions', async () => {
const mockResponse = {
sessions: [
new Session(mockSession({ sessionId: '1', favorite: true })),
new Session(mockSession({ sessionId: '2' })),
],
total: 2,
};
(sessionService.getSessions as jest.Mock).mockResolvedValue(mockResponse);
await sessionStore.fetchSessions({ page: 1, filters: [] }, true);
expect(sessionService.getSessions).toHaveBeenCalledWith({
page: 1,
filters: [],
});
expect(sessionStore.list.length).toBe(2);
expect(sessionStore.total).toBe(2);
expect(sessionStore.sessionIds).toEqual(['1', '2']);
expect(sessionStore.favoriteList.length).toBe(1);
expect(sessionStore.favoriteList[0].sessionId).toBe('1');
expect(sessionStore.loadingSessions).toBe(false);
});
it('should handle errors and set loading to false', async () => {
const mockError = new Error('API error');
console.error = jest.fn();
(sessionService.getSessions as jest.Mock).mockRejectedValue(mockError);
await sessionStore.fetchSessions({ filters: [] }, true);
expect(console.error).toHaveBeenCalledWith(mockError);
expect(sessionStore.loadingSessions).toBe(false);
});
});
describe('clearAll', () => {
it('should clear session list and current session', () => {
sessionStore.list = [new Session({ sessionId: 'test' })];
sessionStore.current = new Session({ sessionId: 'current' });
sessionStore.clearAll();
expect(sessionStore.list).toEqual([]);
expect(sessionStore.current.sessionId).toBe('');
});
});
describe('fetchSessionData', () => {
it('should fetch and set session data with events', async () => {
const mockSessionId = 'test-session-id';
const mockSessionInfo = { sessionId: mockSessionId, userId: 'user1' };
const mockEventsData = {
events: [
{ type: 'LOCATION', url: 'https://example.com', time: 100 },
{ type: 'CLICK', value: 'button', time: 200 },
],
errors: [],
crashes: [],
issues: [],
resources: [],
stackEvents: [],
userEvents: [],
userTesting: [],
};
(sessionService.getSessionInfo as jest.Mock).mockResolvedValue(
mockSessionInfo,
);
(sessionService.getSessionEvents as jest.Mock).mockResolvedValue(
mockEventsData,
);
(checkEventWithFilters as jest.Mock).mockReturnValue(false);
await sessionStore.fetchSessionData(mockSessionId);
expect(sessionService.getSessionInfo).toHaveBeenCalledWith(
mockSessionId,
false,
);
expect(sessionService.getSessionEvents).toHaveBeenCalledWith(
mockSessionId,
);
expect(sessionStore.current.sessionId).toBe(mockSessionId);
expect(sessionStore.visitedEvents.length).toBe(1);
expect(sessionStore.visitedEvents[0].url).toBe('https://example.com');
expect(sessionStore.host).toBe('');
expect(sessionStore.prefetched).toBe(false);
});
it('should handle event filtering based on search filters', async () => {
const mockSessionId = 'test-session-id';
const mockSessionInfo = { sessionId: mockSessionId, userId: 'user1' };
const mockEventsData = {
events: [
{ type: 'LOCATION', url: 'https://example.com', time: 100 },
{ type: 'CLICK', value: 'button', time: 200 },
],
};
// Setup search filters
(searchStore.instance.events as any) = [
{ key: 'LOCATION', operator: 'is', value: 'https://example.com' },
];
(sessionService.getSessionInfo as jest.Mock).mockResolvedValue(
mockSessionInfo,
);
(sessionService.getSessionEvents as jest.Mock).mockResolvedValue(
mockEventsData,
);
(checkEventWithFilters as jest.Mock).mockReturnValue(true);
await sessionStore.fetchSessionData(mockSessionId);
expect(sessionStore.eventsIndex).toEqual([0]);
});
it('should handle different filter operators', async () => {
const mockSessionId = 'test-session-id';
const mockSessionInfo = { sessionId: mockSessionId, userId: 'user1' };
const mockEventsData = {
events: [
{ type: 'LOCATION', url: 'https://example.com', time: 100 },
{ type: 'CLICK', value: 'test-button', time: 200 },
],
};
(searchStore.instance.events as any) = [
{ key: 'CLICK', operator: 'contains', value: 'test' },
];
(sessionService.getSessionInfo as jest.Mock).mockResolvedValue(
mockSessionInfo,
);
(sessionService.getSessionEvents as jest.Mock).mockResolvedValue(
mockEventsData,
);
(checkEventWithFilters as jest.Mock).mockReturnValue(true);
await sessionStore.fetchSessionData(mockSessionId);
expect(sessionStore.eventsIndex).toEqual([1]);
});
it('should handle errors when fetching events', async () => {
const mockSessionId = 'test-session-id';
const mockSessionInfo = { sessionId: mockSessionId, userId: 'user1' };
const mockError = new Error('API error');
console.error = jest.fn();
(sessionService.getSessionInfo as jest.Mock).mockResolvedValue(
mockSessionInfo,
);
(sessionService.getSessionEvents as jest.Mock).mockRejectedValue(
mockError,
);
await sessionStore.fetchSessionData(mockSessionId);
expect(console.error).toHaveBeenCalledWith(
'Failed to fetch events',
mockError,
);
expect(sessionStore.current.sessionId).toBe(mockSessionId);
expect(sessionStore.current.events).toEqual([]);
});
it('should handle errors when fetching session info', async () => {
const mockSessionId = 'test-session-id';
const mockError = new Error('API error');
console.error = jest.fn();
(sessionService.getSessionInfo as jest.Mock).mockRejectedValue(mockError);
await sessionStore.fetchSessionData(mockSessionId);
expect(console.error).toHaveBeenCalledWith(mockError);
expect(sessionStore.fetchFailed).toBe(true);
});
});
describe('sortSessions', () => {
it('should sort sessions by the specified key in ascending order', () => {
sessionStore.list = [
new Session(mockSession({ duration: 3000, sessionId: '1' })),
new Session(mockSession({ duration: 1000, sessionId: '2' })),
new Session(mockSession({ duration: 2000, sessionId: '3' })),
];
sessionStore.favoriteList = [
new Session(mockSession({ duration: 3000, sessionId: '1' })),
new Session(mockSession({ duration: 2000, sessionId: '3' })),
];
sessionStore.sortSessions('duration', 1);
expect(sessionStore.list.map((s) => s.sessionId)).toEqual([
'2',
'3',
'1',
]);
expect(sessionStore.favoriteList.map((s) => s.sessionId)).toEqual([
'3',
'1',
]);
});
it('should sort sessions by the specified key in descending order', () => {
sessionStore.list = [
new Session(mockSession({ duration: 3000, sessionId: '1' })),
new Session(mockSession({ duration: 1000, sessionId: '2' })),
new Session(mockSession({ duration: 2000, sessionId: '3' })),
];
sessionStore.sortSessions('duration', -1);
expect(sessionStore.list.map((s) => s.sessionId)).toEqual([
'1',
'3',
'2',
]);
});
});
});