Skip to main content

How to build a scalable test automation framework with Playwright and Pytest

Posted By

Pratima Jadhav

Date Posted
24-Jan-2026

Shipping software fast is hard. Shipping it fast without breaking things is even harder. As products grow, test suites become difficult to maintain, pipelines slow down, and flaky UI tests start costing real engineering time.

That is where a well-designed automation framework matters. Not just a set of scripts, but a structure that supports clean test design, reliable execution, and fast debugging when failures happen.

In this blog series, we walk through how to build an enterprise-ready automation framework that supports:

  • Page Object Model
  • JSON-based test data
  • Retry mechanisms
  • Allure and HTML reports
  • Slack notifications
  • GitHub Actions CI/CD pipelines

By the end of this guide, you will have a production-ready framework that supports cross-browser testing, parallel execution, and team-friendly reporting.

What is Playwright?

Playwright is Microsoft’s next-generation automation framework designed for browser, API, and UI testing. It supports modern web applications built using frameworks such as React, Angular, and Vue, and it is designed to handle dynamic content and asynchronous behaviour reliably.

Unlike traditional browser automation tools that rely heavily on external drivers, Playwright communicates directly with browser engines. This gives it better control over browser behaviour, faster execution, and more consistent results.

Key features of Playwright

  • Multi-browser support (Chromium, Firefox, WebKit)
  • Multi-language bindings (Python, JavaScript, Java, .NET)
  • Auto-waiting for elements and network events
  • Web-first assertions
  • Built-in tracing, video, and screenshot capture
  • Test isolation using browser contexts
  • Network mocking
  • Native API testing support

These features significantly reduce flakiness and make debugging easier, especially when failures occur in CI pipelines.

Comparison btween Playwright and Selenium 

Both Playwright and Selenium automate browsers, but their internal architectures are fundamentally different. These differences affect test stability, execution speed, and maintenance effort over time.

Feature Playwright Selenium Winner
Auto-waiting Built-in Manual waits required Playwright
Speeed Very fast Slower (legacy protocol) Playwright
Architecture Single API across browsers WebDriver dependent Playwright
Trace & Video Inbuilt Third-party tools Playwright
Shadow DOM Supports Limited Playwright
API Testing  Native Needs RestAssured/Postman Playwright
Test Isolation Per test browser/context Shared session patterns common Playwright
Flakiness Very low Medium–High Playwright

Why enterprises prefer Playwright over Selenium:

  • Lower maintenance
  • Fewer flaky tests
  • Native modern app support
  • Faster CI execution
  • Reduced debugging time

Why Python works well for automation

  • Simple and readable syntax
  • Large library ecosystem
  • Strong support for API and async workflows
  • Faster onboarding for new team members

Python allows both developers and QA engineers to contribute to automation without steep learning curves.

Why Pytest is suitable for enterprise testing

  • Plugin-based architecture
  • Powerful fixtures for browser lifecycle management
  • Rich reporting integrations
  • Native support for markers, retries, and parametrization
  • Smooth integration with Playwright

Together, Python and Pytest form an enterprise-grade automation stack that balances ease of use with scalability.

Real-world use cases for Playwright automation

Playwright is widely used across industries where reliability and compliance are critical:

  • E-commerce functional testing
  • Banking UI validation
  • Insurance workflows
  • Admin dashboards and portals
  • Multi-role authentication flows
  • Progressive web apps
  • API + UI integrated test flows

Because Playwright supports both API and UI testing, teams can validate complete business workflows instead of testing each layer independently.

Playwright test automation model

High-level framework architecture

modern-Playwright-framework/
  ├── config/
  │    └── config.json
  ├── pages/
  │    └── login_page.py
  ├── tests/
  │    └── test_login_regression.py
  ├── utils/
  │    ├── json_reader.py
  │    └── slack_notify.py
  ├── testdata/
  │    └── login.json
  ├── reports/
  ├── conftest.py
  ├── pytest.ini
  ├── requirements.txt
  └── .github/workflows/Playwright-ci.yml

This structure separates responsibilities clearly, which helps teams scale test coverage without turning the repository into a maintenance problem.

Building the framework structure

You are now moving from concepts into implementation. This section explains how to structure a Playwright Pytest automation framework so it remains maintainable, scalable, and enterprise-ready as test coverage and team size grow.

This framework structure follows proven automation design patterns used in large QA teams to support parallel execution, CI/CD integration, and long-term test stability.

Folder structure explained

project/
  ├── config/         → Environment configs
  ├── pages/          → Page Object Model classes
  ├── tests/          → Test suites
  ├── utils/          → Reusable utilities
  ├── testdata/       → JSON test data
  ├── reports/        → HTML/Allure reports
  ├── conftest.py     → Pytest fixtures
  ├── pytest.ini      → Test configuration
  └── requirements.txt

Why this structure works

  • Separation of concerns
  • Scalable for 500+ test cases
  • Team collaboration enabled
  • Reduces code duplication

This layout also aligns well with standard enterprise automation guidelines.

Page Object Model (POM)

The Page Object Model enforces separation between UI interaction logic and test validation logic. UI actions are wrapped inside page classes instead of being written directly in test files.

Page Object Model

Why POM works well with Playwright?

  • Keeps test scripts short and readable
  • Centralizes locator updates
  • Encapsulates business workflows
  • Makes UI changes easier to manage

This reduces the ripple effect of UI updates across the test suite.

Locators as global constants

Selectors should not be scattered across test files.

