Data-Driven Testing with Playwright & TypeScript: A Practical Guide

Search for a command to run...

No comments yet. Be the first to comment.
This blog series lets you learn about best practices and new tools, get tips from experts and get the latest news from the TypeScript community. Follow us and stay up-to-date with typescript.
Type-driven development is a transformative approach that prioritizes type design before implementation, fundamentally changing how developers build robust and maintainable applications. This comprehensive guide explores the principles, techniques, a...
Quick Summary / Key Takeaways IoT software development is the process of building software that connects devices, sensors, cloud systems, mobile apps, dashboards, and data platforms. A good IoT prod

Quick Summary / Key Takeaways Fintech in UAE is moving beyond digital wallets and mobile banking. The next wave is being shaped by instant payments, open finance, AI agents, unified digital identity,

Quick Summary / Key Takeaways ux design benefits show up directly in conversion rates because better user experience removes doubt, friction, and confusion. UX design helps users move from interest

Quick Summary / Key Takeaways Digital transformation Dubai projects work best when they begin with a business bottleneck, not a shopping list of software. Mid-size companies have a useful advantage.

Quick Summary Enterprise web application development is the work of turning complex business processes into secure, usable browser-based software. These applications are usually built for teams that h

In today’s fast-paced development cycles, automated testing isn’t just helpful—it’s essential. But as your app scales, so does your test suite. That’s where Data-Driven Testing (DDT) comes in. It’s a technique that makes your tests more flexible, reusable, and easier to maintain—especially when you’re working with tools like Playwright and TypeScript.
In this guide, we’ll break down what data-driven testing is, why it’s useful, and how to implement it in a Playwright project with real-world examples using arrays, JSON, and CSV files.
At its core, data-driven testing is about separating your test logic from your test data. Instead of hardcoding input values in your tests, you feed them data from external sources—allowing you to run the same test multiple times with different inputs.
This approach keeps your tests clean, your data manageable, and your testing process scalable.
Here’s why developers and QA teams love DDT:
✅ Write your test logic once, reuse it across different scenarios
✅ Keep test data organised in separate files
✅ Cover more test cases with less code
✅ Make your tests easier to update when data changes
Playwright makes it easy to pull in data from various sources like:
Inline arrays (great for small datasets)
JSON files (structured and readable)
CSV files (great for large sets of tabular data)
Databases (for real-world or dynamic data sets)
Let’s walk through a few examples.
The simplest way to get started is by defining your test data directly in your test file.
// tests/login-data-driven.spec.ts
import { test, expect } from '@playwright/test';
const loginData = [
{ username: 'admin', password: 'admin123' },
{ username: 'user', password: 'user123' },
{ username: 'test', password: 'wrongPass' },
];
loginData.forEach(({ username, password }) => {
test(`Login test - ${username}`, async ({ page }) =>
{
await page.goto('https://example.com/login');
await page.fill('#username', username);
await page.fill('#password', password);
await page.click('#login');
// Replace with actual validation logic
const currentUrl = page.url();
expect(currentUrl).toContain('/dashboard'); // adjust this based on expected behavior
});
});
This approach is quick and great for small, fixed datasets.
As your data grows or changes frequently, moving it to a .json file keeps things cleaner.
// data/loginData.json
[
{ "username": "admin", "password": "admin123" },
{ "username": "user", "password": "user123" },
{ "username": "test", "password": "wrongPass" }
]
// tests/login-json.spec.ts
import { test, expect } from '@playwright/test';
import * as loginData from '../data/loginData.json';
(loginData as Array<{ username: string; password: string }>).forEach(({ username, password }) =>
{
test(`Login test (JSON) - ${username}`, async ({ page }) => {
await page.goto('https://example.com/login');
await page.fill('#username', username);
await page.fill('#password', password);
await page.click('#login');
const currentUrl = page.url();
expect(currentUrl).toContain('/dashboard');
});
});
Now your data is external and easily editable, even by non-developers.
For teams working with spreadsheets or large tabular data, CSV is a popular choice. You can use a CSV parser like csv-parse to load the data.
// login.csv
username,password
admin,admin123
user,user123
test,wrongPass
// utils/csvReader.ts
import * as fs from 'fs';
import * as path from 'path';
import { parse } from 'csv-parse/sync';
export function readCsvData(filePath: string)
{
const content = fs.readFileSync(path.resolve(filePath));
return parse(content, {
columns: true,
skip_empty_lines: true,
}) as Array<{ username: string; password: string }>;
}
// tests/login-csv.spec.ts
import { test, expect } from '@playwright/test';
import { readCsvData } from '../utils/csvReader';
const data = readCsvData('./data/loginData.csv');
data.forEach(({ username, password }) =>
{
test(`Login test (CSV) - ${username}`, async ({ page }) =>
{
await page.goto('https://example.com/login');
await page.fill('#username', username);
await page.fill('#password', password);
await page.click('#login');
const currentUrl = page.url();
expect(currentUrl).toContain('/dashboard');
});
});
This method is especially useful when you need to run hundreds of test cases from spreadsheet-style data.
Externalize your data: Use JSON or CSV to make data easier to update and manage.
Use descriptive test titles: Include data points (e.g., usernames) in your test names for easier debugging.
Cover a variety of scenarios: Include valid, invalid, and edge-case inputs.
Don’t repeat yourself (DRY): Keep the logic clean and reusable.
Hook it into CI/CD: Automate these tests as part of your deployment pipeline.
If you’re writing more complex tests (e.g., with setup/teardown, multiple roles, or dynamic environments), look into Playwright’s fixtures system. It allows you to inject data or logic directly into test contexts for even more control.
Data-driven testing isn't just a “nice-to-have”—it’s a smart way to build more resilient and flexible test automation.
With Playwright and TypeScript, you’ve got all the tools you need to implement it quickly, whether your data lives in a JSON file, CSV spreadsheet, or even a database. Start by moving a few hardcoded values into structured data, and you'll see your test coverage and maintainability improve dramatically.
Refactor one of your existing test files to use JSON-based input.
Try loading data from a CSV using the csv-parse library.
Set up your Playwright suite to run on different data sets in your CI pipeline.