← Back

Playwright Test Cases & Test Suites

Complete guide to designing Playwright test cases and test suites with Python, real-time application examples, fixtures, parametrization, tagging, and CI execution.

1 What Is a Test Case?

A test case verifies one business behavior with controlled data, clear actions, and expected results.

Python Playwright
def test_successful_login(page):
    page.goto("https://demo.example.com/login")
    page.get_by_label("Email").fill("qa@example.com")
    page.get_by_label("Password").fill("Password123")
    page.get_by_role("button", name="Login").click()
    expect(page.get_by_role("heading", name="Dashboard")).to_be_visible()
Real-time example: Real-time: verify the customer can log in and reach the Dashboard.
2 What Is a Test Suite?

A test suite groups related tests by feature, risk, release purpose, or business area.

Python Playwright
tests/
├── auth/
├── catalog/
├── checkout/
└── orders/
Real-time example: Real-time: checkout tests stay together so the team can run that feature independently.
3 Design Before Coding

Define preconditions, test data, steps, and expected results before writing Playwright code.

Python Playwright
# Test: customer adds Wireless Mouse to cart
# Given: product is in stock
# When: customer clicks Add to cart
# Then: cart shows quantity 1
Real-time example: Real-time: convert the business scenario directly into browser actions and assertions.
4 Clear Test Naming

Use behavior-oriented names that explain the expected outcome.

Python Playwright
def test_customer_can_add_in_stock_product_to_cart(page):
    ...

def test_login_shows_error_for_invalid_password(page):
    ...
Real-time example: Real-time: CI failure names immediately tell the team what behavior broke.
5 Arrange Act Assert

Separate setup, user action, and verification for readable, diagnosable tests.

Python Playwright
def test_update_cart_quantity(page):
    # Arrange
    page.goto("https://shop.example.com/cart")
    # Act
    page.get_by_role("spinbutton", name="Quantity").fill("2")
    # Assert
    expect(page.get_by_text("Quantity: 2")).to_be_visible()
Real-time example: Real-time: a cart test has one obvious setup, action, and business assertion.
6 Smoke Test Suite

Smoke tests cover critical paths and run after every deployment.

Python Playwright
@pytest.mark.smoke
def test_customer_can_login(page):
    ...
Real-time example: Real-time: run a small smoke suite before spending CI time on full regression.
7 Regression Test Suite

Regression tests protect previously working functionality across major features.

Python Playwright
@pytest.mark.regression
def test_coupon_is_applied(page):
    ...

@pytest.mark.regression
def test_order_confirmation_is_shown(page):
    ...
Real-time example: Real-time: run regression nightly or before a release.
8 Feature-Based Structure

Organize files around product capabilities instead of one huge test file.

Python Playwright
tests/
├── auth/test_login.py
├── catalog/test_search.py
├── checkout/test_payment.py
└── orders/test_history.py
Real-time example: Real-time: feature ownership stays clear as the suite grows.
9 Reusable Fixtures

Fixtures centralize repeatable setup such as authenticated customers.

Python Playwright
@pytest.fixture
def logged_in_customer(page):
    login(page, "qa@example.com", "Password123")
    return page
Real-time example: Real-time: order tests reuse the same authenticated state without duplicating login steps.
10 conftest.py

Use conftest.py for fixtures shared across many test modules.

Python Playwright
@pytest.fixture
def customer_credentials():
    return {"email":"qa@example.com", "password":"Password123"}
Real-time example: Real-time: common credentials and environment helpers live in one place.
11 Independent Tests

Each test should create or obtain its own required state and must not depend on test order.

Python Playwright
def test_order_history(page):
    seed_order_for("qa@example.com")
    page.goto("https://shop.example.com/orders")
    expect(page.get_by_role("heading", name="My Orders")).to_be_visible()
Real-time example: Real-time: if another test fails, this test can still run.
12 Avoid Shared Mutable State

Do not assume another test left the browser on a specific page or with a specific cart.

Python Playwright
def test_checkout_requires_address(page):
    page.goto("https://shop.example.com/checkout")
    expect(page.get_by_label("Billing address")).to_be_visible()
Real-time example: Real-time: navigation is explicit, so the test is deterministic.
13 Parametrize Test Data

Use pytest parametrization when behavior is identical but input data varies.

Python Playwright
@pytest.mark.parametrize("amount,expected", [
    ("0", "Amount must be greater than 0"),
    ("1000000", "Amount exceeds daily limit")
])
def test_transfer_boundaries(page, amount, expected):
    ...
