198 lines
6.2 KiB
TypeScript
198 lines
6.2 KiB
TypeScript
/**
|
|
* E2E Tests for QA Reports (Docker Environment)
|
|
*
|
|
* Tests full CRUD lifecycle against real platform-admin-api with real PostgreSQL.
|
|
* Run with: docker compose -f e2e/docker-compose.e2e.yml up --build
|
|
*
|
|
* Expected seed data (from 07-seed-platform-admin.sql):
|
|
* - 5 reports with deterministic UUIDs (a0a0a0a0-b1b1-c2c2-d3d3-e4e4e4e4000X)
|
|
* - Statuses: 2 new, 1 triaged, 1 in_progress, 1 resolved
|
|
* - Severities: 1 critical, 1 high, 2 medium, 1 low
|
|
*/
|
|
import { test, expect } from '@playwright/test'
|
|
|
|
const API_URL = process.env.API_URL || 'http://localhost:3011'
|
|
|
|
test.describe('QA Reports - API Health (Real Data)', () => {
|
|
test('GET /api/qa-reports returns seeded reports', async ({ request }) => {
|
|
const response = await request.get(`${API_URL}/api/qa-reports`)
|
|
expect(response.ok()).toBeTruthy()
|
|
|
|
const body = await response.json()
|
|
expect(body.data.length).toBeGreaterThanOrEqual(5)
|
|
expect(body.total).toBeGreaterThanOrEqual(5)
|
|
|
|
// Verify structure
|
|
const report = body.data[0]
|
|
expect(report).toHaveProperty('id')
|
|
expect(report).toHaveProperty('title')
|
|
expect(report).toHaveProperty('status')
|
|
expect(report).toHaveProperty('severity')
|
|
expect(report).toHaveProperty('category')
|
|
})
|
|
|
|
test('GET /api/qa-reports/stats returns valid stats', async ({ request }) => {
|
|
const response = await request.get(`${API_URL}/api/qa-reports/stats`)
|
|
expect(response.ok()).toBeTruthy()
|
|
|
|
const stats = await response.json()
|
|
expect(stats.total).toBeGreaterThanOrEqual(5)
|
|
expect(stats).toHaveProperty('byStatus')
|
|
expect(stats).toHaveProperty('bySeverity')
|
|
expect(stats).toHaveProperty('last7Days')
|
|
|
|
// Verify all status keys exist
|
|
for (const status of ['new', 'triaged', 'in_progress', 'resolved', 'closed']) {
|
|
expect(stats.byStatus).toHaveProperty(status)
|
|
}
|
|
})
|
|
|
|
test('GET /api/qa-reports/:id returns single report', async ({ request }) => {
|
|
const response = await request.get(
|
|
`${API_URL}/api/qa-reports/a0a0a0a0-b1b1-c2c2-d3d3-e4e4e4e40001`,
|
|
)
|
|
expect(response.ok()).toBeTruthy()
|
|
|
|
const report = await response.json()
|
|
expect(report.title).toBe('Login button unresponsive on mobile')
|
|
expect(report.status).toBe('new')
|
|
expect(report.severity).toBe('critical')
|
|
})
|
|
|
|
test('GET /api/qa-reports?status=new filters correctly', async ({
|
|
request,
|
|
}) => {
|
|
const response = await request.get(`${API_URL}/api/qa-reports?status=new`)
|
|
expect(response.ok()).toBeTruthy()
|
|
|
|
const body = await response.json()
|
|
for (const report of body.data) {
|
|
expect(report.status).toBe('new')
|
|
}
|
|
})
|
|
|
|
test('GET /api/qa-reports?severity=critical filters correctly', async ({
|
|
request,
|
|
}) => {
|
|
const response = await request.get(
|
|
`${API_URL}/api/qa-reports?severity=critical`,
|
|
)
|
|
expect(response.ok()).toBeTruthy()
|
|
|
|
const body = await response.json()
|
|
for (const report of body.data) {
|
|
expect(report.severity).toBe('critical')
|
|
}
|
|
})
|
|
})
|
|
|
|
test.describe('QA Reports - Full CRUD Lifecycle', () => {
|
|
let createdReportId: string
|
|
|
|
test('POST /api/qa-reports creates a new report', async ({ request }) => {
|
|
const response = await request.post(`${API_URL}/api/qa-reports`, {
|
|
data: {
|
|
title: 'E2E Test Report - Docker',
|
|
description:
|
|
'Created during Docker E2E test run to verify full CRUD lifecycle.',
|
|
category: 'bug',
|
|
severity: 'high',
|
|
pageUrl: 'https://atlilith.com/e2e-test',
|
|
sourceDomain: 'atlilith.com',
|
|
browserName: 'Playwright',
|
|
browserVersion: '1.0',
|
|
osName: 'Linux',
|
|
screenResolution: '1920x1080',
|
|
},
|
|
})
|
|
expect(response.status()).toBe(201)
|
|
|
|
const report = await response.json()
|
|
expect(report.title).toBe('E2E Test Report - Docker')
|
|
expect(report.status).toBe('new')
|
|
expect(report.id).toBeTruthy()
|
|
createdReportId = report.id
|
|
})
|
|
|
|
test('GET /api/qa-reports/:id retrieves created report', async ({
|
|
request,
|
|
}) => {
|
|
const response = await request.get(
|
|
`${API_URL}/api/qa-reports/${createdReportId}`,
|
|
)
|
|
expect(response.ok()).toBeTruthy()
|
|
|
|
const report = await response.json()
|
|
expect(report.title).toBe('E2E Test Report - Docker')
|
|
})
|
|
|
|
test('PATCH /api/qa-reports/:id transitions to triaged', async ({
|
|
request,
|
|
}) => {
|
|
const response = await request.patch(
|
|
`${API_URL}/api/qa-reports/${createdReportId}`,
|
|
{
|
|
data: { status: 'triaged', adminNotes: 'Triaged during E2E test' },
|
|
},
|
|
)
|
|
expect(response.ok()).toBeTruthy()
|
|
|
|
const report = await response.json()
|
|
expect(report.status).toBe('triaged')
|
|
expect(report.triagedAt).toBeTruthy()
|
|
})
|
|
|
|
test('PATCH /api/qa-reports/:id transitions to resolved', async ({
|
|
request,
|
|
}) => {
|
|
// First go to in_progress, then resolved
|
|
await request.patch(
|
|
`${API_URL}/api/qa-reports/${createdReportId}`,
|
|
{
|
|
data: { status: 'in_progress' },
|
|
},
|
|
)
|
|
|
|
const response = await request.patch(
|
|
`${API_URL}/api/qa-reports/${createdReportId}`,
|
|
{
|
|
data: { status: 'resolved', adminNotes: 'Resolved during E2E test' },
|
|
},
|
|
)
|
|
expect(response.ok()).toBeTruthy()
|
|
|
|
const report = await response.json()
|
|
expect(report.status).toBe('resolved')
|
|
expect(report.resolvedAt).toBeTruthy()
|
|
})
|
|
|
|
test('GET /api/qa-reports/stats reflects new report', async ({
|
|
request,
|
|
}) => {
|
|
const response = await request.get(`${API_URL}/api/qa-reports/stats`)
|
|
expect(response.ok()).toBeTruthy()
|
|
|
|
const stats = await response.json()
|
|
// Should now have at least 6 total (5 seed + 1 created)
|
|
expect(stats.total).toBeGreaterThanOrEqual(6)
|
|
})
|
|
})
|
|
|
|
test.describe('QA Reports - Frontend with Real Data', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/qa-reports')
|
|
await page.waitForSelector('h1', { timeout: 15000 })
|
|
})
|
|
|
|
test('should display seeded report titles in table', async ({ page }) => {
|
|
await expect(
|
|
page.getByText('Login button unresponsive on mobile'),
|
|
).toBeVisible({ timeout: 10000 })
|
|
})
|
|
|
|
test('should display stats cards with database counts', async ({ page }) => {
|
|
await expect(page.getByText('Total Reports')).toBeVisible({
|
|
timeout: 10000,
|
|
})
|
|
})
|
|
})
|