Answer
Data-Driven Testing in Playwright
Method 1 — test.each() (Parameterized Tests)
TypeScript
import { test, expect } from '@playwright/test';
// Array of test cases
const loginCases = [
{ email: 'user@test.com', password: 'pass123', expected: '/dashboard', desc: 'valid user' },
{ email: 'admin@test.com', password: 'admin123', expected: '/admin', desc: 'admin user' },
{ email: 'wrong@test.com', password: 'wrongpass', expected: '/login', desc: 'invalid user' },
];
for (const { email, password, expected, desc } of loginCases) {
test(`login: ${desc}`, async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill(email);
await page.getByLabel('Password').fill(password);
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL(expected);
});
}
Method 2 — Dynamic Test from JSON File
TypeScript
// test-data/users.json
// [{"role":"admin","email":"admin@t.com","password":"admin123"},...]
import userData from '../test-data/users.json';
for (const user of userData) {
test(`login as ${user.role}`, async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill(user.email);
await page.getByLabel('Password').fill(user.password);
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL(`/${user.role}`);
});
}
Method 3 — CSV Data
TypeScript
import * as fs from 'fs';
import * as path from 'path';
function readCSV(filePath: string): Record<string, string>[] {
const content = fs.readFileSync(filePath, 'utf-8');
const lines = content.trim().split('\n');
const headers = lines[0].split(',');
return lines.slice(1).map(line => {
const values = line.split(',');
return Object.fromEntries(headers.map((h, i) => [h.trim(), values[i]?.trim()]));
});
}
const testData = readCSV(path.join(__dirname, '../test-data/products.csv'));
for (const row of testData) {
test(`search for ${row.productName}`, async ({ page }) => {
await page.goto('/');
await page.getByRole('searchbox').fill(row.productName);
await page.getByRole('button', { name: 'Search' }).click();
await expect(page.locator('.result-count')).toContainText(`${row.expectedCount} results`);
});
}
Method 4 — Form Validation Data-Driven
TypeScript
const formErrors = [
{ field: 'email', value: '', error: 'Email is required' },
{ field: 'email', value: 'not-an-email', error: 'Invalid email format' },
{ field: 'password', value: '123', error: 'Password too short' },
{ field: 'phone', value: 'abc', error: 'Invalid phone number' },
];
for (const { field, value, error } of formErrors) {
test(`form validation: ${field} - ${error}`, async ({ page }) => {
await page.goto('/register');
await page.getByLabel(field).fill(value);
await page.getByRole('button', { name: 'Submit' }).click();
await expect(page.getByText(error)).toBeVisible();
});
}
Using Environment-Specific Data
TypeScript
// test-data/credentials.ts
export const credentials = {
staging: { email: 'test@staging.com', password: 'staging123' },
prod: { email: 'test@prod.com', password: 'prod456' },
};
// In test
const env = process.env.TEST_ENV || 'staging';
const creds = credentials[env as 'staging' | 'prod'];
