Mengintegrasikan performance checks dalam automated tests: load time assertions, API response time, dan performance monitoring di CI/CD

Setelah di episode 13 kita mempelajari visual testing, pada episode ini kita menambahkan dimensi lain: performance. Functional test bisa pass tetapi aplikasi tetap lambat — performance testing mendeteksi ini.
test('homepage loads within 3 seconds', async ({ page }) => {
const startTime = Date.now();
await page.goto('/');
const loadTime = Date.now() - startTime;
expect(loadTime).toBeLessThan(3000);
console.log(`Homepage loaded in ${loadTime}ms`);
});test('no resource takes more than 1 second', async ({ page }) => {
const resources: number[] = [];
page.on('response', async (response) => {
const timing = response.request().timing();
resources.push(timing.responseEnd - timing.requestStart);
});
await page.goto('/');
await page.waitForLoadState('networkidle');
const slowResources = resources.filter(t => t > 1000);
expect(slowResources).toHaveLength(0);
});test('API responds within 500ms', async ({ request }) => {
const startTime = Date.now();
const response = await request.get('/api/users');
const responseTime = Date.now() - startTime;
expect(response.ok()).toBeTruthy();
expect(responseTime).toBeLessThan(500);
});// playwright.config.ts
export default defineConfig({
use: {
launchOptions: {
args: ['--enable-precise-memory-info'],
},
},
});test('Core Web Vitals', async ({ page }) => {
await page.goto('/');
// Measure LCP
const lcp = await page.evaluate(() => {
return new Promise<number>(resolve => {
new PerformanceObserver(list => {
const entries = list.getEntries();
resolve(entries[entries.length - 1].startTime);
}).observe({ type: 'largest-contentful-paint', buffered: true });
});
});
expect(lcp).toBeLessThan(2500); // Good LCP
});Performance Budget:
├── Page load: < 3 seconds
├── First Contentful Paint: < 1.5 seconds
├── Largest Contentful Paint: < 2.5 seconds
├── Time to Interactive: < 3.5 seconds
├── Total bundle size: < 500KB
└── API response: < 500msTip
Performance assertions harus realistis. Jangan set budget terlalu ketat yang menyebabkan false positives, atau terlalu longgar yang tidak berguna.
test('performance budget', async ({ page }) => {
const startTime = Date.now();
// Measure page load
await page.goto('/');
await page.waitForLoadState('networkidle');
const loadTime = Date.now() - startTime;
// Assert performance budget
expect(loadTime).toBeLessThan(3000);
// Check no console errors
const errors: string[] = [];
page.on('console', msg => {
if (msg.type() === 'error') errors.push(msg.text());
});
expect(errors).toHaveLength(0);
});Di episode 15 selanjutnya kita akan membahas cross-browser & device automation — browser matrix, mobile viewport, dan emulation. Sampai jumpa di episode 15!