Best practices:

  • Avoid raw locators inside tests
  • Define locators as reusable constants in page classes
  • Keep selector changes localized

Example:

USERNAME_INPUT = "#username"
PASSWORD_INPUT = "#password"
LOGIN_BUTTON   = "//button[text()='Login']"

Config file for environment management

config/config.json
{
  "base_url": "https://demo-app.com",
  "env": "qa"
}

Using a centralized config file allows the same test suite to run across environments without modifying code.

JSON test data handling

testdata/login.json

{
  "valid_user": {
    "username": "admin@test.com",
    "password": "Admin@123"
  }
}

Utility to load test data:

class JSONReader:
    @staticmethod
    def load_json(path):
        import json
        with open(path) as f:
            return json.load(f)

Separating test data from logic allows business inputs to change independently from automation code.

LoginPage POM example

pages/login_page.py

from Playwright.sync_api import Page

class LoginPage:

    USERNAME = "#username"
    PASSWORD = "#password"
    LOGIN_BTN = "button[type='submit']"

    def __init__(self, page: Page):
        self.page = page

    def login(self, username, password):
        self.page.fill(self.USERNAME, username)
        self.page.fill(self.PASSWORD, password)
        self.page.click(self.LOGIN_BTN)
        self.page.wait_for_url("**/dashboard")

This page object exposes business actions instead of raw UI commands, which keeps tests focused on outcomes.

Writing & executing tests

This section focuses on converting your framework into working test suites, showing how Playwright and Pytest work together to create reliable, readable, and repeatable automated test cases.

Creating Pytest test cases

tests/test_login_regression.py

import pytest
from utils.json_reader import JSONReader
from pages.login_page import LoginPage

@pytest.mark.regression
def test_valid_login(setup):
    page = setup
    data = JSONReader.load_json("testdata/login.json")["valid_user"]

    login = LoginPage(page)
    login.login(data["username"], data["password"])

    assert "dashboard" in page.url, "Login failed!"

This test reads like a business scenario instead of a sequence of UI commands.

Pytest markers

pytest.ini

[pytest]
markers =
  regression: Regression Test Suite
  smoke: Smoke Test Suite

addopts = --reruns 2 --html=reports/report.html --self-contained-html

Markers allow selective execution based on pipeline stage or risk level.

Retry mechanism

Enabled through:

pytest --reruns 2 --reruns-delay 3

Retries help stabilize pipelines affected by temporary network or infrastructure delays.

End-to-end login example

The flow validates:

  • Navigation
  • Test data loading
  • POM interaction
  • Assertions
  • Reporting
  • Screenshots

The entire workflow is validated using Playwright’s stable browser automation.

Allure + HTML Reports

Install:

pip install allure-pytest pytest-html

Execute:

pytest --alluredir=allure-results
allure serve allure-results

Reports provide visibility for both technical and non-technical stakeholders.

Screenshots and tracing on failure

Inside conftest.py:

if request.node.rep_call.failed:
    page.screenshot(path=f"reports/{request.node.name}.png")

Tracing:

page.context.tracing.start()
page.context.tracing.stop(path="trace.zip")

Parallel test execution

Pytest:

pytest -n 4

Playwright’s isolated browser contexts allow safe parallel execution without shared state issues.

CI/CD + Slack notification integration

Automation only delivers real value when it runs consistently in CI/CD pipelines and shares results with the team. This section shows how to integrate your Playwright Pytest framework with GitHub Actions and push execution updates directly to Slack.

Github actions workflow

.github/workflows/Playwright-ci.yml

name: Playwright Automation

on:
  push:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Install Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.10"

      - name: Install dependencies
        run: |
          pip install -r requirements.txt
          Playwright install

      - name: Run Tests
        run: pytest --alluredir=allure-results

      - name: Upload Report Artifact
        uses: actions/upload-artifact@v3
        with:
          name: allure-results
          path: allure-results

      - name: Notify Slack
        run: python utils/slack_notify.py
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

This ensures automated validation on every push to the main branch.

Slack notification integration

utils/slack_notify.py
import requests
import json
import os

def send_message(text):
    url = os.getenv("SLACK_WEBHOOK")
    payload = {"text": text}
    requests.post(url, data=json.dumps(payload))

if __name__ == "__main__":
    send_message("Playwright Test Execution Completed. Reports Uploaded!")

Notifications keep the team informed without manual monitoring of pipelines.

Sharing summary + report link

Slack notification includes:

  • Total tests executed
  • Passed and failed counts
  • Report link
  • Execution duration

This allows quick assessment of build health.

Best practices for scaling automation

  • Maintain locator versioning
  • Introduce service-layer testing
  • Use test tags for grouping
  • Prevent duplicate test coverage
  • Run smoke tests on every pull request
  • Schedule full regression runs nightly

Scaling automation is as much about discipline as it is about tooling.

Future enhancements

Potential next steps include:

  • Dockerized execution
  • Hybrid API and UI workflows
  • Integration with BrowserStack or Sauce Labs
  • Failure trend analysis and clustering

Next steps in your Playwright and pytest automation journey

This series continues with two upcoming deep-dive blogs that focus on advanced testing scenarios:
•    Using Playwright for GenAI application testing 
•    End-to-end MCP server application testing using Playwright + Pytest + Python  with Slack integration

If your team is looking to modernize automation, improve pipeline reliability, or scale test coverage without increasing maintenance overhead, Opcito’s experts are here to help. Contact us for support in designing and implementing automation frameworks that align with your product architecture and delivery goals.

Subscribe to our feed

select webform