Real-time example: Real-time: one test covers multiple banking limits.
14 pytest.mark Categories

Markers let you select smoke, regression, checkout, critical, or other groups.

Python Playwright
@pytest.mark.checkout
@pytest.mark.smoke
def test_checkout(page):
    ...
Real-time example: Run focused suites with pytest -m checkout or pytest -m "smoke and checkout".
15 Critical Path Suite

Keep a small set of revenue, authentication, and high-risk tests for frequent execution.

Python Playwright
@pytest.mark.critical
def test_customer_can_purchase_product(page):
    add_product(page, "Wireless Mouse")
    checkout(page)
    expect(page.get_by_text("Order confirmed")).to_be_visible()
Real-time example: Real-time: protect the core purchase journey after every deployment.
16 Page Object Model

Move repeated UI actions and locators into page objects while tests describe business behavior.

Python Playwright
class LoginPage:
    def __init__(self, page):
        self.page = page
        self.email = page.get_by_label("Email")
        self.password = page.get_by_label("Password")
        self.login_button = page.get_by_role("button", name="Login")

    def login(self, email, password):
        self.email.fill(email)
        self.password.fill(password)
        self.login_button.click()
Real-time example: Real-time: a locator change is fixed in one page object.
17 Business-Focused Tests

Keep test names and flows aligned to customer outcomes, hiding low-level UI details when useful.

Python Playwright
def test_customer_can_download_invoice(invoice_page):
    invoice_page.open_latest_order()
    invoice_page.download_invoice()
    expect(invoice_page.success_message).to_be_visible()
Real-time example: Real-time: the test reads like a requirement, not a click script.
18 API + UI Data Setup

Create expensive prerequisite data through an API and verify the user-facing result through the UI.

Python Playwright
api.post("/customers", data={"email":"new@example.com"})
page.goto("https://shop.example.com/profile")
expect(page.get_by_text("new@example.com")).to_be_visible()
Real-time example: Real-time: seed a customer quickly, then validate the web experience.
19 Authentication State

Save authenticated browser state for suites that do not need to test the login flow itself.

Python Playwright
# after successful login
page.context.storage_state(path="playwright/.auth/customer.json")
Real-time example: Real-time: checkout tests start authenticated without repeating login.
20 Separate Auth Tests

Login correctness belongs in authentication tests; downstream tests should use authenticated fixtures.

Python Playwright
def test_invalid_login(page):
    ...

def test_customer_can_open_orders(authenticated_page):
    authenticated_page.goto("https://shop.example.com/orders")
    ...
Real-time example: Real-time: a login outage is diagnosed in one auth test instead of failing every suite.
21 Negative Tests

Validate invalid input, denied access, insufficient balance, duplicate actions, and other expected failures.

Python Playwright
def test_transfer_rejects_insufficient_balance(page):
    page.goto("https://bank.example.com/transfer")
    page.get_by_label("Amount").fill("100000")
    page.get_by_role("button", name="Transfer").click()
    expect(page.get_by_text("Insufficient balance")).to_be_visible()
Real-time example: Real-time: banking automation verifies both successful and rejected transactions.
22 Boundary Tests

Cover minimum, maximum, empty, and exact-limit values where business rules matter.

Python Playwright
@pytest.mark.parametrize("value", ["0", "1000000"])
def test_amount_limits(page, value):
    page.get_by_label("Amount").fill(value)
    page.get_by_role("button", name="Transfer").click()
Real-time example: Real-time: boundary coverage catches off-by-one and validation defects.
23 Role-Based Suites

Use fixtures for admin, manager, and customer roles and test authorization explicitly.

Python Playwright
def test_customer_cannot_open_admin_page(customer_page):
    customer_page.goto("https://app.example.com/admin/users")
    expect(customer_page.get_by_text("Access denied")).to_be_visible()
Real-time example: Real-time: permission tests state exactly which role should have access.
24 Smoke vs Regression vs Full

Use layered execution: smoke for health, regression for broad coverage, full for everything.

Python Playwright
pytest -m smoke
pytest -m regression
pytest
Real-time example: Real-time: pull requests get fast feedback while scheduled runs get full coverage.
25 Workflow Scenarios

If a true business flow is sequential, keep the lifecycle together instead of making separate tests depend on order.

Python Playwright
def test_order_lifecycle(page):
    create_order(page)
    approve_order(page)
    ship_order(page)
    deliver_order(page)
    expect(page.get_by_text("Delivered")).to_be_visible()
Real-time example: Real-time: an order lifecycle is naturally sequential, so model it as one workflow.
26 Meaningful Assertions

