platform-codebase/features/platform-admin/frontend-admin/e2e/analytics.docker.e2e.ts

387 lines
15 KiB
TypeScript
Executable file

/**
* E2E Tests for All Analytics Pages (Docker Environment)
*
* Tests all 10 analytics routes with REAL database data.
* Run with: docker compose -f e2e/docker-compose.e2e.yml up --build
*
* Routes tested:
* 1. /analytics/revenue - Revenue metrics and trends
* 2. /analytics/transactions - Transaction list and filtering
* 3. /analytics/pnl - Profit and loss statement
* 4. /analytics/costs - Platform costs breakdown
* 5. /analytics/real-time - Real-time activity
* 6. /analytics/performance - System performance
* 7. /analytics/errors - Error tracking
* 8. /analytics/funnels - Conversion funnels (covered in separate file)
* 9. /analytics/bounce - Bounce rate analysis
* 10. /analytics/ab-testing - A/B test results
*/
import { test, expect } from '@playwright/test'
// =============================================================================
// Revenue Page Tests
// =============================================================================
test.describe('Revenue Page (Real Data)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/analytics/revenue')
// Wait for data to load
await page.waitForSelector('h1, h2', { timeout: 10000 })
})
test('should display revenue page title and metrics', async ({ page }) => {
// Check page title (use first() to avoid strict mode violation with multiple matching headings)
await expect(
page.getByRole('heading', { name: /revenue/i }).first(),
).toBeVisible()
// Revenue metrics should show real data
const content = await page.textContent('body')
// Should have currency values from seed data
expect(content).toMatch(/\$[\d,]+/)
})
test('should show revenue breakdown by type', async ({ page }) => {
// Check for transaction type breakdown (from seed data)
const transactionTypes = ['SUBSCRIPTION', 'PRODUCTSALE', 'TIP', 'SERVICEBOOKING']
for (const type of transactionTypes) {
// At least one type should be visible or in a chart
const typeVisible = await page.getByText(type, { exact: true }).isVisible().catch(() => false)
if (typeVisible) {break}
}
})
})
// =============================================================================
// Transactions Page Tests
// =============================================================================
test.describe('Transactions Page (Real Data)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/analytics/transactions')
await page.waitForSelector('table, [data-testid="transaction-list"]', { timeout: 10000 })
})
test('should display transactions table with data', async ({ page }) => {
await expect(
page.getByRole('heading', { name: /transaction/i }).first(),
).toBeVisible()
// Table should have transaction data
const tableRows = page.locator('table tbody tr')
const rowCount = await tableRows.count()
expect(rowCount).toBeGreaterThan(0)
})
test('should have filter controls', async ({ page }) => {
// Check for filter/search controls
const hasSearch = await page.getByPlaceholder(/search/i).isVisible().catch(() => false)
const hasFilter = await page.getByRole('combobox').isVisible().catch(() => false)
expect(hasSearch || hasFilter).toBeTruthy()
})
})
// =============================================================================
// P&L Page Tests
// =============================================================================
test.describe('P&L Page (Real Data)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/analytics/pnl')
await page.waitForSelector('h1, h2, .card', { timeout: 10000 })
})
test('should display P&L statement with revenue and costs', async ({ page }) => {
await expect(
page.getByRole('heading', { name: /p.?&.?l|profit|loss/i }).first(),
).toBeVisible()
// Should show financial data
const content = await page.textContent('body')
// Look for currency values
expect(content).toMatch(/\$[\d,]+/)
})
test('should show revenue vs costs comparison', async ({ page }) => {
// P&L should show both revenue and cost sections
const hasRevenue = await page.getByText(/revenue|income/i).isVisible()
const hasCosts = await page.getByText(/cost|expense/i).isVisible()
expect(hasRevenue || hasCosts).toBeTruthy()
})
})
// =============================================================================
// Costs Page Tests
// =============================================================================
test.describe('Costs Page (Real Data)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/analytics/costs')
await page.waitForSelector('h1, h2, .card', { timeout: 10000 })
})
test('should display cost metrics with seeded data', async ({ page }) => {
await expect(
page.getByRole('heading', { name: /cost/i }).first(),
).toBeVisible()
// Should show cost categories from seed data
const categories = ['INFRASTRUCTURE', 'PAYMENT_PROCESSING', 'MODERATION', 'MARKETING']
let foundCategory = false
for (const category of categories) {
const visible = await page.getByText(category).isVisible().catch(() => false)
if (visible) {
foundCategory = true
break
}
}
expect(foundCategory).toBeTruthy()
})
test('should show cost breakdown chart or table', async ({ page }) => {
// Should have either a chart or table showing cost breakdown
const hasChart = await page.locator('canvas, svg').first().isVisible().catch(() => false)
const hasTable = await page.locator('table').first().isVisible().catch(() => false)
expect(hasChart || hasTable).toBeTruthy()
})
})
// =============================================================================
// Real-Time Page Tests
// =============================================================================
test.describe('Real-Time Page (Real Data)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/analytics/real-time')
await page.waitForSelector('h1, h2, .card', { timeout: 10000 })
})
test('should display real-time metrics', async ({ page }) => {
await expect(
page.getByRole('heading', { name: /real.?time/i }).first(),
).toBeVisible()
// Should show activity metrics (even if zero for test data)
const content = await page.textContent('body')
expect(content).toBeTruthy()
})
test('should show activity feed or active users', async ({ page }) => {
// Real-time page should show activity or user counts
const hasActivity = await page.getByText(/active|activity|user|session/i).isVisible().catch(() => false)
expect(hasActivity).toBeTruthy()
})
})
// =============================================================================
// Performance Page Tests
// =============================================================================
test.describe('Performance Page (Real Data)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/analytics/performance')
await page.waitForSelector('h1, h2, .card', { timeout: 10000 })
})
test('should display performance metrics', async ({ page }) => {
await expect(
page.getByRole('heading', { name: /performance/i }).first(),
).toBeVisible()
// Should show performance-related metrics
const content = await page.textContent('body')
// Look for metrics like response time, latency, or requests
const hasPerformanceData = /ms|latency|response|request|throughput|uptime/i.test(content || '')
expect(hasPerformanceData || content!.length > 100).toBeTruthy()
})
test('should show endpoint performance table', async ({ page }) => {
// Should have endpoint metrics table or similar
const hasTable = await page.locator('table').first().isVisible().catch(() => false)
const hasList = await page.locator('ul, ol, [role="list"]').first().isVisible().catch(() => false)
expect(hasTable || hasList).toBeTruthy()
})
})
// =============================================================================
// Error Tracking Page Tests
// =============================================================================
test.describe('Error Tracking Page (Real Data)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/analytics/errors')
await page.waitForSelector('h1, h2, .card', { timeout: 10000 })
})
test('should display error tracking dashboard', async ({ page }) => {
await expect(
page.getByRole('heading', { name: /error/i }).first(),
).toBeVisible()
// Should show error data from seed
const content = await page.textContent('body')
expect(content!.length).toBeGreaterThan(100)
})
test('should show error types from seeded data', async ({ page }) => {
// Check for error types/severities from seed data
const errorTypes = ['API', 'DATABASE', 'PAYMENT', 'AUTHENTICATION']
const severities = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']
let foundType = false
for (const type of [...errorTypes, ...severities]) {
const visible = await page.getByText(type, { exact: true }).isVisible().catch(() => false)
if (visible) {
foundType = true
break
}
}
expect(foundType).toBeTruthy()
})
test('should display recent errors list', async ({ page }) => {
// Should have a list or table of recent errors
const hasTable = await page.locator('table').first().isVisible().catch(() => false)
const hasList = await page.locator('[class*="error"], [class*="list"]').first().isVisible().catch(() => false)
expect(hasTable || hasList).toBeTruthy()
})
})
// =============================================================================
// Bounce Rate Page Tests
// =============================================================================
test.describe('Bounce Rate Page (Real Data)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/analytics/bounce')
await page.waitForSelector('h1, h2, .card', { timeout: 10000 })
})
test('should display bounce rate metrics', async ({ page }) => {
await expect(
page.getByRole('heading', { name: /bounce/i }).first(),
).toBeVisible()
// Should show percentage values for bounce rate
const content = await page.textContent('body')
expect(content).toMatch(/%/)
})
test('should show bounce rate by page', async ({ page }) => {
// Should have page-level breakdown
const hasPageBreakdown = await page.getByText(/page|url|path/i).isVisible().catch(() => false)
const hasTable = await page.locator('table').first().isVisible().catch(() => false)
expect(hasPageBreakdown || hasTable).toBeTruthy()
})
})
// =============================================================================
// A/B Testing Page Tests
// =============================================================================
test.describe('A/B Testing Page (Real Data)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/analytics/ab-testing')
await page.waitForSelector('h1, h2, .card', { timeout: 10000 })
})
test('should display A/B testing dashboard', async ({ page }) => {
await expect(
page.getByRole('heading', { name: /a.?b|testing|experiment/i }).first(),
).toBeVisible()
})
test('should show active tests from seeded data', async ({ page }) => {
// Check for test names from seed data
const testNames = [
'Pricing Page Redesign',
'CTA Button Color Test',
'Subscription Copy Test',
]
let foundTest = false
for (const name of testNames) {
const visible = await page.getByText(name).isVisible().catch(() => false)
if (visible) {
foundTest = true
break
}
}
// At least the page should render with some content
const content = await page.textContent('body')
expect(foundTest || content!.includes('test') || content!.includes('Test')).toBeTruthy()
})
test('should display test status indicators', async ({ page }) => {
// Check for status badges (RUNNING, COMPLETED, DRAFT from seed data)
const statuses = ['RUNNING', 'COMPLETED', 'DRAFT']
let foundStatus = false
for (const status of statuses) {
const visible = await page.getByText(status, { exact: true }).isVisible().catch(() => false)
if (visible) {
foundStatus = true
break
}
}
expect(foundStatus).toBeTruthy()
})
test('should show test results with confidence levels', async ({ page }) => {
// Completed tests should show confidence percentage
const content = await page.textContent('body')
// Look for percentage or confidence indicators
const hasConfidence = content!.match(/%/) || content!.includes('confidence')
expect(hasConfidence).toBeTruthy()
})
})
// =============================================================================
// API Health Checks for All Analytics Endpoints
// =============================================================================
test.describe('Analytics API Health', () => {
test('should have healthy revenue endpoint', async ({ request }) => {
const apiUrl = process.env.API_URL || 'http://localhost:3012'
const response = await request.get(`${apiUrl}/api/analytics/admin/revenue/metrics`)
expect(response.ok()).toBeTruthy()
})
test('should have healthy transactions endpoint', async ({ request }) => {
const apiUrl = process.env.API_URL || 'http://localhost:3012'
const response = await request.get(`${apiUrl}/api/analytics/admin/transactions`)
expect(response.ok()).toBeTruthy()
})
test('should have healthy costs endpoint', async ({ request }) => {
const apiUrl = process.env.API_URL || 'http://localhost:3012'
const response = await request.get(`${apiUrl}/api/analytics/admin/costs/metrics`)
expect(response.ok()).toBeTruthy()
})
test('should have healthy errors endpoint', async ({ request }) => {
const apiUrl = process.env.API_URL || 'http://localhost:3012'
const response = await request.get(`${apiUrl}/api/analytics/admin/errors/metrics`)
expect(response.ok()).toBeTruthy()
})
test('should have healthy ab-tests endpoint', async ({ request }) => {
const apiUrl = process.env.API_URL || 'http://localhost:3012'
const response = await request.get(`${apiUrl}/api/analytics/admin/ab-tests/active`)
expect(response.ok()).toBeTruthy()
})
test('should have healthy performance endpoint', async ({ request }) => {
const apiUrl = process.env.API_URL || 'http://localhost:3012'
const response = await request.get(`${apiUrl}/api/analytics/admin/performance/metrics`)
expect(response.ok()).toBeTruthy()
})
test('should have healthy bounce-rate endpoint', async ({ request }) => {
const apiUrl = process.env.API_URL || 'http://localhost:3012'
const response = await request.get(`${apiUrl}/api/analytics/admin/bounce-rate/metrics`)
expect(response.ok()).toBeTruthy()
})
test('should have healthy realtime endpoint', async ({ request }) => {
const apiUrl = process.env.API_URL || 'http://localhost:3012'
const response = await request.get(`${apiUrl}/api/analytics/admin/realtime/metrics`)
expect(response.ok()).toBeTruthy()
})
test('should have healthy pnl endpoint', async ({ request }) => {
const apiUrl = process.env.API_URL || 'http://localhost:3012'
const response = await request.get(`${apiUrl}/api/analytics/admin/pnl/statement`)
expect(response.ok()).toBeTruthy()
})
})