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>
269 lines
9.6 KiB
TypeScript
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)
|
|
})
|
|
})
|