ObsiViewer/e2e/logging.spec.ts

201 lines
6.0 KiB
TypeScript

import { test, expect } from '@playwright/test';
test.describe('Frontend Logging System', () => {
let logRequests: any[] = [];
test.beforeEach(async ({ page }) => {
logRequests = [];
// Intercept log requests
await page.route('**/api/log', async (route) => {
const request = route.request();
const postData = request.postDataJSON();
// Store the log data
if (Array.isArray(postData)) {
logRequests.push(...postData);
} else {
logRequests.push(postData);
}
// Respond with success
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ ok: true }),
});
});
});
test('should log APP_START on page load', async ({ page }) => {
await page.goto('/');
// Wait for logs to be sent
await page.waitForTimeout(3000);
const appStartLogs = logRequests.filter(log => log.event === 'APP_START');
expect(appStartLogs.length).toBeGreaterThan(0);
const log = appStartLogs[0];
expect(log.app).toBe('ObsiViewer');
expect(log.sessionId).toBeTruthy();
expect(log.context).toBeDefined();
});
test('should log SEARCH_EXECUTED on search', async ({ page }) => {
await page.goto('/');
// Find search input and perform search
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i]').first();
await searchInput.fill('test query');
await searchInput.press('Enter');
// Wait for logs
await page.waitForTimeout(3000);
const searchLogs = logRequests.filter(log => log.event === 'SEARCH_EXECUTED');
expect(searchLogs.length).toBeGreaterThan(0);
const log = searchLogs[0];
expect(log.data.query).toBe('test query');
});
test('should log BOOKMARKS_OPEN when opening bookmarks', async ({ page }) => {
await page.goto('/');
// Click bookmarks button/tab
const bookmarksButton = page.locator('button:has-text("Bookmarks"), [data-testid="bookmarks-tab"]').first();
if (await bookmarksButton.isVisible()) {
await bookmarksButton.click();
// Wait for logs
await page.waitForTimeout(3000);
const bookmarksLogs = logRequests.filter(log => log.event === 'BOOKMARKS_OPEN');
expect(bookmarksLogs.length).toBeGreaterThan(0);
}
});
test('should log GRAPH_VIEW_OPEN when opening graph view', async ({ page }) => {
await page.goto('/');
// Click graph view button/tab
const graphButton = page.locator('button:has-text("Graph"), [data-testid="graph-tab"]').first();
if (await graphButton.isVisible()) {
await graphButton.click();
// Wait for logs
await page.waitForTimeout(3000);
const graphLogs = logRequests.filter(log => log.event === 'GRAPH_VIEW_OPEN');
expect(graphLogs.length).toBeGreaterThan(0);
}
});
test('should log THEME_CHANGE when toggling theme', async ({ page }) => {
await page.goto('/');
// Find and click theme toggle button
const themeButton = page.locator('button[aria-label*="theme" i], button:has-text("Theme")').first();
if (await themeButton.isVisible()) {
await themeButton.click();
// Wait for logs
await page.waitForTimeout(3000);
const themeLogs = logRequests.filter(log => log.event === 'THEME_CHANGE');
expect(themeLogs.length).toBeGreaterThan(0);
const log = themeLogs[0];
expect(log.data.from).toBeDefined();
expect(log.data.to).toBeDefined();
}
});
test('should include session ID in all logs', async ({ page }) => {
await page.goto('/');
// Perform multiple actions
const searchInput = page.locator('input[type="search"]').first();
if (await searchInput.isVisible()) {
await searchInput.fill('test');
await searchInput.press('Enter');
}
// Wait for logs
await page.waitForTimeout(3000);
expect(logRequests.length).toBeGreaterThan(0);
const sessionIds = new Set(logRequests.map(log => log.sessionId));
expect(sessionIds.size).toBe(1); // All logs should have same session ID
});
test('should include context in all logs', async ({ page }) => {
await page.goto('/');
// Wait for logs
await page.waitForTimeout(3000);
expect(logRequests.length).toBeGreaterThan(0);
logRequests.forEach(log => {
expect(log.context).toBeDefined();
expect(log.context.version).toBeDefined();
expect(log.context.route).toBeDefined();
});
});
test('should batch logs when multiple events occur', async ({ page }) => {
await page.goto('/');
// Perform multiple quick actions
const searchInput = page.locator('input[type="search"]').first();
if (await searchInput.isVisible()) {
await searchInput.fill('test1');
await searchInput.press('Enter');
await page.waitForTimeout(100);
await searchInput.fill('test2');
await searchInput.press('Enter');
await page.waitForTimeout(100);
await searchInput.fill('test3');
await searchInput.press('Enter');
}
// Wait for batched logs
await page.waitForTimeout(3000);
// Should have received logs (possibly batched)
expect(logRequests.length).toBeGreaterThan(0);
});
test('should handle offline scenario', async ({ page, context }) => {
await page.goto('/');
// Go offline
await context.setOffline(true);
// Perform actions while offline
const searchInput = page.locator('input[type="search"]').first();
if (await searchInput.isVisible()) {
await searchInput.fill('offline test');
await searchInput.press('Enter');
}
await page.waitForTimeout(1000);
const offlineLogCount = logRequests.length;
// Go back online
await context.setOffline(false);
// Wait for queued logs to be sent
await page.waitForTimeout(5000);
// Should have received more logs after going online
expect(logRequests.length).toBeGreaterThanOrEqual(offlineLogCount);
});
});