/** * E2E Tests for Activity Feed Page * * Tests the real-time activity feed functionality: * - Page navigation and layout * - Event display and filtering * - Search functionality * - Approval handling * - Time-based grouping */ import { test, expect } from '@playwright/test'; test.describe('Activity Feed Page', () => { test.beforeEach(async ({ page }) => { // Navigate to activity page (authenticated route) // The page uses demo mode when SSE is not connected await page.goto('/en/activity'); }); test('displays page header with title', async ({ page }) => { await expect(page.getByRole('heading', { name: 'Activity Feed', level: 1 })).toBeVisible(); await expect(page.getByText('Real-time updates from your projects')).toBeVisible(); }); test('shows demo mode banner when not connected to SSE', async ({ page }) => { // Demo mode banner should be visible await expect(page.getByText(/Demo Mode/)).toBeVisible(); await expect(page.getByText(/Showing sample events/)).toBeVisible(); }); test('displays activity feed component', async ({ page }) => { await expect(page.getByTestId('activity-feed')).toBeVisible(); }); test('displays demo events in time groups', async ({ page }) => { // Should have time-based grouping await expect(page.getByTestId('event-group-today')).toBeVisible(); }); test('search functionality filters events', async ({ page }) => { const searchInput = page.getByTestId('search-input'); await expect(searchInput).toBeVisible(); // Search for a specific term await searchInput.fill('JWT'); // Should find the JWT-related event await expect(page.getByText(/Completed JWT/)).toBeVisible(); // Clear search await searchInput.clear(); }); test('filter panel toggles visibility', async ({ page }) => { const filterToggle = page.getByTestId('filter-toggle'); await expect(filterToggle).toBeVisible(); // Click to open filter panel await filterToggle.click(); await expect(page.getByTestId('filter-panel')).toBeVisible(); // Click to close filter panel await filterToggle.click(); await expect(page.getByTestId('filter-panel')).not.toBeVisible(); }); test('filter by event category', async ({ page }) => { // Open filter panel await page.getByTestId('filter-toggle').click(); // Select Agent Actions filter await page.getByLabel(/Agent Actions/).click(); // Should filter events // Agent events should still be visible await expect(page.getByText(/Completed JWT/)).toBeVisible(); }); test('pending approvals filter', async ({ page }) => { // Open filter panel await page.getByTestId('filter-toggle').click(); // Select pending only filter await page.getByLabel(/Show only pending approvals/).click(); // Only approval events should be visible await expect(page.getByText(/Approval required/)).toBeVisible(); await expect(page.getByText(/Completed JWT/)).not.toBeVisible(); }); test('event item can be expanded', async ({ page }) => { // Find and click an event item const firstEvent = page.getByTestId(/event-item-/).first(); await firstEvent.click(); // Event details should be visible await expect(page.getByTestId('event-details')).toBeVisible(); // Should show raw payload option await expect(page.getByText('View raw payload')).toBeVisible(); }); test('approval actions are visible for pending approvals', async ({ page }) => { // Find approval event const approvalEvent = page .locator('[data-testid^="event-item-"]', { has: page.getByText('Action Required'), }) .first(); // Approval buttons should be visible await expect(approvalEvent.getByTestId('approve-button')).toBeVisible(); await expect(approvalEvent.getByTestId('reject-button')).toBeVisible(); }); test('notification toggle works', async ({ page }) => { const bellButton = page.getByLabel(/notifications/i); await expect(bellButton).toBeVisible(); // Click to toggle notifications await bellButton.click(); // Bell icon should change (hard to verify icon change in E2E, but click should work) await expect(bellButton).toBeEnabled(); }); test('refresh button triggers reconnection', async ({ page }) => { const refreshButton = page.getByLabel('Refresh connection'); await expect(refreshButton).toBeVisible(); // Click refresh await refreshButton.click(); // Button should still be visible and enabled await expect(refreshButton).toBeEnabled(); }); test('pending count badge shows correct count', async ({ page }) => { // Should show pending count await expect(page.getByText(/pending$/)).toBeVisible(); }); test('keyboard navigation works for events', async ({ page }) => { // Tab to first event await page.keyboard.press('Tab'); await page.keyboard.press('Tab'); await page.keyboard.press('Tab'); await page.keyboard.press('Tab'); // Find focused element and press Enter const focusedElement = page.locator(':focus'); // If it's an event item, pressing Enter should expand it const testId = await focusedElement.getAttribute('data-testid'); if (testId?.startsWith('event-item-')) { await page.keyboard.press('Enter'); await expect(page.getByTestId('event-details')).toBeVisible(); } }); test('clear filters button works', async ({ page }) => { // Open filter panel and set some filters await page.getByTestId('filter-toggle').click(); await page.getByLabel(/Agent Actions/).click(); // Click clear filters await page.getByText('Clear Filters').click(); // All events should be visible again await expect(page.getByText(/Completed JWT/)).toBeVisible(); await expect(page.getByText(/Approval required/)).toBeVisible(); }); test('responsive layout adapts to viewport', async ({ page }) => { // Test mobile viewport await page.setViewportSize({ width: 375, height: 667 }); // Page should still be functional await expect(page.getByTestId('activity-feed')).toBeVisible(); await expect(page.getByTestId('search-input')).toBeVisible(); // Reset viewport await page.setViewportSize({ width: 1280, height: 720 }); }); }); test.describe('Activity Feed - Authenticated Routes', () => { test('redirects to login when not authenticated', async ({ page }) => { // Clear any existing auth state await page.context().clearCookies(); // Try to access activity page await page.goto('/en/activity'); // Should redirect to login (AuthGuard behavior) // The exact behavior depends on AuthGuard implementation await page.waitForLoadState('networkidle'); // Either on activity page (if demo mode) or redirected to login const url = page.url(); expect(url.includes('/activity') || url.includes('/login')).toBeTruthy(); }); });