E2E Testing Tools
| Tool | Strength |
|---|---|
| Selenium | Multi-language, mature |
| Cypress | Great DX, in-browser |
| Playwright ⭐ | Multi-browser, fast, Microsoft |
| Puppeteer | Chromium only |
| TestCafe | No WebDriver |
Playwright Example
import { test, expect } from '@playwright/test';
test('login flow', async ({ page }) => {
await page.goto('https://app.com/login');
await page.fill('#email', 'rahim@x.com');
await page.fill('#password', 'secret');
await page.click('button[type=submit]');
await expect(page).toHaveURL(/dashboard/);
await expect(page.locator('h1')).toHaveText('Welcome');
});
Cypress Example
describe('Login', () => {
it('should login', () => {
cy.visit('/login');
cy.get('#email').type('rahim@x.com');
cy.get('#password').type('secret');
cy.get('button').click();
cy.url().should('include', '/dashboard');
});
});
Page Object Pattern ⭐
// LoginPage.ts
class LoginPage {
constructor(page) { this.page = page; }
async goto() { await this.page.goto('/login'); }
async login(email, pass) {
await this.page.fill('#email', email);
await this.page.fill('#password', pass);
await this.page.click('button[type=submit]');
}
}
// Usage: tests become readable, selectors centralized
API Testing
// Postman Collection + Newman CLI
newman run api-tests.json
// REST Assured (Java)
given().contentType("application/json").body(user)
.when().post("/api/users")
.then().statusCode(201).body("id", notNullValue());
// Supertest (Node)
const res = await request(app).post('/api/users').send({email});
expect(res.status).toBe(201);
Contract Testing ⭐
Consumer-provider API contract validate — breaking change early detect।
// Pact — Consumer writes expectation
await provider.addInteraction({
state: 'user exists',
uponReceiving: 'GET /users/1',
willRespondWith: { status: 200, body: { id: 1, name: "Rahim" } }
});
// Provider verifies
pact-provider-verifier --provider-base-url=http://localhost:3000
Visual Regression
Screenshot compare — unintended UI change catch।
Tools: Percy, Chromatic, Playwright screenshots, BackstopJS।
Mobile Testing
Appium (native), Detox (React Native), Espresso (Android), XCUITest (iOS)।
Accessibility Testing
// Playwright + axe-core
import AxeBuilder from '@axe-core/playwright';
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
Test Data Management
- Factories (faker, bogus)
- Fixtures (JSON seed)
- Database reset per test
- Docker compose for DB
- Test containers (disposable)
Flaky Tests ⭐
Sometimes pass, sometimes fail। Common causes:
- Timing (hardcoded sleep)
- Shared state
- External dependency
- Async race condition
- Test order dependency
Fixes
- Explicit waits (not sleep)
- Isolation per test
- Retry mechanism (last resort)
- Quarantine flaky → fix first
CI Integration
# GitHub Actions
- run: npm test
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: test-results/