Test Automation Frameworks: Selenium vs Cypress vs Playwright Compared
Test automation frameworks provide the structure, libraries, and tools needed to write, organize, and run automated tests — from browser-based UI tests to API tests — in a consistent, maintainable way across environments.
What You’ll Learn
- How Selenium, Cypress, and Playwright compare (architecture, speed, reliability)
- When to choose each framework for your project
- How to integrate automated tests into CI/CD pipelines
- Best practices for writing maintainable test automation
- Common test automation pitfalls and solutions
Why Test Automation Matters
Manual testing doesn’t scale. As your application grows, the number of regression tests grows exponentially. Automated tests run in minutes what would take days of manual testing, and they run consistently — no fatigue, no skipped steps, no “it worked on my machine.” Companies with strong test automation deploy 200x more frequently than those without (DORA State of DevOps).
Doda Browser uses automated visual regression testing across all platforms — a UI change that shifts a button by 2 pixels on one OS shouldn’t go unnoticed.
Learning Path
flowchart LR
A[Unit Testing] --> B[Integration Testing]
B --> C[Test Automation<br/>You are here]
C --> D[CI/CD Pipeline]
D --> E[Production Monitoring]
style C fill:#f90,color:#fff
Framework Comparison
| Feature | Selenium WebDriver | Cypress | Playwright |
|---|---|---|---|
| Architecture | Browser drivers via WebDriver protocol | In-process, runs in browser | Browser-specific protocols (CDP) |
| Language | Java, Python, JS, C#, Ruby | JavaScript/TypeScript | JavaScript/TypeScript, Python, Java, .NET |
| Browser support | Chrome, Firefox, Safari, Edge | Chrome-family only | Chrome, Firefox, Safari, Edge |
| Speed | Moderate | Fast | Fastest |
| Network control | Limited | Stub/Spy | Route interception, mock APIs |
| Auto-waiting | Manual waits required | Automatic | Automatic |
| IFrame support | Yes | Limited | Yes |
| Mobile testing | Appium integration | Limited | Mobile Safari/Chrome |
| Debugging | Screenshots, logs | Time-travel, video | Traces, video, screenshots |
| Community | Largest | Large, growing | Large, very active |
Selenium WebDriver
The veteran framework, supporting multiple browsers and languages.
Setup
npm install selenium-webdriver
# Download ChromeDriver matching your Chrome versionExample
const { Builder, By, until } = require('selenium-webdriver');
async function example() {
const driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get('https://example.com/login');
// Find and interact with elements
await driver.findElement(By.id('email')).sendKeys('user@example.com');
await driver.findElement(By.id('password')).sendKeys('secret123');
// Wait for element and click
await driver.wait(
until.elementIsVisible(driver.findElement(By.css('button[type="submit"]'))),
5000
);
await driver.findElement(By.css('button[type="submit"]')).click();
// Wait for navigation
await driver.wait(until.urlContains('/dashboard'), 5000);
console.log('Login successful!');
} finally {
await driver.quit();
}
}
example();When to Use Selenium
- Need to test across multiple browsers (including Safari, legacy IE)
- Team uses Java, C#, or Python for tests
- Need mobile testing via Appium
- Existing investment in Selenium infrastructure
Cypress
Modern, developer-friendly framework with real-time reloading and time-travel debugging.
Setup
npm install cypress --save-dev
npx cypress openExample
// cypress/e2e/login.cy.js
describe('Login', () => {
beforeEach(() => {
cy.visit('https://example.com/login');
});
it('logs in successfully', () => {
cy.get('#email').type('user@example.com');
cy.get('#password').type('secret123');
cy.get('button[type="submit"]').click();
cy.url().should('include', '/dashboard');
cy.get('.welcome').should('contain', 'Welcome back');
});
it('shows error for invalid credentials', () => {
cy.get('#email').type('wrong@example.com');
cy.get('#password').type('wrongpass');
cy.get('button[type="submit"]').click();
cy.get('.error-message').should('be.visible');
});
it('validates empty fields', () => {
cy.get('button[type="submit"]').click();
cy.get('#email:invalid').should('exist');
});
});When to Use Cypress
- Frontend-focused team already using JavaScript
- Need fast, reliable tests for Chrome-based browsers
- Want time-travel debugging and automatic waiting
- Testing modern SPAs (React, Vue, Angular)
Playwright
The newest framework, built by Microsoft, offering the fastest execution and broadest features.
Setup
npm install @playwright/test
npx playwright installExample
// tests/login.spec.js
const { test, expect } = require('@playwright/test');
test.describe('Login', () => {
test('logs in successfully', async ({ page }) => {
await page.goto('https://example.com/login');
await page.fill('#email', 'user@example.com');
await page.fill('#password', 'secret123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/dashboard/);
await expect(page.locator('.welcome')).toHaveText('Welcome back');
});
test('handles network failure gracefully', async ({ page }) => {
// Intercept and block login API
await page.route('**/api/login', route => route.abort());
await page.goto('/login');
await page.fill('#email', 'user@example.com');
await page.fill('#password', 'secret123');
await page.click('button[type="submit"]');
await expect(page.locator('.error')).toContainText('Network error');
});
test('mobile responsive layout', async ({ page }) => {
// Test on mobile viewport
await page.setViewportSize({ width: 375, height: 812 });
await page.goto('/login');
await expect(page.locator('.form-container')).toBeVisible();
// Verify mobile layout
const box = await page.locator('.form-container').boundingBox();
expect(box.width).toBeLessThan(400);
});
});When to Use Playwright
- Need the fastest test execution
- Testing across Chromium, Firefox, and WebKit
- Need network interception and API mocking
- Want built-in mobile viewport testing
- Building new test infrastructure from scratch
CI/CD Integration
# .github/workflows/test.yml — Playwright example
name: E2E Tests
on:
push:
branches: [main]
pull_request:
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
services:
app:
image: myapp:latest
ports:
- 3000:3000
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Install Playwright
run: npx playwright install --with-deps
- name: Run tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: playwright-report/
retention-days: 7Parallel Execution
# Playwright — run across 4 workers
npx playwright test --workers=4
# Cypress — run in parallel (paid plan)
npx cypress run --parallel
# Selenium — Grid mode
java -jar selenium-server.jar hub
java -jar selenium-server.jar node --hub http://localhost:4444Choosing the Right Framework
Decision Matrix
| If you need… | Choose… |
|---|---|
| Cross-browser testing (all major browsers) | Playwright or Selenium |
| Fast feedback in development | Cypress or Playwright |
| Mobile web testing | Playwright (mobile viewports) or Appium |
| Multiple programming languages | Selenium (Java, Python, C#, Ruby, JS) |
| API + UI testing in one framework | Playwright (built-in API testing) |
| Enterprise with existing Java/Selenium | Keep Selenium, consider adding Playwright |
Migration Path
Moving from Selenium to Playwright:
// Selenium style
driver.findElement(By.id("email")).sendKeys("user@example.com");
// Playwright equivalent
page.fill("#email", "user@example.com");
// or
page.locator("#email").fill("user@example.com");Common Test Automation Mistakes
1. Flaky Tests
Tests that pass sometimes and fail sometimes destroy trust in the suite.
Fix: Use automatic waiting (Playwright, Cypress auto-wait). Remove time.sleep() and fixed waits. Fix race conditions.
2. Testing Through the UI When Not Needed
Every UI test is slower and more brittle than an API or unit test.
Fix: Follow the test pyramid. Test business logic at the unit level, interactions at the integration level, and only critical journeys at the UI level.
3. No Page Object Model
Tests with duplicated selectors and navigation logic are hard to maintain.
// BAD: selectors duplicated across tests
test('login', async ({ page }) => {
await page.fill('#email', 'user@example.com');
await page.fill('#password', 'secret123');
await page.click('button[type="submit"]');
});
// GOOD: Page Object Model
class LoginPage {
constructor(page) {
this.page = page;
this.emailInput = page.locator('#email');
this.passwordInput = page.locator('#password');
this.submitButton = page.locator('button[type="submit"]');
}
async login(email, password) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
}
test('login', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.login('user@example.com', 'secret123');
});4. Over-reliance on End-to-End Tests
Hundreds of E2E tests are slow and flaky. The test pyramid applies to automation too.
Fix: 10 well-chosen E2E tests are worth more than 100 fragile ones.
5. Not Running Tests in CI
Tests that only run on a developer’s machine don’t protect the codebase.
Fix: Every PR must run the test suite. Block merging on test failures.
6. Testing in Production
Automated tests that run against production risk corrupting data and alerting users.
Fix: Use staging or dedicated test environments. If you must test in production, use read-only operations and isolated test accounts.
7. No Reporting or Debugging
Tests that fail without screenshots, logs, or traces are hard to diagnose.
Fix: Enable video recording, screenshot on failure, and detailed logging in all test frameworks.
Practice Questions
1. What are the three main browser automation frameworks compared in this tutorial?
Selenium WebDriver, Cypress, and Playwright.
2. What is the architectural difference between Selenium and Playwright?
Selenium uses the WebDriver protocol through browser-specific drivers. Playwright uses browser-native protocols (Chrome DevTools Protocol for Chromium) directly, making it faster and more reliable.
3. When would you choose Cypress over Playwright?
When you need time-travel debugging, automatic waiting, and are testing Chrome-based browsers only. Cypress is great for frontend-focused JavaScript teams.
4. What is the Page Object Model and why is it important?
A design pattern where each page or component has a class encapsulating its selectors and interaction methods. It reduces duplication and makes tests more maintainable.
5. How do you handle flaky tests in CI?
Use automatic waiting instead of fixed delays, isolate tests (no shared state), retry flaky tests with a limit, and investigate root causes immediately.
Challenge: Take an existing Selenium test suite and migrate one critical test to Playwright. Compare execution time, reliability, and code readability. Document the differences.
FAQ
What’s Next
| Tutorial | What You’ll Learn |
|---|---|
| Continuous Testing in CI/CD | Integrating tests into the delivery pipeline |
| Playwright Testing Guide | Deep dive into Playwright features |
| Cypress Testing Guide | Deep dive into Cypress features |
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-20.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro