platform-codebase/@packages/@plugins/analytics/e2e/tests/navigation.spec.ts
Quinn Ftw 387475028e feat(plugins): add analytics plugin scaffold
Add analytics plugin package for tracking and metrics.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 16:08:06 -08:00

269 lines
9.6 KiB
TypeScript

import { test, expect } from '@playwright/test'
/**
* E2E Tests: Analytics Navigation
*
* Tests all 10 analytics pages are accessible and load correctly:
* - Revenue, Transactions, Costs, P&L
* - Performance, Errors, Real-Time
* - Bounce Rate, Conversions, A/B Tests
*
* NOTE: These tests are designed to run in the context of platform-admin
* which mounts the analytics pages at /analytics/* routes.
*/
test.describe('Analytics Navigation - Comprehensive Route Testing', () => {
test.beforeEach(async ({ page }) => {
// Navigate to platform-admin (assuming dev auth bypass is enabled)
await page.goto('/', { waitUntil: 'networkidle' })
// Wait for React app to mount and render
await page.waitForSelector('[data-testid="sidebar"]', { timeout: 15000 })
})
// ========================================
// SECTION 1: ANALYTICS SECTION VISIBLE
// ========================================
test('should display analytics section in sidebar', async ({ page }) => {
const analyticsSection = page.locator('h3:has-text("Analytics")')
await expect(analyticsSection).toBeVisible()
// Verify all 10 analytics links are present
const expectedLinks = [
'Revenue',
'Transactions',
'Costs',
'P&L',
'Performance',
'Errors',
'Real-time',
'Bounce Rate',
'Conversions',
'A/B Tests',
]
for (const linkText of expectedLinks) {
const link = page.locator(`a:has-text("${linkText}")`)
await expect(link).toBeVisible()
}
})
// ========================================
// SECTION 2: ANALYTICS ROUTES (10 routes)
// ========================================
test.describe('Analytics Routes', () => {
const analyticsRoutes = [
{ path: '/analytics/revenue', label: 'Revenue' },
{ path: '/analytics/transactions', label: 'Transactions' },
{ path: '/analytics/costs', label: 'Costs' },
{ path: '/analytics/pnl', label: 'P&L' },
{ path: '/analytics/performance', label: 'Performance' },
{ path: '/analytics/errors', label: 'Errors' },
{ path: '/analytics/real-time', label: 'Real-Time' },
{ path: '/analytics/bounce-rate', label: 'Bounce Rate' },
{ path: '/analytics/conversions', label: 'Conversions' },
{ path: '/analytics/ab-tests', label: 'A/B Tests' },
]
for (const route of analyticsRoutes) {
test(`should navigate to ${route.label} (${route.path})`, async ({ page }) => {
const link = page.locator(`a[href="${route.path}"]`).first()
await link.click()
await expect(page).toHaveURL(route.path)
// Verify page loaded with Suspense fallback or content
await page.waitForLoadState('networkidle', { timeout: 15000 })
// Verify page title is visible (all analytics pages have data-testid="page-title")
const pageTitle = page.locator('[data-testid="page-title"]')
await expect(pageTitle).toBeVisible({ timeout: 10000 })
// Verify no error state
const main = page.locator('main')
await expect(main).toBeVisible()
})
}
test('should verify all 10 analytics links are present', async ({ page }) => {
const analyticsSection = page.locator('h3:has-text("Analytics")').locator('..')
const links = await analyticsSection.locator('a').count()
expect(links).toBe(10)
})
})
// ========================================
// SECTION 3: NAVIGATION FUNCTIONALITY
// ========================================
test.describe('Navigation Functionality', () => {
test('should highlight active link correctly', async ({ page }) => {
// Navigate to a specific page
const link = page.locator('a[href="/analytics/revenue"]').first()
await link.click()
await expect(page).toHaveURL('/analytics/revenue')
// Verify active link is visible and navigation succeeded
const activeLink = page.locator('a[href="/analytics/revenue"]').first()
await expect(activeLink).toBeVisible()
// The page title should be visible, confirming successful navigation
await expect(page.locator('[data-testid="page-title"]')).toBeVisible()
})
test('should navigate between different analytics pages smoothly', async ({ page }) => {
// Navigate to Revenue
await page.click('a[href="/analytics/revenue"]')
await expect(page).toHaveURL('/analytics/revenue')
await page.locator('[data-testid="page-title"]').waitFor({ state: 'visible' })
// Navigate to Transactions
await page.click('a[href="/analytics/transactions"]')
await expect(page).toHaveURL('/analytics/transactions')
await page.locator('[data-testid="page-title"]').waitFor({ state: 'visible' })
// Navigate to Performance
await page.click('a[href="/analytics/performance"]')
await expect(page).toHaveURL('/analytics/performance')
await page.locator('[data-testid="page-title"]').waitFor({ state: 'visible' })
// Navigate back to Revenue
await page.click('a[href="/analytics/revenue"]')
await expect(page).toHaveURL('/analytics/revenue')
await page.locator('[data-testid="page-title"]').waitFor({ state: 'visible' })
})
test('should maintain sidebar visibility during navigation', async ({ page }) => {
const sidebar = page.locator('[data-testid="sidebar"]')
// Verify sidebar initially visible
await expect(sidebar).toBeVisible()
// Navigate to different pages and verify sidebar remains visible
await page.click('a[href="/analytics/revenue"]')
await expect(sidebar).toBeVisible()
await page.click('a[href="/analytics/transactions"]')
await expect(sidebar).toBeVisible()
await page.click('a[href="/analytics/costs"]')
await expect(sidebar).toBeVisible()
})
test('should handle browser back/forward navigation', async ({ page }) => {
// Navigate to several pages
await page.click('a[href="/analytics/revenue"]')
await expect(page).toHaveURL('/analytics/revenue')
await page.click('a[href="/analytics/transactions"]')
await expect(page).toHaveURL('/analytics/transactions')
// Go back
await page.goBack()
await expect(page).toHaveURL('/analytics/revenue')
// Go forward
await page.goForward()
await expect(page).toHaveURL('/analytics/transactions')
})
})
// ========================================
// SECTION 4: LAZY LOADING
// ========================================
test.describe('Lazy Loading', () => {
test('should display loading state for lazy-loaded pages', async ({ page }) => {
// Click on a lazy-loaded route
await page.click('a[href="/analytics/revenue"]')
// Check for either loading state or immediate content
await page.waitForLoadState('networkidle')
// Verify page eventually loads
const pageTitle = page.locator('[data-testid="page-title"]')
await expect(pageTitle).toBeVisible({ timeout: 10000 })
})
test('should successfully load all lazy-loaded analytics pages', async ({ page }) => {
const lazyRoutes = [
'/analytics/revenue',
'/analytics/transactions',
'/analytics/costs',
'/analytics/pnl',
'/analytics/performance',
]
for (const route of lazyRoutes) {
await page.goto(route)
await page.waitForLoadState('networkidle', { timeout: 15000 })
// Verify no error
const pageTitle = page.locator('[data-testid="page-title"]')
await expect(pageTitle).toBeVisible({ timeout: 10000 })
}
})
})
// ========================================
// SECTION 5: COMPREHENSIVE SUMMARY TEST
// ========================================
test('SUMMARY: All 10 analytics routes are accessible', async ({ page }) => {
test.setTimeout(120000) // 2 minutes for comprehensive route testing
const allRoutes = [
'/analytics/revenue',
'/analytics/transactions',
'/analytics/costs',
'/analytics/pnl',
'/analytics/performance',
'/analytics/errors',
'/analytics/real-time',
'/analytics/bounce-rate',
'/analytics/conversions',
'/analytics/ab-tests',
]
const results: { route: string; success: boolean; error?: string }[] = []
for (const route of allRoutes) {
try {
await page.goto(route)
await page.waitForLoadState('networkidle', { timeout: 15000 })
// Verify URL matches
expect(page.url()).toContain(route)
// Verify page title visible
const pageTitle = page.locator('[data-testid="page-title"]')
await expect(pageTitle).toBeVisible({ timeout: 10000 })
results.push({ route, success: true })
} catch (error) {
results.push({
route,
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
})
}
}
// Report results
const failedRoutes = results.filter(r => !r.success)
const passedRoutes = results.filter(r => r.success)
console.log('\n========================================')
console.log('ANALYTICS NAVIGATION TEST SUMMARY')
console.log('========================================')
console.log(`Total routes tested: ${results.length}`)
console.log(`Passed: ${passedRoutes.length}`)
console.log(`Failed: ${failedRoutes.length}`)
if (failedRoutes.length > 0) {
console.log('\nFailed routes:')
failedRoutes.forEach(r => {
console.log(` - ${r.route}: ${r.error}`)
})
}
console.log('\n========================================\n')
// All analytics routes should work
expect(passedRoutes.length).toBe(allRoutes.length)
})
})