Backend (@backend-dev): - Add ReportService with PDF/CSV generation (reportlab, pandas) - Implement Report API endpoints (POST, GET, DELETE, download) - Add ReportRepository and schemas - Configure storage with auto-cleanup (30 days) - Rate limiting: 10 downloads/minute - Professional PDF templates with charts support Frontend (@frontend-dev): - Integrate Recharts for data visualization - Add CostBreakdown, TimeSeries, ComparisonBar charts - Implement scenario comparison page with multi-select - Add dark/light mode toggle with ThemeProvider - Create Reports page with generation form and list - Add new UI components: checkbox, dialog, tabs, label, skeleton - Implement useComparison and useReports hooks QA (@qa-engineer): - Setup Playwright E2E testing framework - Create 7 test spec files with 94 test cases - Add visual regression testing with baselines - Configure multi-browser testing (Chrome, Firefox, WebKit) - Add mobile responsive tests - Create test fixtures and helpers - Setup GitHub Actions CI workflow Documentation (@spec-architect): - Create detailed kanban-v0.4.0.md with 27 tasks - Update progress.md with v0.4.0 tracking - Create v0.4.0 planning prompt Features: ✅ PDF/CSV Report Generation ✅ Interactive Charts (Pie, Area, Bar) ✅ Scenario Comparison (2-4 scenarios) ✅ Dark/Light Mode Toggle ✅ E2E Test Suite (94 tests) Dependencies added: - Backend: reportlab, pandas, slowapi - Frontend: recharts, date-fns, @radix-ui/react-checkbox/dialog/tabs - Testing: @playwright/test 27 tasks completed, 100% v0.4.0 implementation
130 lines
3.8 KiB
TypeScript
130 lines
3.8 KiB
TypeScript
/**
|
|
* E2E Test: Setup Verification
|
|
*
|
|
* This test file verifies that the E2E test environment is properly configured.
|
|
* Run this first to ensure everything is working correctly.
|
|
*/
|
|
|
|
import { test, expect } from '@playwright/test';
|
|
import { navigateTo, waitForLoading } from './utils/test-helpers';
|
|
|
|
test.describe('E2E Setup Verification', () => {
|
|
test('frontend dev server is running', async ({ page }) => {
|
|
await navigateTo(page, '/');
|
|
|
|
// Verify the page loads
|
|
await expect(page.locator('body')).toBeVisible();
|
|
|
|
// Check for either dashboard or loading state
|
|
const bodyText = await page.locator('body').textContent();
|
|
expect(bodyText).toBeTruthy();
|
|
expect(bodyText!.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
test('backend API is accessible', async ({ request }) => {
|
|
// Try to access the API health endpoint or scenarios endpoint
|
|
const response = await request.get('http://localhost:8000/api/v1/scenarios', {
|
|
timeout: 10000,
|
|
});
|
|
|
|
// Should get 200 OK
|
|
expect(response.status()).toBe(200);
|
|
|
|
// Response should be JSON
|
|
const contentType = response.headers()['content-type'];
|
|
expect(contentType).toContain('application/json');
|
|
|
|
// Should have expected structure
|
|
const data = await response.json();
|
|
expect(data).toHaveProperty('items');
|
|
expect(data).toHaveProperty('total');
|
|
expect(Array.isArray(data.items)).toBe(true);
|
|
});
|
|
|
|
test('CORS is configured correctly', async ({ request }) => {
|
|
const response = await request.get('http://localhost:8000/api/v1/scenarios', {
|
|
headers: {
|
|
'Origin': 'http://localhost:5173',
|
|
},
|
|
});
|
|
|
|
// Check CORS headers
|
|
const corsHeader = response.headers()['access-control-allow-origin'];
|
|
expect(corsHeader).toBeTruthy();
|
|
});
|
|
|
|
test('all required browsers are available', async ({ browserName }) => {
|
|
// This test will run on all configured browsers
|
|
// If it passes, the browser is properly installed
|
|
expect(['chromium', 'firefox', 'webkit']).toContain(browserName);
|
|
});
|
|
|
|
test('screenshots can be captured', async ({ page }) => {
|
|
await navigateTo(page, '/');
|
|
await waitForLoading(page);
|
|
|
|
// Take a screenshot
|
|
const screenshot = await page.screenshot();
|
|
|
|
// Verify screenshot is not empty
|
|
expect(screenshot).toBeTruthy();
|
|
expect(screenshot.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
test('localStorage and sessionStorage work', async ({ page }) => {
|
|
await navigateTo(page, '/');
|
|
|
|
// Test localStorage
|
|
await page.evaluate(() => {
|
|
localStorage.setItem('e2e-test', 'test-value');
|
|
});
|
|
|
|
const localValue = await page.evaluate(() => {
|
|
return localStorage.getItem('e2e-test');
|
|
});
|
|
|
|
expect(localValue).toBe('test-value');
|
|
|
|
// Clean up
|
|
await page.evaluate(() => {
|
|
localStorage.removeItem('e2e-test');
|
|
});
|
|
});
|
|
|
|
test('network interception works', async ({ page }) => {
|
|
// Intercept API calls
|
|
const apiCalls: string[] = [];
|
|
|
|
await page.route('**/api/**', async (route) => {
|
|
apiCalls.push(route.request().url());
|
|
await route.continue();
|
|
});
|
|
|
|
await navigateTo(page, '/');
|
|
await waitForLoading(page);
|
|
|
|
// Verify we intercepted API calls
|
|
expect(apiCalls.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
test.describe('Environment Variables', () => {
|
|
test('required environment variables are set', () => {
|
|
// Verify CI environment if applicable
|
|
if (process.env.CI) {
|
|
expect(process.env.CI).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('test data directories exist', async () => {
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const fixturesDir = path.join(__dirname, 'fixtures');
|
|
const screenshotsDir = path.join(__dirname, 'screenshots');
|
|
|
|
expect(fs.existsSync(fixturesDir)).toBe(true);
|
|
expect(fs.existsSync(screenshotsDir)).toBe(true);
|
|
});
|
|
});
|