← Back to Home

Playwright Automation Testing - Complete Guide

1. Introduction to Playwright

Playwright is a modern, open-source automation framework developed by Microsoft, enabling fast, reliable end-to-end testing of web applications. It supports multiple languages (JavaScript, TypeScript, Python, Java, .NET) and covers all modern browsers like Chromium, Firefox, and WebKit.

Playwright’s strength is its automatic wait handling, modern architecture, and cross-browser capabilities. It is especially popular for testing Single Page Applications (SPAs) with dynamic elements and complex client-side logic.

2. Why Playwright?

Overall, Playwright is designed to simplify modern test automation challenges with fewer dependencies and less boilerplate code.

3. Installing Playwright

Playwright is built on Node.js. Before starting, ensure you have Node.js installed on your machine. You can verify by running:

node -v

If not installed, download from Node.js official site.

Install Playwright Using NPM

npm init playwright@latest

This command will initialize a new Playwright project, letting you choose:

Playwright will automatically download browser binaries for Chromium, Firefox, and WebKit.

Project Structure

After setup, a typical Playwright project folder will look like this:


tests/
  example.spec.js
playwright.config.js
package.json
  

You are now ready to write your first Playwright script!

4. Writing Your First Playwright Test

Let’s write a simple test to check the Playwright setup. By default, the Playwright test runner uses @playwright/test which supports powerful test functions and assertions.

Create a file called example.spec.js under the tests folder:

const { test, expect } = require('@playwright/test');

test('should have correct page title', async ({ page }) => {
  await page.goto('https://playwright.dev/');
  await expect(page).toHaveTitle(/Playwright/);
});

This test will:

Running the Test

In your terminal, run:

npx playwright test

Playwright will launch the browser in headless mode and execute your test. You’ll see a success or failure report in the console.

View HTML Reports

After running, you can generate an HTML report:

npx playwright show-report

This will open a graphical test report in your browser.

5. Understanding Locators in Playwright

Locators are at the heart of Playwright. They help you identify and interact with page elements. Playwright offers powerful locator strategies that automatically retry and wait until the element is ready, reducing flaky tests.

Common Locator Types

Using Locators

You can perform actions with locators:


await page.locator('#username').fill('myUser');
await page.locator('#password').fill('myPass');
await page.locator('button[type=submit]').click();
  

Playwright’s locator engine supports chaining and powerful queries:


await page.locator('.card').filter({ hasText: 'Special Offer' }).click();
  

These locators make it easy to write readable, maintainable tests.

6. Assertions in Playwright

Playwright includes a powerful set of built-in assertions that integrate seamlessly with its test runner. Assertions validate that the page or elements meet expected conditions.

Common Assertions

Why Assertions Matter

Assertions make your tests meaningful by verifying the correct state of the application after performing actions. Without assertions, you are only performing steps without validating outcomes.

Best Practices

7. Handling Dropdowns, Alerts, and Iframes

Handling Dropdowns

You can select an option from a dropdown using:


await page.selectOption('#country', 'IN'); // Selects India by value
  

You can also select by label or index with selectOption.

Handling Alerts and Pop-ups

Playwright provides event listeners for handling dialogs:


page.on('dialog', async dialog => {
  console.log(dialog.message());
  await dialog.accept();
});
  

This pattern helps manage confirmation boxes or JavaScript alerts.

Working with Iframes

To work with elements inside an iframe:


const frame = page.frame({ name: 'myFrame' });
await frame.click('button#submit');
  

You can locate the iframe either by its name, url, or other attributes.

File Uploads

Playwright supports file uploads directly:


await page.setInputFiles('input[type=file]', 'myfile.pdf');
  

File Downloads

To handle downloads:


const [ download ] = await Promise.all([
  page.waitForEvent('download'),
  page.click('a#downloadLink')
]);
await download.saveAs('myfile.pdf');
  

8. Page Object Model in Playwright

The Page Object Model (POM) is a design pattern that helps you organize test code by separating page interactions into reusable classes. This improves maintainability and readability.

Creating a Page Object

For example, create a file called loginPage.js:


class LoginPage {
  constructor(page) {
    this.page = page;
    this.usernameInput = page.locator('#username');
    this.passwordInput = page.locator('#password');
    this.loginButton = page.locator('button[type=submit]');
  }
  
  async login(username, password) {
    await this.usernameInput.fill(username);
    await this.passwordInput.fill(password);
    await this.loginButton.click();
  }
}
module.exports = { LoginPage };
  

Using the Page Object

In your test file:


const { LoginPage } = require('./loginPage');

test('login scenario', async ({ page }) => {
  const login = new LoginPage(page);
  await page.goto('https://example.com/login');
  await login.login('user1', 'pass1');
  await expect(page).toHaveURL(/dashboard/);
});
  