Assertions should verify business outcomes, not just that a click completed.

Python Playwright
page.get_by_role("button", name="Generate").click()
expect(page.get_by_text("Report ready")).to_be_visible()
Real-time example: Real-time: verify the report-ready state instead of asserting only that the button was clicked.
27 Requirement Traceability

Map important tests to requirement or story IDs for coverage visibility.

Python Playwright
@pytest.mark.requirement("CHK-104")
def test_customer_can_apply_valid_coupon(page):
    ...
Real-time example: Real-time: a requirement ID links automation back to the business story.
28 Folder + Marker Strategy

Folders provide discoverability while markers provide flexible execution across risk and feature dimensions.

Python Playwright
tests/smoke/
tests/regression/

pytest tests/smoke
pytest -m checkout
Real-time example: Real-time: teams can run either an owned folder or a cross-cutting marker.
29 Flaky Test Management

Retries should not hide flaky behavior. Track unstable tests and investigate timing, data, environment, or locator causes.

Python Playwright
@pytest.mark.flaky
def test_payment_confirmation(page):
    ...
Real-time example: Real-time: isolate a flaky test for investigation while keeping the root cause visible.
30 Trace and Failure Artifacts

Use Playwright traces, screenshots, and videos according to the CI retention policy.

Python Playwright
pytest --tracing=retain-on-failure --screenshot=only-on-failure
Real-time example: Real-time: a failed checkout can be diagnosed from the recorded browser state.
31 Parallel Execution

Independent tests can run across workers to shorten feedback time. Keep test data isolated.

Python Playwright
pytest -n 4
Real-time example: Real-time: four independent product tests can execute concurrently without sharing mutable state.
32 CI Environment Configuration

Use environment variables for URLs, credentials, and deployment-specific settings.

Python Playwright
import os
BASE_URL = os.environ["BASE_URL"]

def test_home(page):
    page.goto(BASE_URL)
Real-time example: Real-time: the same suite can target QA, staging, or another approved environment.
33 Prefer Web-First Waiting

Use Playwright assertions and auto-waiting instead of fixed sleeps wherever possible.

Python Playwright
page.get_by_role("button", name="Generate").click()
expect(page.get_by_text("Report ready")).to_be_visible()
Real-time example: Real-time: wait for the business result instead of sleeping for a fixed number of seconds.
34 Browser Test Matrix

Run important scenarios across supported browser projects without multiplying every test unnecessarily.

Python Playwright
# Playwright projects can cover chromium, firefox, and webkit.
# Keep the highest-risk scenarios in the cross-browser matrix.
Real-time example: Real-time: login and checkout can be cross-browser while low-risk tests stay on the default project.
35 Release Pipeline Strategy

Layer checks from fastest to broadest: unit/API, smoke UI, targeted regression, then full cross-browser coverage.

Python Playwright
pytest tests/smoke
pytest tests/regression -m "critical or checkout"
pytest tests/e2e
Real-time example: Real-time: fail fast on smoke failures before spending CI time on the full suite.
36 Complete E-Commerce Example

Combine fixtures, page objects, markers, positive and negative cases around one business domain.

Python Playwright
@pytest.mark.ecommerce
@pytest.mark.smoke
def test_customer_can_buy_product(authenticated_shop):
    authenticated_shop.add_product("Wireless Mouse")
    authenticated_shop.checkout()
    expect(authenticated_shop.order_confirmation).to_be_visible()
Real-time example: Real-time: protect the purchase journey while keeping supporting checkout cases in regression.
37 Recommended Project Blueprint

Separate configuration, fixtures, page objects, test data, and suites as the project grows.

Python Playwright
playwright-python/
├── pages/
├── tests/smoke/
├── tests/regression/
├── test_data/
├── conftest.py
├── pytest.ini
└── requirements.txt
Real-time example: Real-time: this structure stays manageable as more teams and features are added.
38 Final Test-Design Mental Model

Think: business behavior → test case → data → fixture → Playwright actions → assertions → suite/marker → CI. Keep tests independent, readable, deterministic, and risk-focused.

Python Playwright
@pytest.mark.smoke
def test_customer_can_complete_checkout(authenticated_shop):
    authenticated_shop.add_product("Wireless Mouse")
    authenticated_shop.complete_payment("test-card")
    expect(authenticated_shop.order_confirmation).to_be_visible()
Real-time example: Final rule: automate behavior that matters to the business, organize it into purposeful suites, and let Playwright handle browser synchronization.