Skip to main content

Quality Assurance

Running Multiple Test Cases from a CSV File Using Playwright and TypeScript.

Digital Technology, Software Development Concept. Coding Programmer Working On Laptop With Circuit Board And Javascript On Virtual Screen

In the world of automated testing, maintaining flexibility and scalability is crucial—especially when it comes to validating functionality across multiple data inputs. Data-driven testing enables QA professionals to decouple test scripts from the input data, allowing the same test flow to run with multiple sets of inputs.

This tutorial explains how to set up data-driven tests in Playwright using TypeScript, where external CSV files provide varying input data for each scenario.

This approach is highly effective for validating login scenarios, form submissions, and any functionality that depends on multiple sets of data.

Why Use Data-Driven Testing?

Data-driven testing provides several benefits:

  • Reduced Code Duplication: Instead of writing multiple similar tests, a single test reads various inputs from an external file.
  • Improved Maintainability: Test data can be modified independently of the test logic.
  • Scalability: Enables easier scaling of testing across a wide range of input combinations.

When working with TypeScript and Playwright, using CSV files for test input is a natural fit for structured test cases, such as form validation, login testing, and e-commerce transactions.

Setting Up the Project

To get started, make sure you have a Playwright and TypeScript project set up. If not, here’s how to initialize it:

npm init -y

npm install -D @playwright/test

npx playwright install

Enable TypeScript support:

npm install -D typescript ts-node

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Create a basic tsconfig.json:
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "dist"
},
"include": ["*.ts"]
}
Create a basic tsconfig.json: { "compilerOptions": { "target": "ES6", "module": "commonjs", "strict": true, "esModuleInterop": true, "outDir": "dist" }, "include": ["*.ts"] }
Create a basic tsconfig.json:

{

  "compilerOptions": {

    "target": "ES6",

    "module": "commonjs",

    "strict": true,

    "esModuleInterop": true,

    "outDir": "dist"

  },

  "include": ["*.ts"]

}

 

Now, install a CSV parsing library:

npm install csv-parse

Creating the CSV File

We’ll begin by setting up a basic loginData.csv file containing sample login credentials.

username, password

user1,password1

user2,password2

invalidUser,wrongPass

Save it in your project root directory.

Reading CSV Data in TypeScript

Create a helper function, readCSV.ts, to parse CSV files:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import fs from 'fs';
import { parse } from 'csv-parse';
export async functionloadCSV(fileLocation: string): Promise<Record<string, string>[]>{
returnnewPromise((resolve, reject) =>{
const results: Record<string, string>[] = [];
fs.createReadStream(fileLocation)
.pipe(parse({ columns: true, skip_empty_lines: true}))
.on('readable', function(){
let row;
while((row = this.read()) !== null){
results.push(row);
}
})
.on('end', () =>resolve(results))
.on('error', (error) =>reject(error));
});
}
import fs from 'fs'; import { parse } from 'csv-parse'; export async function loadCSV(fileLocation: string): Promise<Record<string, string>[]> { return new Promise((resolve, reject) => { const results: Record<string, string>[] = []; fs.createReadStream(fileLocation) .pipe(parse({ columns: true, skip_empty_lines: true })) .on('readable', function () { let row; while ((row = this.read()) !== null) { results.push(row); } }) .on('end', () => resolve(results)) .on('error', (error) => reject(error)); }); }
import fs from 'fs';

import { parse } from 'csv-parse';

export async function loadCSV(fileLocation: string): Promise<Record<string, string>[]> {

  return new Promise((resolve, reject) => {

    const results: Record<string, string>[] = [];

    fs.createReadStream(fileLocation)

      .pipe(parse({ columns: true, skip_empty_lines: true }))

      .on('readable', function () {

        let row;

        while ((row = this.read()) !== null) {

          results.push(row);

        }

      })

      .on('end', () => resolve(results))

      .on('error', (error) => reject(error));

  });

}

Writing the Data-Driven Test in Playwright

Now, let’s write a test that uses this CSV data. Create a file named login.spec.ts:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { test, expect } from '@playwright/test';
import { readCSV } from './readCSV';
test.describe('Data-Driven Login Tests', () =>{
let testData: Array<{ username: string; password: string }>;
test.beforeAll(async() =>{
testfile = await readCSV('./loginData.csv');
});
for(const data of testfile ||[]){
test(`Log in attempt with ${data.username}`, async({ page }) =>{
await page.goto('https://example.com/login');
await page.fill('#username', data.username);
await page.fill('#password', data.password);
await page.click('button[type="submit"]');
// Adjust this check based on expected outcomes
if(data.username.startsWith('user')){
await expect(page).toHaveURL(/dashboard/);
}else{
expect(page.locator('.error-text')).toBeVisible();
}
});
}
});
import { test, expect } from '@playwright/test'; import { readCSV } from './readCSV'; test.describe('Data-Driven Login Tests', () => { let testData: Array<{ username: string; password: string }>; test.beforeAll(async () => { testfile = await readCSV('./loginData.csv'); }); for (const data of testfile || []) { test(`Log in attempt with ${data.username}`, async ({ page }) => { await page.goto('https://example.com/login'); await page.fill('#username', data.username); await page.fill('#password', data.password); await page.click('button[type="submit"]'); // Adjust this check based on expected outcomes if (data.username.startsWith('user')) { await expect(page).toHaveURL(/dashboard/); } else { expect(page.locator('.error-text')).toBeVisible(); } }); } });
import { test, expect } from '@playwright/test';

import { readCSV } from './readCSV';




test.describe('Data-Driven Login Tests', () => {

  let testData: Array<{ username: string; password: string }>;




  test.beforeAll(async () => {

    testfile = await readCSV('./loginData.csv');

  });




  for (const data of testfile || []) {

    test(`Log in attempt with ${data.username}`, async ({ page }) => {

      await page.goto('https://example.com/login');

      await page.fill('#username', data.username);

      await page.fill('#password', data.password);

      await page.click('button[type="submit"]');




      // Adjust this check based on expected outcomes

      if (data.username.startsWith('user')) {

        await expect(page).toHaveURL(/dashboard/);

      } else {

         expect(page.locator('.error-text')).toBeVisible();

      }

    });

  }

});

The approach reads each row from the CSV and generates individual test cases dynamically, using the data from each entry as input parameters.

Best Practices

  • Separate Test Data from Logic: Always keep your data files separate from test scripts to simplify maintenance.
  • Validate Test Inputs: Ensure CSV files are clean and correctly formatted.
  • Parameterize Conditions: Adjust validation logic based on the nature of test data (e.g., valid vs. invalid credentials).

Conclusion

Using CSV-based data-driven testing with Playwright and TypeScript offers a powerful way to scale test coverage without bloating your codebase. It’s ideal for login scenarios, input validation, and other repetitive test cases where only the data varies.

By externalizing your data and looping through test scenarios programmatically, you can reduce redundancy, improve maintainability, and support continuous delivery pipelines more effectively.

As your application grows, this strategy will help ensure that your test suite remains efficient, readable, and scalable.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Uddesh Jain

Uddesh Jain is a technical consultant with over 4 years of experience in software testing. He is strongly interested in discovering new technologies and is driven to impart knowledge through his blogs.

More from this Author

Follow Us