POM makes tests cleaner and easier to update when page layouts change.

↑ Back to Dropdowns & Alerts

9. Data-driven Testing in Playwright

Data-driven testing lets you run the same test scenario with different sets of data. This improves coverage and reduces duplication.

Example with Inline Data


const { test, expect } = require('@playwright/test');

const dataSet = [
  { username: 'user1', password: 'pass1' },
  { username: 'user2', password: 'pass2' }
];

for (const data of dataSet) {
  test(`login test for ${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]');
    await expect(page).toHaveURL(/dashboard/);
  });
}
  

Reading from JSON

You can also store test data in an external JSON file and import it:


// data.json
[
  { "username": "u1", "password": "p1" },
  { "username": "u2", "password": "p2" }
]
  

// test file
const data = require('./data.json');
for (const record of data) {
  test(`login test for ${record.username}`, async ({ page }) => {
    // same steps
  });
}
  

Benefits

10. Parallel Test Execution in Playwright

Playwright supports parallel execution natively, running multiple tests simultaneously to speed up overall execution.

How It Works

Playwright creates workers that run test files in parallel. By default, it will choose the number of workers based on your CPU cores.

Running in Parallel

npx playwright test --workers=4

This will run 4 parallel workers. Adjust the number to suit your machine or CI pipeline.

Configuration

You can also configure the number of workers in playwright.config.js:


module.exports = {
  workers: 3
};
  

Best Practices

11. Reporting in Playwright

Playwright provides several built-in reporting options to help you analyze test results. The default HTML report is easy to use and visually appealing.

Generating an HTML Report

After running your tests, you can view the report using:

npx playwright show-report

This will open an HTML-based dashboard summarizing your test results, including passed/failed test cases and their timings.

Custom Reporters

Playwright also supports adding custom reporters in your playwright.config.js:


module.exports = {
  reporter: [
    ['list'],
    ['json', { outputFile: 'results.json' }],
    ['html', { open: 'never' }]
  ]
};
  

This configuration uses a list reporter, a JSON file for automation pipelines, and an HTML report without auto-opening.

Popular Third-Party Reporting Options

Reporting helps stakeholders and developers understand test quality over time.

12. Integrating Playwright with CI/CD

Integrating Playwright into a CI/CD pipeline ensures tests run automatically whenever code changes are pushed. Popular platforms like GitHub Actions, GitLab CI, and Jenkins support Playwright seamlessly.

Example: GitHub Actions

Create a file called .github/workflows/playwright.yml:


name: Playwright Tests
on:
  push:
    branches: [ main ]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install dependencies
        run: npm ci
      - name: Install Playwright browsers
        run: npx playwright install --with-deps
      - name: Run tests
        run: npx playwright test
  

Other CI Tools

Benefits of CI/CD Automation

13. Best Practices in Playwright

Following best practices makes your Playwright tests more reliable, easier to maintain, and faster to execute.

Recommended Practices

Debugging Tips

Maintainability

14. Final Mini Project: Automated Login Flow

This example demonstrates a simple Playwright test framework structure using the Page Object Model (POM) to test a login feature.

1. Project Structure


playwright-login/
├── tests/
│   └── login.spec.js
├── pages/
│   └── LoginPage.js
├── data/
│   └── credentials.json
├── playwright.config.js
├── package.json
  

2. Page Object – LoginPage.js


class LoginPage {
  constructor(page) {
    this.page = page;
    this.username = page.locator('#username');
    this.password = page.locator('#password');
    this.loginBtn = page.locator('button[type=submit]');
  }

  async goto() {
    await this.page.goto('https://example.com/login');
  }

  async login(user, pass) {
    await this.username.fill(user);
    await this.password.fill(pass);
    await this.loginBtn.click();
  }
}
module.exports = { LoginPage };
  

3. Test File – login.spec.js


const { test, expect } = require('@playwright/test');
const { LoginPage } = require('../pages/LoginPage');
const data = require('../data/credentials.json');

for (const { username, password } of data) {
  test(`Login test for ${username}`, async ({ page }) => {
    const login = new LoginPage(page);
    await login.goto();
    await login.login(username, password);
    await expect(page).toHaveURL(/dashboard/);
  });
}
  

4. Test Data – credentials.json


[
  { "username": "user1", "password": "pass1" },
  { "username": "user2", "password": "pass2" }
]
  

5. Run the Tests

npx playwright test

This small framework can be extended to other modules like registration, search, dashboard, etc.

15. Resources & Further Learning

Here are some official and community-driven resources to go deeper with Playwright:

Official Documentation

Learning & Practice

Community

Bookmark these resources and keep exploring the ecosystem as Playwright evolves rapidly.