Files
Profa 494cb11c1f feat: Add comprehensive E2E test suite for agentics.org
Added complete Playwright-based E2E testing infrastructure with 36 tests
covering functional, responsive, accessibility, and performance testing.

**Test Infrastructure:**
- Playwright config with 7 browser/device configurations
- Page Object Model for maintainable test code
- npm scripts for various test execution modes

**Test Suites (36 tests total):**
- homepage.spec.ts: 14 functional tests (navigation, hero, stats, CTAs)
- responsive.spec.ts: 5 responsive design tests (mobile, tablet, desktop)
- accessibility.spec.ts: 10 WCAG 2.1 AA compliance tests
- performance.spec.ts: 7 performance and Web Vitals tests

**Documentation:**
- E2E-TEST-PLAN.md: Comprehensive 15-section test strategy (700+ lines)
- README.md: Complete usage guide (300+ lines)
- QUICKSTART.md: 5-minute setup guide
- DELIVERABLES.md: Detailed deliverables summary

**Key Features:**
- Based on real content crawled from live site
- TypeScript for type safety
- axe-core integration for accessibility testing
- Screenshot and video capture on failure
- CI/CD ready with GitHub Actions example
- Cross-browser: Chrome, Firefox, Safari, Edge, Mobile
- Responsive: Mobile (iPhone 12), Tablet (iPad), Desktop

**Test Coverage:**
✅ All 7 navigation items
✅ Hero section with community stats (100K+ members)
✅ 4 explore cards (About, Impact, Community, Projects)
✅ 7 Paths of Impact
✅ "What is Agentic AI" section
✅ Community stats (130K+ Reddit, 52K+ LinkedIn, 3K+ Discord)
✅ SEO metadata and Open Graph tags
✅ HTTPS enforcement
✅ Footer and copyright

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 18:18:45 +00:00

215 lines
6.4 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { HomePage } from '../pages/HomePage';
/**
* Test Suite: Performance Tests
*
* Coverage:
* - TC-009: Page Load Performance
* - TC-010: Resource Optimization
* - Core Web Vitals (LCP, FID, CLS)
*/
test.describe('Performance Tests', () => {
test('TC-009: Page should load within acceptable time limits', async ({ page }) => {
const homePage = new HomePage(page);
// Measure page load time
const startTime = Date.now();
await homePage.goto();
const loadTime = Date.now() - startTime;
// Verify page loads within 5 seconds
expect(loadTime).toBeLessThan(5000);
// Get detailed performance metrics
const metrics = await homePage.getPerformanceMetrics();
// Verify Time to First Byte (should be fast)
expect(metrics.connectTime).toBeLessThan(2000);
// Verify render time is acceptable
expect(metrics.renderTime).toBeLessThan(3000);
});
test('TC-010: Resources should be optimized', async ({ page }) => {
const homePage = new HomePage(page);
// Track network requests
const requests: any[] = [];
page.on('request', (request) => {
requests.push({
url: request.url(),
resourceType: request.resourceType(),
});
});
await homePage.goto();
// Verify JavaScript files are loaded
const jsFiles = requests.filter(r => r.resourceType === 'script');
expect(jsFiles.length).toBeGreaterThan(0);
// Verify CSS files are loaded
const cssFiles = requests.filter(r => r.resourceType === 'stylesheet');
expect(cssFiles.length).toBeGreaterThan(0);
// Verify images are loaded
const imageFiles = requests.filter(r => r.resourceType === 'image');
expect(imageFiles.length).toBeGreaterThan(0);
// Check for caching headers
const response = await page.goto('/');
const headers = response ? await response.allHeaders() : {};
// Verify cache headers exist (cache-control or etag)
const hasCaching = headers['cache-control'] || headers['etag'];
expect(hasCaching).toBeTruthy();
});
test('TC-P03: Core Web Vitals should meet "Good" thresholds', async ({ page }) => {
const homePage = new HomePage(page);
await homePage.goto();
// Get Web Vitals
const webVitals = await page.evaluate(() => {
return new Promise((resolve) => {
// Largest Contentful Paint (LCP)
let lcp = 0;
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1] as any;
lcp = lastEntry.renderTime || lastEntry.loadTime;
}).observe({ entryTypes: ['largest-contentful-paint'] });
// Cumulative Layout Shift (CLS)
let cls = 0;
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (!(entry as any).hadRecentInput) {
cls += (entry as any).value;
}
}
}).observe({ entryTypes: ['layout-shift'] });
// Wait a bit to collect metrics
setTimeout(() => {
resolve({ lcp, cls });
}, 3000);
});
});
const vitals = webVitals as { lcp: number; cls: number };
// LCP should be < 2.5s (2500ms) for "Good"
if (vitals.lcp > 0) {
expect(vitals.lcp).toBeLessThan(2500);
}
// CLS should be < 0.1 for "Good"
expect(vitals.cls).toBeLessThan(0.1);
});
test('TC-P04: Images should be optimized', async ({ page }) => {
const homePage = new HomePage(page);
// Track image requests
const images: any[] = [];
page.on('response', async (response) => {
if (response.request().resourceType() === 'image') {
const headers = await response.allHeaders();
images.push({
url: response.url(),
status: response.status(),
contentType: headers['content-type'],
size: parseInt(headers['content-length'] || '0'),
});
}
});
await homePage.goto();
await page.waitForLoadState('networkidle');
// Verify images are successfully loaded
images.forEach((img) => {
expect(img.status).toBe(200);
});
// Verify modern image formats are used (webp, svg, etc.)
const modernFormats = images.filter((img) =>
img.contentType?.includes('webp') ||
img.contentType?.includes('svg') ||
img.contentType?.includes('avif')
);
// At least some images should use modern formats
expect(modernFormats.length).toBeGreaterThan(0);
});
test('TC-P05: Page should not have render-blocking resources', async ({ page }) => {
const homePage = new HomePage(page);
// Measure time to first paint
await homePage.goto();
const paintMetrics = await page.evaluate(() => {
const paint = performance.getEntriesByType('paint');
return {
firstPaint: paint.find((p) => p.name === 'first-paint')?.startTime,
firstContentfulPaint: paint.find((p) => p.name === 'first-contentful-paint')?.startTime,
};
});
// FCP should be < 1.8s for "Good"
if (paintMetrics.firstContentfulPaint) {
expect(paintMetrics.firstContentfulPaint).toBeLessThan(1800);
}
});
test('TC-P06: Page should handle slow 3G connection', async ({ page, context }) => {
// Simulate slow 3G connection
await context.route('**/*', async (route) => {
// Add delay to simulate slow connection
await new Promise((resolve) => setTimeout(resolve, 100));
await route.continue();
});
const homePage = new HomePage(page);
const startTime = Date.now();
await homePage.goto();
const loadTime = Date.now() - startTime;
// Should still load within reasonable time on slow connection
expect(loadTime).toBeLessThan(10000); // 10 seconds on slow 3G
// Verify main content is visible
await expect(homePage.heroHeading).toBeVisible();
});
test('TC-P07: No JavaScript errors in console', async ({ page }) => {
const errors: string[] = [];
// Listen for console errors
page.on('console', (msg) => {
if (msg.type() === 'error') {
errors.push(msg.text());
}
});
// Listen for page errors
page.on('pageerror', (error) => {
errors.push(error.message);
});
const homePage = new HomePage(page);
await homePage.goto();
// Wait for page to fully load
await page.waitForLoadState('networkidle');
// Should have no JavaScript errors
expect(errors).toEqual([]);
});
});