201 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			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);
 | 
						|
  });
 | 
						|
});
 |