Playwright with Docker and Kubernetes (Beginner to Advanced)

Modern organizations rarely execute Playwright tests directly on developers’ machines. Instead, they package the automation framework into Docker containers and execute them in Kubernetes clusters for scalability, consistency, and faster execution.

This chapter explains how to run Playwright in Docker and Kubernetes using industry best practices.


Table of Contents

  1. Why Docker?
  2. Why Kubernetes?
  3. Docker Architecture
  4. Installing Docker
  5. Running Playwright in Docker
  6. Creating Dockerfile
  7. Creating .dockerignore
  8. Docker Commands
  9. Docker Compose
  10. Running Playwright Reports
  11. Kubernetes Architecture
  12. Running Playwright on Kubernetes
  13. Kubernetes Deployment
  14. ConfigMap
  15. Secret Management
  16. Persistent Volumes
  17. Best Practices
  18. Interview Questions

What is Docker?

Docker is a containerization platform that packages an application with all of its dependencies.

Instead of:

Developer Machine

↓

Install Node

↓

Install Playwright

↓

Install Browsers

↓

Install Libraries

Docker packages everything together.


Why Use Docker?

Benefits

  • Same environment everywhere
  • No “works on my machine” issues
  • Easy deployment
  • Portable
  • Lightweight
  • Fast startup
  • CI/CD friendly

Traditional Execution

Developer Laptop

↓

Install Node

↓

Install Browser

↓

Install Dependencies

↓

Run Tests

Different developers may have different versions.


Docker Execution

Docker Image

↓

Node

↓

Playwright

↓

Chromium

↓

Firefox

↓

WebKit

↓

Automation Code

Everyone runs the exact same environment.


Docker Architecture

               Docker Engine
                    │
        ┌───────────┼───────────┐
        ▼           ▼           ▼
   Container 1  Container 2  Container 3
      Smoke      Regression      API

Each container is isolated.


Install Docker

Verify installation:

docker --version

Verify Docker Engine:

docker info

List images:

docker images

List running containers:

docker ps

Recommended Project Structure

PlaywrightFramework

│

├── tests/

├── pages/

├── fixtures/

├── utils/

├── playwright.config.ts

├── package.json

├── Dockerfile

├── docker-compose.yml

├── .dockerignore

└── README.md

Understanding Dockerfile

A Dockerfile contains instructions to build a Docker image.

Typical steps:

Base Image

↓

Copy Project

↓

Install Dependencies

↓

Install Browsers

↓

Execute Tests

Sample Dockerfile

FROM mcr.microsoft.com/playwright:v1.55.0-jammy

WORKDIR /app

COPY package*.json ./

RUN npm ci

COPY . .

CMD ["npx", "playwright", "test"]

Explanation

FROM

Uses Microsoft’s official Playwright image, which already includes:

  • Node.js
  • Playwright
  • Supported browsers
  • Required Linux libraries

WORKDIR /app

Creates the working directory.


COPY package*.json ./

Copies package files first to improve Docker layer caching.


RUN npm ci

Installs dependencies exactly as defined in package-lock.json.

Use npm ci in CI/CD rather than npm install because it is faster and more deterministic.


COPY . .

Copies project files.


CMD

Runs Playwright tests.


Build Docker Image

docker build -t playwright-framework .

Explanation

docker build

↓

Create Image

↓

Tag

↓

playwright-framework

Verify Images

docker images

Example

REPOSITORY              TAG

playwright-framework    latest

Run Container

docker run playwright-framework

Run in Interactive Mode

docker run -it playwright-framework

Useful for debugging.


Mount Local Directory

docker run -v ${PWD}:/app playwright-framework

This keeps project files synchronized between the host and the container.


Run Specific Test

docker run playwright-framework npx playwright test tests/login.spec.ts

Pass Environment Variables

docker run \
-e ENV=QA \
-e USERNAME=admin \
playwright-framework

Avoid hardcoding credentials in the image.


.dockerignore

Just like .gitignore, Docker ignores unnecessary files.

Example

node_modules

playwright-report

test-results

.git

.vscode

Benefits

  • Smaller images
  • Faster builds
  • Better performance

Docker Layers

Base Image

↓

Node Modules

↓

Project Files

↓

Automation Code

Docker caches unchanged layers, reducing build times.


Docker Compose

Docker Compose manages multiple containers.

Example

Playwright

↓

Application

↓

Database

↓

API

Sample docker-compose.yml

version: "3.9"

services:
  playwright:
    build: .
    container_name: playwright-tests
    command: npx playwright test
    volumes:
      - .:/app

Run:

docker compose up

Parallel Containers

Instead of

One Container

↓

1000 Tests

Use

Container 1

Smoke

----------------

Container 2

Regression

----------------

Container 3

API

----------------

Container 4

Payments

This reduces execution time.


Storing Reports

Map reports to the host machine.

Example

docker run \
-v ${PWD}/playwright-report:/app/playwright-report \
playwright-framework

Generated reports remain available after the container exits.


Running HTML Report

npx playwright show-report

Kubernetes Introduction

Docker manages containers.

Kubernetes manages many containers across one or more machines.


Why Kubernetes?

Benefits

  • Auto scaling
  • Self healing
  • Load balancing
  • High availability
  • Rolling updates
  • Automatic restarts

Kubernetes Architecture

               Kubernetes Cluster

                     │

        ┌────────────┼────────────┐

        ▼            ▼            ▼

      Node 1      Node 2      Node 3

        │            │            │

     Pod A        Pod B       Pod C

        │            │            │

  Playwright    Playwright   Playwright

Kubernetes Components

ComponentPurpose
ClusterEntire Kubernetes environment
NodePhysical or virtual machine
PodSmallest deployable unit
DeploymentManages Pods
ServiceNetwork access to Pods
ConfigMapStores configuration
SecretStores sensitive values
VolumePersistent storage

Pod

A Pod contains one or more containers.

Example

Pod

↓

Playwright Container

Deployment

A Deployment manages Pods.

Example

Deployment

↓

3 Pods

↓

Auto Restart

↓

Auto Scaling

Sample Deployment YAML

apiVersion: apps/v1

kind: Deployment

metadata:
  name: playwright

spec:
  replicas: 3

  selector:
    matchLabels:
      app: playwright

  template:

    metadata:

      labels:

        app: playwright

    spec:

      containers:

      - name: playwright

        image: playwright-framework:latest

Apply Deployment

kubectl apply -f deployment.yaml

Verify Pods

kubectl get pods

Verify Deployments

kubectl get deployments

Describe Pod

kubectl describe pod <pod-name>

View Logs

kubectl logs <pod-name>

This is the first step when diagnosing failures.


Execute Commands Inside a Pod

kubectl exec -it <pod-name> -- bash

Useful for troubleshooting.


ConfigMap

Store non-sensitive configuration.

Example

Base URL

Environment

Browser

Timeout

Avoid embedding these values in container images.


Secret Management

Never store:

  • Passwords
  • API Keys
  • Access Tokens

inside:

  • Dockerfile
  • Git Repository
  • Source Code

Use Kubernetes Secrets or an external secrets manager.


Volume

Containers are temporary.

Store reports using Persistent Volumes.

Playwright

↓

Report

↓

Persistent Volume

↓

Accessible Later

Auto Scaling

Example

2 Pods

↓

10 Pods

↓

20 Pods

↓

Back to 2

Kubernetes can scale based on resource usage or custom metrics.


CI/CD Flow

Developer

↓

Git Push

↓

GitHub Actions

↓

Build Docker Image

↓

Push Image

↓

Deploy Kubernetes

↓

Run Smoke Tests

↓

Run Regression

↓

Publish Report

↓

Notify Team

Enterprise Architecture

Developer

        │

        ▼

GitHub Repository

        │

        ▼

GitHub Actions

        │

        ▼

Docker Build

        │

        ▼

Container Registry

        │

        ▼

Kubernetes Cluster

        │

        ▼

Playwright Pods

        │

        ▼

Automation Execution

        │

        ▼

Reports

        │

        ▼

Slack / Email Notification

Docker Best Practices

  • Use the official Playwright Docker image.
  • Use npm ci instead of npm install in CI.
  • Keep images as small as possible.
  • Use .dockerignore.
  • Don’t store secrets in images.
  • Mount reports as volumes.
  • Pin image versions instead of relying on latest.
  • Run containers as a non-root user when possible.

Kubernetes Best Practices

  • Keep Pods stateless.
  • Use ConfigMaps for configuration.
  • Use Secrets for credentials.
  • Configure readiness and liveness probes when appropriate.
  • Set CPU and memory requests/limits.
  • Store reports outside Pods.
  • Scale horizontally instead of creating oversized Pods.
  • Use namespaces to separate environments such as Dev, QA, and UAT.

Docker vs Kubernetes

DockerKubernetes
Builds and runs containersOrchestrates containers
Runs on a single machineManages clusters
Manual scalingAutomatic scaling
Manual restartSelf-healing
Simple deploymentEnterprise deployment
Good for local developmentBest for production environments

Common Interview Questions

1. Why use Docker with Playwright?

Answer:
Docker provides a consistent execution environment across local machines and CI/CD systems, eliminating dependency and browser version differences.


2. Why use the official Playwright Docker image?

Answer:
It already contains compatible versions of Node.js, Playwright, browsers, and required Linux dependencies, reducing setup effort and compatibility issues.


3. What is the difference between a Docker image and a container?

Answer:
A Docker image is an immutable blueprint containing the application and its dependencies. A container is a running instance of that image.


4. Why use Kubernetes for Playwright?

Answer:
Kubernetes automates deployment, scaling, recovery, and management of Playwright containers, making it suitable for large-scale parallel test execution.


5. What is a Pod?

Answer:
A Pod is the smallest deployable unit in Kubernetes. It contains one or more containers that share networking and storage resources.


6. How do you securely manage credentials in Kubernetes?

Answer:
Use Kubernetes Secrets (or an enterprise secrets manager) and inject them into Pods as environment variables or mounted files instead of storing them in source code or Docker images.


7. How would you execute 5,000 Playwright tests quickly?

Answer:
Split tests into logical suites, run them in parallel across multiple Playwright workers and Kubernetes Pods, reuse authenticated sessions with storageState, use API-based test data setup where possible, and collect reports from shared storage.


8. What challenges have you seen when running Playwright in containers?

Answer:
Common challenges include browser resource consumption, report persistence, secure secret management, parallel test data collisions, and ensuring enough CPU and memory for stable execution. These are addressed through proper container configuration, persistent storage, isolated test data, and Kubernetes resource management.

SOLID Principles with Playwright Examples (TypeScript)

Introduction

SOLID is a set of five object-oriented design principles introduced by Robert C. Martin (Uncle Bob). These principles help developers build software that is:

  • Easy to maintain
  • Easy to extend
  • Highly reusable
  • Loosely coupled
  • Easy to test

In enterprise Playwright frameworks, following SOLID principles results in cleaner Page Objects, reusable utilities, scalable workflows, and better test automation architecture.


Why SOLID is Important in Automation Frameworks

Without SOLID principles, frameworks often become:

  • Huge Page Objects (1000+ lines)
  • Duplicate code
  • Difficult to maintain
  • Hard to extend
  • Strongly coupled
  • Fragile when the application changes

With SOLID principles:

  • Classes have clear responsibilities
  • New features require minimal changes
  • Code becomes reusable
  • Frameworks scale efficiently

What does SOLID stand for?

PrincipleFull Form
SSingle Responsibility Principle
OOpen Closed Principle
LLiskov Substitution Principle
IInterface Segregation Principle
DDependency Inversion Principle

S — Single Responsibility Principle (SRP)

Definition

A class should have only one reason to change.

Each class should have one responsibility.


Bad Example

A LoginPage doing everything.

class LoginPage {

    login() {}

    logout() {}

    readExcel() {}

    generateRandomUser() {}

    takeScreenshot() {}

    sendEmail() {}

}

Problems

  • Too many responsibilities
  • Difficult maintenance
  • Hard to reuse
  • Large file

Good Example

Separate responsibilities.

LoginPage

↓

Login only
ExcelUtility

↓

Read Excel
ScreenshotUtility

↓

Capture Screenshot
Logger

↓

Logging

Each class has a single purpose.


Enterprise Folder Structure

pages/

    LoginPage.ts

utils/

    ExcelUtility.ts

    Logger.ts

    ScreenshotUtility.ts

Benefits

✔ Small classes

✔ Easy maintenance

✔ Better readability

✔ Easier testing


Interview Question

Why is SRP important in Playwright?

Answer

It prevents Page Objects from becoming large and difficult to maintain. By separating responsibilities into page objects, utilities, workflows, and services, the framework becomes cleaner, reusable, and easier to extend.


O — Open Closed Principle (OCP)

Definition

Software entities should be open for extension but closed for modification.

Instead of changing existing code, extend it.


Bad Example

if(browser=="chromium"){

}

else if(browser=="firefox"){

}

else if(browser=="webkit"){

}

Whenever a new browser is added, this code must be modified.


Better Approach

Use the Strategy Pattern.

Browser Strategy

↓

Chromium

Firefox

WebKit

Adding a new browser:

Edge Strategy

No existing code changes.


Playwright Example

Instead of modifying

BrowserLauncher.ts

Create

ChromiumStrategy

FirefoxStrategy

WebKitStrategy

EdgeStrategy

Benefits

✔ Easy extension

✔ No modification

✔ Low risk

✔ Better architecture


Interview Question

Explain OCP using Playwright.

Answer

A browser launcher should support new browsers without changing existing code. Using Strategy Pattern, each browser has its own implementation, allowing new browsers to be added by creating new strategy classes rather than modifying the launcher.


L — Liskov Substitution Principle (LSP)

Definition

A derived class should be replaceable with its base class without breaking the application.


Example

Suppose

BasePage

contains

open()

waitForPage()

verifyTitle()

Now

LoginPage

DashboardPage

CheckoutPage

extend BasePage.

Any of them should work wherever a BasePage is expected.


Good Example

BasePage

↓

LoginPage

↓

DashboardPage

↓

CartPage

Each subclass honors the behavior defined by the base class.


Bad Example

Suppose BasePage defines

openPage()

but CheckoutPage throws an exception because it cannot open itself.

That violates LSP.


Benefits

✔ Better inheritance

✔ Predictable behavior

✔ Easier maintenance


Interview Question

How does LSP help automation?

Answer

It ensures that all page objects derived from a common base behave consistently. Shared framework code can work with any page object without requiring special handling.


I — Interface Segregation Principle (ISP)

Definition

Clients should not be forced to depend on interfaces they don’t use.


Bad Example

interface Utility{

readExcel();

takeScreenshot();

sendEmail();

uploadFile();

downloadFile();

}

Every implementing class must define unnecessary methods.


Better Example

Separate interfaces.

ExcelReader

↓

readExcel()

ScreenshotService

↓

takeScreenshot()

FileUploader

↓

upload()

Benefits

✔ Small interfaces

✔ Easier implementation

✔ Better readability


Interview Question

Why is ISP useful in Playwright?

Answer

It avoids creating large interfaces that force unrelated implementations. Separate interfaces for reporting, screenshots, file handling, and data readers keep the framework modular and easier to maintain.


D — Dependency Inversion Principle (DIP)

Definition

High-level modules should not depend on low-level modules.

Both should depend on abstractions.


Bad Example

class LoginWorkflow{

private login=new LoginPage(page);

}

Strong coupling.


Better Example

Inject dependency.

constructor(private loginPage: LoginPage){

}

Now

LoginWorkflow

doesn’t create LoginPage.

Someone else provides it.


Architecture

Test

↓

Fixture

↓

Workflow

↓

Page Object

Each layer receives dependencies instead of creating them.


Playwright Example

Playwright Fixtures naturally support Dependency Injection.

Instead of

const page=new LoginPage(browserPage);

Fixtures inject

loginPage

directly into the test.


Benefits

✔ Loose coupling

✔ Easy testing

✔ Easy mocking

✔ Better scalability


Interview Question

How does Playwright support Dependency Injection?

Answer

Playwright fixtures inject dependencies such as browser instances, pages, authenticated sessions, and page objects into test functions. This reduces object creation inside tests and promotes loose coupling.


SOLID Applied to a Playwright Framework

                     Test Layer
                         │
                         ▼
                  Workflow Layer
                         │
                         ▼
                 Page Object Layer
                         │
                         ▼
                 Utility/Service Layer
                         │
                         ▼
                Playwright Framework
                         │
                         ▼
                     Browser

Each layer follows a specific responsibility.


Before SOLID

LoginPage

1000 Lines

↓

Login

Logout

Excel

JSON

API

Logger

Screenshot

Database

Email

Random Data

Very difficult to maintain.


After SOLID

LoginPage

↓

Login Only
Logger

↓

Logging Only
API Client

↓

API Only
Excel Utility

↓

Excel Only
Workflow

↓

Business Process

Clean architecture.


SOLID + Design Patterns

SOLID PrincipleDesign Pattern
SRPPage Object Model
OCPStrategy Pattern
LSPBase Page Inheritance
ISPSmall Interfaces
DIPFixtures + Dependency Injection

Real Enterprise Example

Suppose you’re automating an e-commerce application.

Without SOLID

CheckoutPage

↓

Login

↓

Search

↓

Add Product

↓

Payment

↓

Database

↓

Email

↓

Report

↓

Screenshot

One class controls everything.


With SOLID

CheckoutWorkflow

↓

LoginPage

↓

ProductPage

↓

CartPage

↓

PaymentPage

↓

OrderPage

Utilities

Logger

API

Screenshot

Excel

JSON

Random Data

Every class has one responsibility.


Enterprise Benefits

Following SOLID results in:

  • Smaller Page Objects
  • Better readability
  • Easier debugging
  • Cleaner architecture
  • Reusable code
  • Easier onboarding for new team members
  • Better unit and integration testing
  • Faster feature development
  • Simpler code reviews

Common SOLID Mistakes in Playwright

❌ Putting business workflows inside page objects

Move business flows to a separate Workflow (Facade) layer.


❌ Creating one huge Utility class

Split it into focused utilities:

  • Logger
  • DateUtility
  • JsonUtility
  • ExcelUtility
  • ScreenshotUtility

❌ Hardcoding object creation

Avoid:

const loginPage = new LoginPage(page);

Prefer dependency injection through Playwright fixtures or a factory.


❌ Large BasePage classes

Keep BasePage limited to truly common functionality such as navigation, waiting, or shared helpers. Don’t force unrelated pages to inherit unnecessary behavior.


❌ Large interfaces

Create small, purpose-specific interfaces rather than one interface containing dozens of unrelated methods.


Senior Playwright Interview Questions

1. What are SOLID principles?

Answer

SOLID is a set of five object-oriented design principles that improve maintainability, extensibility, reusability, and scalability. They help reduce coupling and encourage clean architecture.


2. Which SOLID principle is most important in automation?

Answer

All five are valuable, but Single Responsibility Principle (SRP) is often the most impactful because it prevents oversized Page Objects and encourages separation of concerns across pages, workflows, utilities, and services.


3. How does Playwright support Dependency Inversion?

Answer

Playwright fixtures provide dependency injection by supplying browser instances, contexts, pages, and custom page objects to tests. Tests depend on abstractions provided by fixtures instead of creating concrete objects themselves.


4. How do SOLID principles improve a Playwright framework?

Answer

They make the framework modular, reusable, easier to extend, and simpler to maintain. New functionality can often be added by introducing new classes rather than modifying existing ones, reducing the risk of breaking stable automation.


5. How do SOLID principles relate to design patterns?

Answer

Design patterns are practical implementations of SOLID ideas. For example:

  • SRP → Page Object Model, Workflow layer
  • OCP → Strategy Pattern
  • LSP → Base Page inheritance
  • ISP → Focused interfaces
  • DIP → Fixtures and Dependency Injection

Using SOLID together with patterns like Factory, Builder, Strategy, and Facade results in an enterprise-grade Playwright framework that is easier to scale and maintain over time.

Advanced Playwright Design Patterns (Factory, Builder, Strategy)

As Playwright automation frameworks grow, applying design patterns helps improve maintainability, scalability, reusability, and test readability. These patterns are commonly discussed in interviews for Senior SDET, Automation Architect, and QA Lead roles.

Why Use Design Patterns?

Without design patterns, automation frameworks often suffer from:

  • Duplicate code
  • Tight coupling
  • Difficult maintenance
  • Large Page Objects
  • Hardcoded logic
  • Poor scalability

Using design patterns helps create frameworks that are easier to extend and maintain.


1. Factory Pattern

What is Factory Pattern?

The Factory Pattern centralizes object creation instead of allowing tests to instantiate classes directly.

Instead of:

const loginPage = new LoginPage(page);
const dashboardPage = new DashboardPage(page);
const cartPage = new CartPage(page);

Create objects through a factory.


Why Use Factory Pattern?

Benefits

  • Centralized object creation
  • Easier maintenance
  • Supports Dependency Injection
  • Simplifies test code
  • Reduces duplicate initialization

Architecture

               Test

                │

                ▼

          Page Factory

        ┌──────┼──────┐

        ▼      ▼      ▼

   LoginPage Dashboard CartPage

Example Implementation

LoginPage

import { Page } from '@playwright/test';

export class LoginPage {

    constructor(private readonly page: Page) {}

    async login(username: string, password: string) {
        // Login steps
    }

}

DashboardPage

import { Page } from '@playwright/test';

export class DashboardPage {

    constructor(private readonly page: Page) {}

    async verifyDashboard() {
        // Verification logic
    }

}

PageFactory

import { Page } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
import { DashboardPage } from '../pages/DashboardPage';

export class PageFactory {

    constructor(private readonly page: Page) {}

    get loginPage() {
        return new LoginPage(this.page);
    }

    get dashboardPage() {
        return new DashboardPage(this.page);
    }

}

Usage

const factory = new PageFactory(page);

await factory.loginPage.login(username, password);

await factory.dashboardPage.verifyDashboard();

Advantages

✔ Cleaner tests

✔ Centralized object creation

✔ Easy maintenance

✔ Supports Dependency Injection

✔ Easily extendable


Disadvantages

  • Slightly more abstraction
  • May be unnecessary for very small projects

Factory Pattern Interview Questions

Q1. Why use the Factory Pattern?

Answer

To centralize object creation, reduce duplicate initialization, improve maintainability, and simplify test code.


Q2. When should you avoid the Factory Pattern?

Answer

For very small frameworks with only a few page objects, a factory may add unnecessary complexity.


2. Builder Pattern

What is Builder Pattern?

The Builder Pattern creates complex objects step by step.

Instead of creating long constructors:

const user = {

    username: "admin",

    password: "pass",

    role: "Manager",

    department: "QA",

    active: true

};

Use a builder.


Why Use Builder Pattern?

Benefits

  • Readable object creation
  • Optional fields
  • Fluent API
  • Easier maintenance
  • Less constructor complexity

Example Architecture

             User Builder

                    │

                    ▼

             Build User Object

                    │

                    ▼

              Test Uses Object

Example

User Model

export interface User {

    username: string;

    password: string;

    role: string;

    department: string;

}

Builder

export class UserBuilder {

    private user = {

        username: "",

        password: "",

        role: "",

        department: ""

    };

    withUsername(username: string) {

        this.user.username = username;

        return this;

    }

    withPassword(password: string) {

        this.user.password = password;

        return this;

    }

    withRole(role: string) {

        this.user.role = role;

        return this;

    }

    withDepartment(department: string) {

        this.user.department = department;

        return this;

    }

    build() {

        return this.user;

    }

}

Usage

const user = new UserBuilder()

    .withUsername("admin")

    .withPassword("admin123")

    .withRole("Manager")

    .withDepartment("QA")

    .build();

Benefits

  • Fluent syntax
  • Easy to read
  • Easy to extend
  • Avoids large constructors
  • Great for test data creation

Real Playwright Use Cases

Builder Pattern is useful for creating:

  • Test users
  • Customer objects
  • Orders
  • Payment requests
  • API payloads
  • Product data
  • Registration forms

Builder Pattern Interview Questions

Q1. Why use Builder instead of constructors?

Answer

Builders improve readability, support optional fields, and prevent constructors with many parameters that are difficult to understand and maintain.


Q2. Where is Builder commonly used in automation?

Answer

Creating complex test data, API payloads, registration forms, and domain objects used across tests.


3. Strategy Pattern

What is Strategy Pattern?

The Strategy Pattern allows you to switch algorithms or behaviors at runtime without changing the client code.

Instead of writing:

if(browser === "chrome") {

}

else if(browser === "firefox") {

}

else if(browser === "webkit") {

}

Move each behavior into its own strategy.


Why Use Strategy Pattern?

Benefits

  • Easy to add new behavior
  • No large if-else chains
  • Better maintainability
  • Open for extension
  • Easier unit testing

Architecture

             Test

              │

              ▼

      Browser Strategy

       ┌─────┼─────┐

       ▼     ▼     ▼

 Chrome Firefox WebKit

Example

Interface

export interface BrowserStrategy {

    launch(): Promise<void>;

}

Chrome Strategy

export class ChromiumStrategy implements BrowserStrategy {

    async launch() {

        console.log("Launch Chromium");

    }

}

Firefox Strategy

export class FirefoxStrategy implements BrowserStrategy {

    async launch() {

        console.log("Launch Firefox");

    }

}

Context

export class BrowserLauncher {

    constructor(private strategy: BrowserStrategy) {}

    async start() {

        await this.strategy.launch();

    }

}

Usage

const launcher = new BrowserLauncher(

    new ChromiumStrategy()

);

await launcher.start();

Playwright Use Cases

Strategy Pattern is useful for:

  • Browser selection
  • Authentication methods
  • Environment-specific behavior
  • Payment gateway flows
  • Report generation
  • File upload mechanisms
  • Different login types (UI, API, SSO)

Authentication Example

               Login

                 │

        ┌────────┼────────┐

        ▼        ▼        ▼

     UI Login  API Login  SSO Login

The test selects the appropriate authentication strategy without changing its own logic.


Report Generation Example

Report Strategy

      │

┌─────┼──────┐

▼     ▼      ▼

HTML Allure JUnit

Advantages of Strategy Pattern

✔ Removes large conditional statements

✔ Supports Open/Closed Principle

✔ Easy to extend

✔ Highly testable

✔ Easy maintenance


Factory vs Builder vs Strategy

FeatureFactoryBuilderStrategy
Main PurposeCreate objectsConstruct complex objectsChange behavior dynamically
FocusObject creationObject configurationAlgorithm/behavior selection
ReturnsReady-to-use objectsConfigured objectSelected implementation
Typical Playwright UsePage Objects, API clientsTest data, payloadsBrowser, authentication, reporting
Supports ExtensibilityYesYesExcellent

Combining Patterns in a Playwright Framework

Enterprise frameworks often combine multiple patterns:

                   Test
                     │
                     ▼
               Workflow Layer
                     │
                     ▼
               Page Factory
                     │
        ┌────────────┼────────────┐
        ▼            ▼            ▼
   LoginPage   ProductPage   CartPage
                     │
                     ▼
              Builder Objects
                     │
                     ▼
             Test Data Objects
                     │
                     ▼
             Strategy Selection
        ┌────────────┼────────────┐
        ▼            ▼            ▼
    Browser      Authentication   Reporting

Real-World Example

Imagine an e-commerce application:

  1. Factory Pattern
    • Creates LoginPage, CartPage, CheckoutPage, and OrderPage.
  2. Builder Pattern
    • Creates customer profiles, shipping addresses, payment requests, and order payloads.
  3. Strategy Pattern
    • Chooses:
      • Browser (Chromium, Firefox, WebKit)
      • Login method (UI, API, SSO)
      • Payment method (Credit Card, PayPal, UPI)
      • Report type (HTML, Allure)

Together, these patterns produce a framework that is easier to maintain, easier to extend, and capable of supporting large-scale automation projects with minimal changes to existing code.


Senior SDET Interview Questions

1. Which design patterns have you used in your Playwright framework?

Answer:
I commonly use the Page Object Model, Factory Pattern for page object creation, Builder Pattern for test data and API payloads, Strategy Pattern for browser and authentication selection, Facade/Workflow Pattern for business processes, and Dependency Injection through Playwright fixtures.


2. Which design pattern is most useful in automation frameworks?

Answer:
There isn’t a single best pattern. Page Object Model is foundational, Factory simplifies object creation, Builder improves test data management, Strategy removes conditional logic, and Workflow (Facade) keeps business flows reusable. The best choice depends on the problem being solved.


3. How do these patterns improve maintainability?

Answer:
They separate responsibilities, reduce code duplication, isolate changes, improve readability, and make it easier to extend the framework without modifying existing test code. This aligns with SOLID principles and results in a more scalable automation architecture.

Real-World Enterprise Playwright Framework Implementation

In this section, we’ll build a production-ready Playwright automation framework and explain how each folder contributes to the overall architecture. This is the type of framework commonly used in enterprise applications and discussed in senior SDET interviews.

Step 1: Enterprise Framework Folder Structure

Playwright-Framework
│
├── .github/
│     └── workflows/
│            playwright.yml
│
├── pages/
│     LoginPage.ts
│     DashboardPage.ts
│     ProductPage.ts
│     CartPage.ts
│     CheckoutPage.ts
│
├── workflows/
│     LoginWorkflow.ts
│     CheckoutWorkflow.ts
│
├── fixtures/
│     baseFixture.ts
│     loginFixture.ts
│
├── utils/
│     Logger.ts
│     WaitUtility.ts
│     JsonUtility.ts
│     RandomData.ts
│     ScreenshotUtility.ts
│     Environment.ts
│
├── api/
│     CustomerAPI.ts
│     OrderAPI.ts
│
├── test-data/
│     login.json
│     checkout.json
│     products.json
│
├── constants/
│     URL.ts
│     Messages.ts
│     Timeout.ts
│
├── tests/
│     login.spec.ts
│     checkout.spec.ts
│     orders.spec.ts
│
├── reports/
├── screenshots/
├── traces/
├── videos/
│
├── playwright.config.ts
├── global-setup.ts
├── global-teardown.ts
├── package.json
└── README.md

Step 2: Responsibilities of Each Folder

pages/

Contains only page-related logic.

Example:

LoginPage

DashboardPage

CheckoutPage

PaymentPage

A page object should:

  • Store page locators
  • Expose page actions
  • Optionally expose page-specific validations

A page object should not:

  • Read Excel files
  • Generate random data
  • Call unrelated APIs
  • Contain business workflows spanning multiple pages

workflows/

Many beginners place all business logic inside page objects.

Instead, create workflow classes.

Example:

Login Workflow

↓

Open Login Page

↓

Enter Username

↓

Enter Password

↓

Click Login

↓

Verify Dashboard

This keeps page objects small and reusable.

Examples:

LoginWorkflow

CheckoutWorkflow

OrderWorkflow

PaymentWorkflow

fixtures/

Provides reusable setup.

Examples:

Browser Fixture

Login Fixture

API Fixture

Database Fixture

Avoid creating browser instances manually in every test.


utils/

Contains reusable helper classes.

Examples:

Date Utility

Random Data

Logger

Encryption

Screenshot Utility

Download Utility

Upload Utility

PDF Utility

Utilities should remain generic and independent of specific pages.


api/

Store API helper classes separately from UI automation.

Example:

Customer API

Order API

Product API

Payment API

This separation allows UI and API automation to evolve independently.


constants/

Avoid hardcoding values.

Examples:

Application URL

Messages

Timeout

Roles

Endpoints

test-data/

Contains:

JSON

CSV

Excel

YAML

XML

Avoid storing test data inside test files.


Step 3: Workflow Layer

Enterprise frameworks often include a workflow (or business layer).

Architecture:

Test

↓

Workflow

↓

Page Objects

↓

Playwright

Example

Instead of

Test

↓

Login Page

↓

Dashboard Page

↓

Cart Page

↓

Checkout Page

Use

Test

↓

Checkout Workflow

↓

All Page Objects

Benefits:

  • Cleaner tests
  • Less duplication
  • Easier maintenance

Step 4: Layered Architecture

                    Tests
                      │
                      ▼
              Business Workflows
                      │
                      ▼
                Page Objects
                      │
                      ▼
                  Utilities
                      │
                      ▼
              Playwright API
                      │
                      ▼
                  Browser
                      │
                      ▼
               Web Application

Each layer has a single responsibility.


Step 5: Login Workflow

Instead of repeating login steps in multiple tests:

Open Login

↓

Enter Username

↓

Enter Password

↓

Click Login

↓

Verify Dashboard

Create a reusable login workflow.

Advantages:

  • Centralized login logic
  • Easy updates
  • Cleaner test cases

Step 6: Checkout Workflow

A checkout workflow might include:

Login

↓

Search Product

↓

Open Product

↓

Add to Cart

↓

Checkout

↓

Payment

↓

Order Confirmation

This represents one business process composed of multiple page objects.


Step 7: API + UI Integration

Many enterprise projects create data through APIs before validating it in the UI.

Example:

API

Create Customer

↓

API

Create Product

↓

API

Generate Order

↓

UI

Search Order

↓

Verify Status

Advantages:

  • Faster setup
  • Less UI dependency
  • More stable tests

Step 8: Data Cleanup Strategy

Automation should avoid leaving unnecessary test data behind.

Typical cleanup:

Create User

↓

Execute Test

↓

Delete User

Or

Create Order

↓

Execute Test

↓

Cancel/Delete Order

Cleanup can be handled:

  • After each test
  • After all tests
  • Through scheduled database jobs (depending on the environment)

Step 9: Reusable Components

Good frameworks maximize reuse.

Reusable examples:

Login

Logout

Navigation

Calendar Selection

Dropdown Selection

Table Reader

File Upload

File Download

Avoid copying the same logic into multiple page objects.


Step 10: Configuration Strategy

Separate configurations by environment.

Example:

Development

↓

QA

↓

UAT

↓

Production

Each environment should define:

  • Base URL
  • API URL
  • Credentials (prefer secure secrets management)
  • Timeouts
  • Feature flags (if applicable)

Step 11: Secure Credential Management

Never commit credentials to source control.

Use:

  • Environment variables
  • Secret managers
  • CI/CD secrets
  • Vault solutions (for enterprise environments)

Avoid:

admin

password123

inside source files.


Step 11: Logging Architecture

Recommended logging flow:

Test Starts

↓

Log Browser Launch

↓

Log Navigation

↓

Log User Actions

↓

Log Validations

↓

Log Result

↓

Log Browser Close

Keep logs informative but concise.


Step 12: Screenshot Strategy

Capture screenshots:

  • On failure
  • Before destructive actions (optional)
  • During debugging (optional)

Avoid capturing screenshots after every step in normal execution.


Step 13: Trace Strategy

Capture traces when:

  • A test fails
  • Debugging intermittent failures
  • Investigating complex synchronization issues

Trace Viewer provides:

  • Timeline
  • DOM snapshots
  • Network activity
  • Console messages
  • User actions

Step 14: Parallel Testing Strategy

Example:

Worker 1

Authentication

--------------------

Worker 2

Orders

--------------------

Worker 3

Payments

--------------------

Worker 4

Reports

Ensure:

  • No shared state
  • Independent test data
  • Separate browser contexts

Step 15: Cross-Browser Strategy

Recommended execution:

Chromium

↓

Firefox

↓

WebKit

Run smoke tests on all browsers and reserve full regression for the browsers required by your project.


Step 16: Continuous Integration Flow

Developer Commit

↓

Pull Request

↓

Code Review

↓

Build

↓

Install Dependencies

↓

Install Browsers

↓

Run Lint

↓

Run Unit Tests (if applicable)

↓

Run Smoke Automation

↓

Run Regression

↓

Generate Report

↓

Publish Artifacts

↓

Notify Team

Step 17: Pull Request Checklist

Before creating a PR:

  • Code builds successfully
  • All tests pass
  • ESLint passes
  • Prettier formatting applied
  • No hardcoded values
  • No static waits
  • No duplicate methods
  • Meaningful commit messages
  • Updated documentation (if required)

Step 18: Versioning Strategy

Example:

Version 1.0

↓

Version 1.1

↓

Version 1.2

↓

Version 2.0

Tag framework releases to simplify rollback and traceability.


Step19: Recommended NPM Scripts

Typical scripts include:

test

test:smoke

test:regression

test:headed

test:chrome

test:firefox

test:webkit

report

lint

format

These provide a consistent way to execute different suites.


Step 20: Enterprise Coding Guidelines

Follow these principles:

Single Responsibility Principle

Each class should have one responsibility.


Open/Closed Principle

Design classes so they can be extended without modifying existing behavior wherever practical.


DRY (Don’t Repeat Yourself)

Move repeated logic into reusable methods or workflows.


KISS (Keep It Simple, Stupid)

Prefer simple, readable solutions over unnecessary complexity.


YAGNI (You Aren’t Gonna Need It)

Don’t implement features before they are actually required.


Step 21: Enterprise Framework Maturity Model

Beginner Framework

  • Tests
  • Page Objects

Intermediate Framework

  • Fixtures
  • Utilities
  • Reporting
  • Environment support

Advanced Framework

  • Business workflows
  • API integration
  • Parallel execution
  • CI/CD
  • Authentication reuse
  • Robust logging
  • Cross-browser support

Enterprise Framework

  • Scalable architecture
  • Secure configuration management
  • API + UI hybrid testing
  • Containerized execution
  • Cloud execution
  • Comprehensive reporting
  • Test analytics
  • Quality gates in CI/CD

Senior Playwright Interview Questions & Answers

1. Why would you introduce a Workflow Layer?

Answer:

A workflow layer encapsulates complete business processes that span multiple pages. This keeps page objects focused on page interactions while making test cases shorter, more readable, and easier to maintain.


2. What is the difference between a Page Object and a Workflow?

Answer:

A Page Object models a single page by exposing its locators and actions.

A Workflow coordinates multiple page objects to accomplish a business process such as placing an order or completing user registration.


3. Why shouldn’t business logic be placed inside page objects?

Answer:

Business workflows often involve multiple pages. Keeping them in page objects creates oversized classes, increases coupling, and makes reuse difficult. Separating workflows improves maintainability and follows the Single Responsibility Principle.


4. How do you organize a framework for thousands of test cases?

Answer:

I organize it into layers (tests, workflows, page objects, utilities, API helpers, fixtures), group tests by feature, externalize configuration and test data, enable parallel execution, use authentication reuse, and integrate reporting and CI/CD.


5. How do you reduce execution time in Playwright?

Answer:

  • Execute tests in parallel.
  • Reuse authenticated sessions with storageState.
  • Create test data through APIs instead of the UI where appropriate.
  • Categorize suites into smoke and regression.
  • Avoid unnecessary browser launches and redundant setup.
  • Remove fixed waits.

6. How do you handle flaky tests?

Answer:

I investigate the root cause rather than relying on retries. Common improvements include using stable locators, waiting on application state instead of time, isolating test data, improving cleanup, and reviewing application synchronization issues.


7. What qualities define a production-ready Playwright framework?

Answer:

A production-ready framework has a clean layered architecture, reusable fixtures, focused page objects, workflow abstraction, secure configuration management, reliable reporting, logging, authentication reuse, CI/CD integration, parallel execution, cross-browser support, coding standards, and comprehensive

Playwright Automation Project for Beginners (Step-by-Step Guide)

This guide explains how to create a production-ready Playwright Automation Framework using TypeScript while following industry standards. It also includes best practices, framework standards, folder structure, and interview questions.

Table of Contents

  1. Introduction to Playwright
  2. Prerequisites
  3. Install Playwright
  4. Create Project Structure
  5. Configure Playwright
  6. Create Test Data
  7. Create Page Objects
  8. Create Utility Classes
  9. Create Base Framework
  10. Write Test Cases
  11. Execute Tests
  12. Generate Reports
  13. Logging
  14. Screenshots & Videos
  15. CI/CD Integration
  16. Framework Standards
  17. Coding Standards
  18. Common Mistakes
  19. Automation Project Interview Questions

Step 1: Understand Playwright

Playwright is Microsoft’s modern end-to-end automation framework that supports:

  • Chromium
  • Firefox
  • WebKit
  • Mobile Browsers

Supports

  • TypeScript
  • JavaScript
  • Python
  • Java
  • .NET

Step 2: Install Node.js

Verify installation

node -v

npm -v

Step 3: Create Project

mkdir PlaywrightFramework

cd PlaywrightFramework

npm init -y

Step 4: Install Playwright

npm init playwright@latest

Choose

TypeScript

tests folder

GitHub Action → Yes

Install Browsers → Yes

Step 5: Project Folder Structure

A recommended enterprise structure:

PlaywrightFramework
│
├── tests/
│     Login.spec.ts
│     Dashboard.spec.ts
│
├── pages/
│     LoginPage.ts
│     DashboardPage.ts
│
├── fixtures/
│     baseFixture.ts
│
├── utils/
│     Logger.ts
│     ExcelReader.ts
│     JSONReader.ts
│     Screenshot.ts
│     WaitHelper.ts
│
├── test-data/
│     login.json
│
├── locators/
│     LoginLocator.ts
│
├── constants/
│     URL.ts
│
├── reports/
│
├── screenshots/
│
├── videos/
│
├── traces/
│
├── global-setup.ts
│
├── global-teardown.ts
│
├── playwright.config.ts
│
├── package.json
│
└── README.md

Step 6: Configure Playwright

Example:

import { defineConfig } from '@playwright/test';

export default defineConfig({

  testDir: './tests',

  timeout: 60000,

  retries: 1,

  reporter: [
    ['html'],
    ['list']
  ],

  use: {

    browserName: 'chromium',

    headless: false,

    screenshot: 'only-on-failure',

    video: 'retain-on-failure',

    trace: 'retain-on-failure'
  }
});

Step 7: Create Test Data

Instead of hardcoding

❌ Bad

page.fill("#username","admin");

Use JSON

{
 "username":"admin",
 "password":"admin123"
}

Advantages

  • Easy maintenance
  • Reusable
  • Supports multiple environments

Step 8: Create Page Object Model

Example

pages/

LoginPage.ts

Methods

login()

enterUsername()

enterPassword()

clickLogin()

verifyLogin()

Each page should contain only methods related to that page.


Step 9: Create Locator Files

Instead of

page.locator("#username")

Create

LoginLocator.ts
username

password

loginButton

Benefits

  • Centralized maintenance
  • Easy updates

Step 10: Create Utility Classes

Common reusable methods:

WaitHelper

DateUtil

RandomGenerator

Logger

Screenshot

ExcelReader

JSONReader

APIHelper

EnvironmentReader

FileUpload

FileDownload

Never duplicate code.


Step 11: Create Base Fixture

Create

fixtures/baseFixture.ts

Purpose

  • Launch Browser
  • Login once
  • Common setup
  • Common teardown
  • Reusable objects

Step 12: Write Test Cases

Example flow

Launch Application

Login

Navigate

Perform Action

Validate

Logout

Every test should be independent.


Step 13: Assertions

Always validate

Example

URL

Title

Text

Visibility

Enabled

Disabled

Count

Attribute

CSS

Without assertions, automation has limited value.


Step 14: Reporting

Supported reports

  • HTML Report
  • Allure Report
  • JSON Report
  • JUnit Report

Generate

npx playwright show-report

Step 15: Screenshots

Capture

  • On Failure
  • Before Action (optional)
  • After Action (optional)

Never capture every step unless debugging.


Step 16: Videos

Retain only failed videos.

video:'retain-on-failure'

Step 17: Trace Viewer

Enable

trace:'retain-on-failure'

Open

npx playwright show-trace trace.zip

Step 18: Logging

Recommended

INFO

DEBUG

WARN

ERROR

Example

Launching Browser

Opening Login Page

Entering Username

Click Login

Dashboard Loaded

Step 19: Environment Files

Use

.env

.env.dev

.env.qa

.env.uat

.env.prod

Never hardcode

  • URLs
  • Credentials
  • Tokens

Step 20: Multiple Environments

QA

UAT

DEV

PROD

Read dynamically using environment variables.


Step 21: Test Data Standards

Keep separate

Positive Data

Negative Data

Boundary Data

Invalid Data

Step 22: Naming Standards

Test Files

Login.spec.ts

Dashboard.spec.ts

Order.spec.ts

Pages

LoginPage

DashboardPage

CartPage

Methods

login()

logout()

searchProduct()

addToCart()

Variables

Good

userName

password

searchText

Avoid

a

b

temp

Step 23: Framework Standards

1. Use Page Object Model

Never write locators directly inside tests.


2. Separate Test Data

Never hardcode values.


3. Use Fixtures

Avoid duplicate setup.


4. Keep Tests Independent

Tests should not depend on execution order.


5. Follow DRY Principle

Don’t Repeat Yourself.


6. Use Explicit Assertions

Validate expected outcomes.


7. Handle Waits Properly

Prefer Playwright’s auto-waiting and explicit expectations. Avoid unnecessary fixed waits (waitForTimeout).


8. Capture Evidence

  • Screenshots
  • Videos
  • Traces

9. Logging

Every important action should be logged.


10. Maintain Readability

Readable code is easier to review and maintain.


Coding Standards

Use Meaningful Test Names

Good

Verify successful login with valid credentials

Bad

Test1

One Assertion Purpose Per Test

Each test should validate one business scenario.


Reuse Components

Avoid duplicate code.


Small Methods

Avoid methods larger than 50–100 lines. Break complex logic into reusable functions.


Remove Dead Code

Delete unused methods and variables.


Git Standards

Commit frequently.

Example

Added Login Page

Implemented Dashboard Page

Added API Utility

Fixed Login Bug

Avoid

Final

Latest

Update

Branch Standards

main

develop

feature/login

feature/cart

bugfix/login

release/v1.2

Folder Standards

Separate

Pages

Tests

Utilities

Fixtures

Reports

Screenshots

Locators

Data

Never mix them.


Reporting Standards

Store

HTML

JSON

JUnit

Allure

Archive reports for CI builds.


CI/CD Standards

Run

  • Smoke Suite
  • Regression Suite
  • Parallel Execution
  • Cross Browser
  • Upload Reports
  • Publish Artifacts

Common Mistakes

❌ Hardcoding credentials

❌ Duplicate locators

❌ Duplicate methods

❌ Static waits

❌ Very long test methods

❌ Dependent tests

❌ No assertions

❌ No logging

❌ Ignoring failed screenshots

❌ Large Page Object classes containing unrelated functionality


Sample Automation Flow

Test

↓

Fixture

↓

Page Object

↓

Locator

↓

Utility

↓

Playwright API

↓

Browser

↓

Application

↓

Assertions

↓

Report

Playwright Automation Framework Interview Questions & Answers

1. Why do you use the Page Object Model?

Answer:
POM separates test logic from page interaction logic, making the framework easier to maintain, reusable, and scalable. Changes to page locators are usually made in one place instead of every test.


2. Why do you use fixtures?

Answer:
Fixtures manage reusable setup and teardown logic, such as browser creation, authenticated sessions, and test data initialization. They reduce duplication and improve test consistency.


3. Why should locators not be written directly in test files?

Answer:
Keeping locators in page objects or dedicated locator files centralizes maintenance. When the UI changes, updates are required in only one place.


4. Why separate test data from test scripts?

Answer:
External test data (JSON, CSV, Excel, etc.) makes tests reusable, supports multiple datasets, and allows non-developers to update test inputs without changing code.


5. Why avoid waitForTimeout()?

Answer:
Fixed waits slow down test execution and can make tests flaky. Playwright provides automatic waiting and assertion-based waiting that are generally more reliable.


6. What is the purpose of playwright.config.ts?

Answer:
It centralizes framework configuration such as browser settings, retries, reporters, timeouts, projects, base URL, and execution behavior.


7. Why use baseURL in Playwright?

Answer:
Using a baseURL allows tests to navigate with relative paths, making it easier to switch environments without changing test code.


8. How do you execute tests in parallel?

Answer:
Playwright supports parallel execution through workers and projects. Independent tests can run simultaneously to reduce execution time.


9. Why use traces, videos, and screenshots?

Answer:
They provide diagnostic information for failed tests, making it easier to identify the cause of failures without rerunning the tests.


10. How do you handle different environments?

Answer:
Store environment-specific values (such as URLs and credentials) in environment files or configuration, and load the required configuration based on the execution environment.


11. How do you make Playwright tests stable?

Answer:
By using resilient locators, relying on Playwright’s built-in waiting mechanisms, writing independent tests, avoiding fixed delays, and using proper assertions.


12. How do you organize a large Playwright framework?

Answer:
A scalable framework separates responsibilities into folders such as tests, pages, fixtures, utils, test-data, reports, and config, following the Single Responsibility Principle.


13. What is the difference between beforeEach and fixtures?

Answer:
beforeEach is useful for simple per-test setup, while fixtures provide dependency injection, composability, type safety, and reusable setup/teardown across the framework.


14. How do you manage authentication efficiently?

Answer:
Use Playwright’s storageState to save an authenticated session after login and reuse it across tests, avoiding repeated login steps.


15. What standards do you follow while building an automation framework?

Answer:

  • Page Object Model
  • Independent test cases
  • Externalized test data
  • Centralized configuration
  • Reusable fixtures and utilities
  • Meaningful logging
  • Robust reporting
  • Version control best practices
  • CI/CD integration
  • Consistent coding standards
  • Minimal code duplication (DRY)
  • Clear folder structure
  • Proper assertions and error handling

Final Framework Checklist

Before considering your Playwright framework production-ready, ensure it includes:

  • ✅ Well-defined folder structure
  • ✅ Page Object Model
  • ✅ Custom fixtures
  • ✅ External test data
  • ✅ Environment-specific configuration
  • ✅ Reusable utility classes
  • ✅ Centralized configuration
  • ✅ HTML and Allure reporting
  • ✅ Automatic screenshots, videos, and traces on failure
  • ✅ Logging support
  • ✅ Parallel execution
  • ✅ Cross-browser testing
  • ✅ Authentication using storageState
  • ✅ GitHub Actions or other CI/CD integration
  • ✅ Linting and code formatting (ESLint and Prettier)
  • ✅ Meaningful test names and documentation
  • ✅ Stable, independent, and maintainable test cases

Advanced Playwright Automation Framework Standards

The following practices are commonly followed in enterprise-level automation projects to build scalable, maintainable, and reliable Playwright frameworks.

Step 24: Test Design Standards

A good automation framework starts with well-designed test cases.

Follow AAA Pattern

Every test should follow the Arrange → Act → Assert pattern.

Arrange
    ↓
Launch Browser
Load Test Data

Act
    ↓
Perform User Actions

Assert
    ↓
Verify Expected Result

Example Structure

test('Verify user can login successfully', async ({ loginPage }) => {

    // Arrange
    const user = loginData.validUser;

    // Act
    await loginPage.login(user.username, user.password);

    // Assert
    await expect(loginPage.dashboardTitle).toBeVisible();

});

Step 25: Naming Convention Standards

Project Name

playwright-ecommerce-framework

playwright-bank-automation

playwright-insurance-framework

Test File Names

Good

login.spec.ts

checkout.spec.ts

orderHistory.spec.ts

Avoid

abc.spec.ts

test.spec.ts

new.spec.ts

Page Object Names

LoginPage

DashboardPage

CartPage

CheckoutPage

PaymentPage

Utility Class Names

ExcelUtility

JsonUtility

ApiHelper

LoggerUtility

RandomDataGenerator

Constant File Names

URLs.ts

Messages.ts

Timeout.ts

Environment.ts

Step 26: Locator Strategy Standards

Always use stable locators.

Best Locator Priority

1. getByRole()

2. getByLabel()

3. getByPlaceholder()

4. getByText()

5. getByTestId()

6. CSS

7. XPath (last option)

Good Example

page.getByRole('button', { name: 'Login' });

Better Example

page.getByTestId('login-button');

Avoid

//*[@id='content']/div[2]/div[3]/table/tr[4]/td[2]

Long XPath expressions are fragile and difficult to maintain.


Step 27: Wait Strategy

One of the biggest causes of flaky automation is poor synchronization.

Recommended Waiting Order

Auto Waiting

↓

expect()

↓

waitForURL()

↓

waitForLoadState()

↓

waitForResponse()

↓

waitForTimeout() (Avoid)

Good

await expect(page.getByText("Welcome")).toBeVisible();

Better

await page.waitForLoadState("networkidle");

Avoid

await page.waitForTimeout(10000);

Step 28: Assertion Standards

Every test should verify business behavior.

Examples

Verify

  • Title
  • URL
  • Text
  • Visibility
  • Enabled
  • Disabled
  • Checkbox state
  • Dropdown values
  • API response
  • Database values (if applicable)

Good

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

Good

await expect(successMessage).toContainText("Successfully Saved");

Step 29: Test Data Management

Store data separately.

test-data

    qa

        login.json

        orders.json

    uat

        login.json

    prod

        login.json

Never Hardcode

Avoid

await page.fill("#username","admin");

Preferred

loginData.username

Step 30: Environment Configuration

Use .env files.

.env.dev

.env.qa

.env.uat

.env.prod

Example

BASE_URL=

USERNAME=

PASSWORD=

Step 31: Logging Standards

A professional framework logs important events.

Log

Browser Launch

Navigation

Login

Click

Validation

Logout

Browser Close

Sample Log

INFO Browser launched

INFO Login page opened

INFO Username entered

INFO Password entered

INFO Login successful

INFO Dashboard loaded

Step 32: Exception Handling Standards

Instead of allowing tests to fail silently, capture useful information.

Example

Take Screenshot

Save Trace

Log Error

Close Browser

Generate Report

Step 33: Retry Standards

Use retries only for unstable environments.

Example

Retry = 1

or

Retry = 2

Avoid large retry counts because they can hide genuine defects.


Step 34: Screenshot Standards

Capture screenshots

On Failure

Before Critical Action

After Critical Action (if needed)

Naming Example

LoginFailure_20260723.png

CheckoutFailure_20260723.png

Step 35: Video Recording Standards

Recommended

retain-on-failure

Avoid recording every test unless required.


Step 36: Trace Standards

Enable trace collection.

retain-on-failure

Trace contains

  • Network
  • DOM
  • Console
  • Actions
  • Timing

Step 37: Test Tagging Standards

Use tags for easier execution.

Example

test('@smoke Verify Login', async () => {})
test('@regression Verify Checkout', async () => {})
test('@sanity Verify Logout', async () => {})

Execute

Smoke

Regression

Sanity

API

UI

Critical

Step 38: Parallel Execution Standards

Group tests logically.

Example

Authentication

↓

Orders

↓

Payments

↓

Reports

Avoid shared test data between parallel tests.


Step 39: Browser Standards

Execute on

Chromium

Firefox

WebKit

Optionally include

Mobile Chrome

Mobile Safari

Step 40: CI/CD Standards

A professional pipeline should

Checkout Code

↓

Install Dependencies

↓

Install Browsers

↓

Run Lint

↓

Run Smoke Tests

↓

Run Regression Tests

↓

Generate Reports

↓

Publish Artifacts

↓

Notify Team

Step 41: Code Review Checklist

Before raising a Pull Request

  • No hardcoded values
  • No duplicate methods
  • No unused imports
  • No commented code
  • No static waits
  • Meaningful variable names
  • Proper assertions
  • Clear comments only where necessary
  • All tests passing
  • Lint checks passing

Step 42: Folder Responsibility

tests/

Contains only test scenarios.

Never store locators here.


pages/

Contains

  • Methods
  • Actions
  • Assertions (optional)
  • Page-specific locators

utils/

Contains reusable helper classes.

Examples

Date Utility

Excel Reader

Logger

Random Data

API Helper

Encryption Helper

fixtures/

Contains

Setup

Teardown

Shared Browser

Shared Context

Shared Login

test-data/

Contains

JSON

CSV

Excel

XML

YAML

reports/

Contains

HTML

Allure

JUnit

JSON

Step 43: Common Utility Classes

Enterprise frameworks usually include utilities such as:

APIUtility

BrowserUtility

CookieUtility

DateUtility

DownloadUtility

EncryptionUtility

EnvironmentUtility

ExcelUtility

FileUtility

JsonUtility

LoggerUtility

MailUtility

PDFUtility

RandomDataGenerator

RetryUtility

ScreenshotUtility

WaitUtility

WindowUtility

Step 44: Framework Architecture

                 Test Scripts
                      │
                      ▼
              Base Fixture Layer
                      │
                      ▼
               Page Object Layer
                      │
                      ▼
               Utility Layer
                      │
                      ▼
           Playwright Framework API
                      │
                      ▼
                 Browser Engine
                      │
                      ▼
                Application Under Test

Step 45: Automation Lifecycle

Requirement

↓

Understand Business Flow

↓

Prepare Test Cases

↓

Create Test Data

↓

Implement Page Objects

↓

Write Test Scripts

↓

Review Code

↓

Execute Tests

↓

Analyze Failures

↓

Fix Issues

↓

Generate Reports

↓

CI/CD Execution

↓

Maintenance

Enterprise-Level Best Practices

1. Follow the Single Responsibility Principle (SRP)

Each class should have one responsibility.

Good

LoginPage

CartPage

OrderPage

Avoid creating one large page object containing multiple unrelated pages.


2. Keep Page Objects Clean

A page object should contain:

  • Locators
  • User actions
  • Page-specific validations (if your team’s standard allows)

Avoid placing business workflows that span multiple pages inside a single page object.


3. Use Meaningful Method Names

Good

login()

logout()

searchProduct()

applyCoupon()

placeOrder()

Bad

doLogin()

click1()

abc()

method2()

4. Keep Methods Small

Instead of

loginAndNavigateToDashboardAndSearchAndLogout()

Split into

login()

navigateToDashboard()

search()

logout()

5. One Test = One Business Scenario

Good

Verify user can login successfully

Bad

Login

Search

Add Product

Delete Product

Logout

Verify Reports

Verify Settings

6. Independent Test Cases

Every test should

  • Create its own data (or use isolated test data)
  • Clean up after itself if necessary
  • Run successfully regardless of execution order

Avoid dependencies such as “Test B requires Test A to pass.”


In the next section, we’ll cover advanced framework design, including:

Enterprise-level interview questions for 3–8 years of Playwright automation experience

Custom Playwright fixtures with dependency injection

storageState Authentication for login reuse

Multi-user session handling

API + UI hybrid automation

Data-driven and keyword-driven approaches in Playwright

GitHub Actions CI/CD implementation

Advanced Playwright Framework Design (Enterprise Level)

This section covers advanced topics used in real-world automation projects. These concepts are commonly discussed in interviews for 3–8 years of QA Automation Engineer / SDET roles.


Step 46: Custom Fixtures

What are Fixtures?

Fixtures provide reusable setup and teardown logic that can be injected into tests. They help avoid duplicated initialization code and improve test maintainability.

Instead of writing:

Launch Browser

Create Context

Open Page

Login

Run Test

inside every test, you create fixtures once and reuse them.


Enterprise Folder Structure

fixtures/

    baseFixture.ts

    loginFixture.ts

    apiFixture.ts

    databaseFixture.ts

Why Use Fixtures?

Benefits include:

  • Code reuse
  • Cleaner test scripts
  • Dependency injection
  • Centralized setup and teardown
  • Easier maintenance
  • Better scalability

Fixture Flow

Test Starts

        │

        ▼

Fixture Initializes

        │

        ▼

Browser Launches

        │

        ▼

Context Created

        │

        ▼

Page Created

        │

        ▼

Login (Optional)

        │

        ▼

Execute Test

        │

        ▼

Cleanup

        │

        ▼

Browser Closed

Step 47: Base Test Pattern

Most enterprise frameworks extend the default Playwright test object.

Example architecture:

Playwright Test

        │

        ▼

Base Fixture

        │

        ▼

Custom Fixtures

        │

        ▼

Page Objects

        │

        ▼

Test Files

This enables tests to receive page objects directly through fixtures.


Step 48: Authentication Using storageState

One of the most common enterprise optimization techniques is reusing authenticated sessions.

Without storageState

Every test performs:

Launch Browser

↓

Open Login Page

↓

Enter Username

↓

Enter Password

↓

Login

↓

Execute Test

Problems:

  • Slow execution
  • Duplicate login code
  • Increased maintenance
  • More authentication traffic

With storageState

Login once.

Save authentication state.

Reuse it for every test.

Flow:

Global Setup

↓

Login

↓

Save Session

↓

All Tests Reuse Session

Advantages:

  • Faster execution
  • Less duplication
  • Stable authentication
  • Cleaner test code

Step 49: Global Setup

Global setup runs before the test suite begins.

Common tasks:

  • Login
  • Generate authentication state
  • Create test users
  • Seed test data
  • Load environment configuration

Step 50: Global Teardown

Runs after all tests finish.

Typical responsibilities:

  • Delete temporary users
  • Remove uploaded files
  • Archive reports
  • Release resources
  • Clean up test data

Step 51: API + UI Hybrid Automation

Enterprise automation often combines API and UI testing.

Example flow:

API

Create Customer

↓

API

Create Order

↓

UI

Login

↓

Search Order

↓

Verify Details

Benefits:

  • Faster execution
  • Reduced UI dependency
  • Better test reliability
  • Easier data setup

Step 52: Data-Driven Testing

Instead of writing multiple similar tests:

Login Test 1

Login Test 2

Login Test 3

Login Test 4

Create one reusable test that reads multiple datasets.

Data sources can include:

  • JSON
  • CSV
  • Excel
  • Database
  • API

Benefits:

  • Less duplicate code
  • Easier maintenance
  • Better coverage

Step 53: Configuration Management

Separate configuration from business logic.

Example configuration values:

Application URL

Browser

Username

Password

Timeout

Retry Count

API URL

Never hardcode these values inside page objects or tests.


Step 54: Browser Context Management

Understand the hierarchy:

Browser

      │

      ▼

Browser Context

      │

      ▼

Page

Browser

  • Launches the browser engine.

Browser Context

  • Represents an isolated browser session.
  • Has independent cookies, storage, and cache.

Page

  • Represents a browser tab.

This isolation enables multiple users or sessions to be tested simultaneously.


Step 55: Multi-User Testing

Example scenario:

Admin Login

        │

        ▼

Approves Order

        │

        ▼

Customer Login

        │

        ▼

Verifies Approved Order

Use separate browser contexts for each user to keep sessions isolated.


Step 56: Parallel Execution Strategy

Enterprise suites typically organize execution by feature or risk level.

Example:

Worker 1

Authentication Tests

------------------------

Worker 2

Order Tests

------------------------

Worker 3

Payment Tests

------------------------

Worker 4

Reporting Tests

Guidelines:

  • Avoid shared mutable test data.
  • Ensure tests are independent.
  • Clean up created data.

Step 57: Test Categorization

Large frameworks categorize tests for faster execution.

Common categories:

Smoke

Sanity

Regression

Critical

API

UI

Integration

End-to-End

Performance (where applicable)

Benefits:

  • Faster release validation
  • Targeted execution
  • Better CI/CD pipelines

Step 58: Smoke Suite

Purpose:

Verify that the application is stable enough for deeper testing.

Typical checks:

Application Launch

Login

Dashboard

Logout

Basic Navigation

Should complete within minutes.


Step 59: Regression Suite

Purpose:

Verify that new changes have not broken existing functionality.

Includes:

Authentication

Orders

Payments

Reports

Profile

Settings

Typically executed:

  • Nightly
  • Before releases
  • After major changes

Step 60: Test Execution Pipeline

Developer Commit

        │

        ▼

Git Push

        │

        ▼

Pull Request

        │

        ▼

Code Review

        │

        ▼

Build

        │

        ▼

Install Dependencies

        │

        ▼

Execute Smoke Tests

        │

        ▼

Execute Regression Tests

        │

        ▼

Generate Reports

        │

        ▼

Publish Artifacts

        │

        ▼

Notify Team

Step 61: Logging Standards

A useful log should answer:

  • What happened?
  • When did it happen?
  • Which test executed it?
  • Was it successful?
  • If it failed, why?

Example log sequence:

INFO  Browser launched

INFO  Login page opened

INFO  Username entered

INFO  Password entered

INFO  Login successful

INFO  Dashboard verified

INFO  Test passed

Avoid excessive logging of trivial actions.


Step 62: Error Handling

When a test fails:

Capture:

  • Screenshot
  • Video (if enabled)
  • Trace
  • Browser console logs (if helpful)
  • Network logs (for debugging API issues)
  • Error message
  • Stack trace

This significantly reduces debugging time.


Step 63: Framework Scalability

A scalable framework should support:

  • Hundreds or thousands of tests
  • Multiple applications
  • Multiple browsers
  • Multiple environments
  • Multiple user roles
  • Parallel execution
  • CI/CD integration

Without major architectural changes.


Step 64: Maintainability Checklist

A maintainable framework should:

  • Minimize duplicated code
  • Use reusable components
  • Centralize configuration
  • Use clear naming conventions
  • Keep page objects focused
  • Keep utilities generic
  • Use meaningful comments only where needed

Step 65: Enterprise Framework Layers

                 Test Layer
                      │
                      ▼
               Fixture Layer
                      │
                      ▼
             Business Workflow Layer
                      │
                      ▼
             Page Object Layer
                      │
                      ▼
              Utility Layer
                      │
                      ▼
          Playwright Framework Layer
                      │
                      ▼
                Browser Engine
                      │
                      ▼
           Application Under Test

The optional Business Workflow Layer contains reusable business processes (for example, “placeOrder” or “createCustomer”) that span multiple page objects while keeping page objects focused on individual pages.


Step 66: Enterprise Automation Checklist

Before releasing an automation framework, verify:

  • ✅ Clear folder structure
  • ✅ Page Object Model implemented
  • ✅ Custom fixtures
  • ✅ Externalized test data
  • ✅ Environment-specific configuration
  • ✅ Authentication reuse with storageState
  • ✅ Robust logging
  • ✅ HTML and/or Allure reporting
  • ✅ Screenshots on failure
  • ✅ Trace collection on failure
  • ✅ Video retention on failure (optional)
  • ✅ Parallel execution support
  • ✅ Cross-browser execution
  • ✅ API integration where appropriate
  • ✅ Linting (ESLint)
  • ✅ Code formatting (Prettier)
  • ✅ GitHub Actions or other CI/CD integration
  • ✅ Documentation (README.md)
  • ✅ Stable, independent test cases

Advanced Playwright Interview Questions & Answers

1. What is the purpose of custom fixtures in Playwright?

Answer:
Custom fixtures encapsulate reusable setup and teardown logic, provide dependency injection, and reduce duplication. They simplify test code by supplying ready-to-use objects such as authenticated pages or page objects.


2. What is storageState?

Answer:
storageState stores browser authentication information, including cookies and local storage. After logging in once, the saved state can be reused across tests, eliminating repeated login steps and improving execution speed.


3. Why use Browser Context instead of multiple Browser instances?

Answer:
Browser contexts are lightweight, isolated sessions within the same browser process. They consume fewer resources while providing separate cookies, storage, and cache, making them ideal for multi-user testing.


4. What are the advantages of Playwright over Selenium?

Answer:

  • Built-in auto-waiting
  • Native support for Chromium, Firefox, and WebKit
  • Fast parallel execution
  • Built-in tracing, screenshots, and video
  • Network interception
  • Reliable locator APIs
  • Multiple isolated browser contexts
  • Rich TypeScript support

5. How do you make Playwright tests less flaky?

Answer:

  • Use stable locators (getByRole, getByTestId, etc.)
  • Avoid fixed waits
  • Rely on Playwright’s auto-waiting and assertions
  • Keep tests independent
  • Use isolated test data
  • Retry only when appropriate
  • Capture traces and screenshots for debugging

6. What is the difference between a Browser, Browser Context, and Page?

Answer:

  • Browser: The browser engine instance.
  • Browser Context: An isolated browser session with its own cookies and storage.
  • Page: A single browser tab within a context.

7. Why should test cases be independent?

Answer:
Independent tests can run in any order, execute safely in parallel, and are easier to debug because failures are isolated to a single scenario.


8. How would you design a Playwright framework for a large enterprise application?

Answer:
I would use a layered architecture with Page Object Model, custom fixtures, reusable business workflows, externalized test data, environment-based configuration, authentication reuse via storageState, centralized logging and reporting, parallel execution, CI/CD integration, and clear coding standards.

JavaScript String Programs for Practice (Without Solutions)

1. Get the First and Last 2 Characters

Description: Write a JavaScript program to create a new string using the first 2 and last 2 characters of a given string. If the string length is less than 2, return an empty string.

Input: "JavaScript"

Expected Output: "Japt"


2. Find the Length of the Longest String in an Array

Description: Write a JavaScript program to find the length of the longest string from an array of strings.

Input:

["Java", "Programming", "Code"]

Expected Output:

11

3. Repeat the Last Two Characters Four Times

Description: Write a JavaScript program to create a string made of four copies of the last two characters.

Input: "Coding"

Expected Output:

ngngngng

4. Reverse a String if Its Length is a Multiple of 4

Description: Reverse the string only if its length is divisible by 4.

Input: "Code"

Expected Output:

edoC

5. Count Occurrences of a Substring

Description: Count how many times a substring appears inside a string.

Input:

String: "banana"
Substring: "an"

Expected Output:

2

6. Check Whether a Character is a Vowel or Consonant

Description: Determine whether a given alphabet is a vowel or consonant.

Input: "e"

Expected Output:

Vowel

7. Find the Longest and Shortest Word

Description: Find the longest and shortest words in a sentence.

Input:

"I love learning JavaScript"

Expected Output:

Longest: JavaScript
Shortest: I

8. Find the Most Frequently Repeated Character

Description: Find the character with the highest frequency.

Input: "programming"

Expected Output:

g

9. Calculate String Length Without Using length Property

Description: Find the length of a string using loop logic only.

Input: "JavaScript"

Expected Output:

10

10. Replace Every Second Occurrence of a Character with ‘$’

Description: Replace every second occurrence of each repeated character with the $ symbol.

Input: "Programming"

Expected Output:

Prog$am$in$

11. Swap the First and Last Character

Description: Exchange the first and last characters of the string.

Input: "JavaScript"

Expected Output:

tavaScripJ

12. Swap the First and Last Character of Every Word

Description: Exchange the first and last character of each word in a sentence.

Input:

"Online Learning"

Expected Output:

enliOn gearninL

13. Count Vowels in Each Word

Description: Count vowels present in every word and display the result as an object.

Input:

"We are learning JavaScript"

Expected Output:

{
We:1,
are:2,
learning:3,
JavaScript:3
}

14. Repeat Vowels Three Times and Consonants Twice

Description: Repeat every vowel three times and every consonant twice.

Input: "Code"

Expected Output:

CCooodee

15. Check Whether a String is a Palindrome

Description: Check whether the given string reads the same forwards and backwards.

Input: "madam"

Expected Output:

Palindrome

16. Reverse the Entire String

Description: Reverse all characters of the string.

Input: "JavaScript"

Expected Output:

tpircSavaJ

17. Calculate String Length

Description: Find the total number of characters in the string.

Input: "Programming"

Expected Output:

11

18. Count Frequency of Every Character

Description: Count the occurrences of each character.

Input: "hello"

Expected Output:

{
h:1,
e:1,
l:2,
o:1
}

19. Combine Two Strings

Description: Join two strings together.

Input:

"Hello"
"World"

Expected Output:

HelloWorld

20. Print Characters at Even Positions

Description: Display characters at even index positions.

Input: "JavaScript"

Expected Output:

JvSrp

21. Check Whether the String Contains Numbers

Description: Determine whether the string contains any numeric digit.

Input: "Code123"

Expected Output:

Contains Number

22. Count Total Vowels

Description: Count all vowels present in the string.

Input: "I love JavaScript"

Expected Output:

6

23. Count Total Consonants

Description: Count all consonants present in the string.

Input: "JavaScript"

Expected Output:

7

24. Print Characters at Odd Positions

Description: Display characters at odd index positions.

Input: "abcdefg"

Expected Output:

bdf

25. Remove Duplicate Characters

Description: Remove duplicate characters while preserving the first occurrence.

Input: "programming"

Expected Output:

progamin

26. Check Whether a String Contains Special Characters

Description: Write a JavaScript program to determine whether a given string contains any special characters.

Input:

"JavaScript@2025!"

Expected Output:

Given string contains special characters.

27. Exchange the First and Last Character of the Entire String

Description: Write a JavaScript program to swap the first and last character of the complete string.

Input:

"We are learning JavaScript"

Expected Output:

"ee are learning JavaScripW"

28. Convert All Characters to Uppercase

Description: Write a JavaScript program to convert all lowercase letters of a string into uppercase.

Input:

"I live in Pune"

Expected Output:

"I LIVE IN PUNE"

29. Remove Newline Characters

Description: Write a JavaScript program to remove newline (\n) characters from a string.

Input:

"Object Oriented Programming\n"

Expected Output:

"Object Oriented Programming"

30. Split and Join a String

Description: Write a JavaScript program to split a string into words and join them using a hyphen (-).

Input:

"Hello World"

Expected Output:

["Hello", "World"]

"Hello-World"

31. Format a Floating-Point Number

Description: Write a JavaScript program to display a floating-point number with exactly 3 decimal places and convert it into a string.

Input:

2.14652

Expected Output:

"2.147"

32. Convert Number Words into Digits

Description: Write a JavaScript program to convert number words into their corresponding numeric value.

Input:

"five four three two one"

Expected Output:

54321

33. Find the Position of a Word

Description: Write a JavaScript program to find the position of a specified word in a sentence.

Input:

Sentence: "I am solving string problems"
Word: "problems"

Expected Output:

4

34. Count Occurrences of a Word

Description: Write a JavaScript program to count how many times a word appears in a sentence.

Input:

Sentence: "We are learning JavaScript and we are practicing daily"
Word: "are"

Expected Output:

2

35. Find the Least Frequent Character

Description: Write a JavaScript program to identify the character with the lowest frequency in a string.

Input:

"abcdabdggfhf"

Expected Output:

c

36. Find Words Greater Than a Given Length

Description: Write a JavaScript program to display all words whose length is greater than the specified value.

Input:

Length: 3
Sentence: "We are learning JavaScript"

Expected Output:

["learning", "JavaScript"]

37. Get the First Four Characters

Description: Write a JavaScript program to extract the first four characters from a string.

Input:

"JavaScript"

Expected Output:

"Java"

38. Create a String Using the First Two and Last Two Characters

Description: Write a JavaScript program to create a new string using the first two and last two characters.

Input:

"JavaScript"

Expected Output:

"Japt"

39. Print the Mirror Image of a String

Description: Write a JavaScript program to display the mirror image (reverse) of a string.

Input:

"JavaScript"

Expected Output:

"tpircSavaJ"

40. Split a String on Vowels

Description: Write a JavaScript program to split a string wherever a vowel occurs.

Input:

"qwerty"

Expected Output:

["qw", "rty"]

41. Replace Multiple Words

Description: Write a JavaScript program to replace multiple words in a sentence with new words.

Input:

Sentence: "I am learning JavaScript at SQA Tools"

Replace:
JavaScript → JS
SQA Tools → Academy

Expected Output:

"I am learning JS at Academy"

42. Replace Multiple Characters

Description: Write a JavaScript program to replace multiple characters in a string simultaneously.

Input:

String: "JavaScript"

Replace:
a → 1
t → 2
i → 3

Expected Output:

"J1v1Scr3p2"

43. Remove Empty Strings from an Array

Description: Write a JavaScript program to remove empty strings from an array of strings.

Input:

["JavaScript", "", "", "Programming"]

Expected Output:

["JavaScript", "Programming"]

44. Remove Punctuation

Description: Write a JavaScript program to remove all punctuation marks from a string.

Input:

"JavaScript: is great, for web development!"

Expected Output:

"JavaScript is great for web development"

45. Find Duplicate Characters

Description: Write a JavaScript program to display all duplicate characters in a string.

Input:

"hello world"

Expected Output:

"lo"

46. Check Whether One String is a Subset of Another

Description: Write a JavaScript program to determine whether all characters of one string exist in another string.

Input:

Main String: "iamlearningjavascript"
Subset String: "jscript"

Expected Output:

true

47. Sort Characters in a String

Description: Write a JavaScript program to sort all characters of a string in ascending order.

Input:

"xyabkmp"

Expected Output:

"abkmpxy"

48. Generate a Random Binary String

Description: Write a JavaScript program to generate a random binary string of the specified length.

Input:

8

Expected Output:

10100110

49. Check Whether a Substring Exists

Description: Write a JavaScript program to determine whether a given substring exists in a string.

Input:

String: "I live in Pune"
Substring: "live"

Expected Output:

Yes

50. Find Frequency of All Substrings

Description: Write a JavaScript program to calculate the frequency of every possible substring in a string.

Input:

"abab"

Expected Output:

{
"a":2,
"ab":2,
"aba":1,
"abab":1,
"b":2,
"ba":1,
"bab":1
}

51. Check Whether Two Strings are Rotations of Each Other

Description: Write a JavaScript program to check whether one string is a rotation of another string.

Input:

String 1: "ABCD"
String 2: "CDAB"

Expected Output:

The strings are rotations of each other.

52. Remove All Whitespaces from a String

Description: Write a JavaScript program to remove all whitespace characters from a string.

Input:

"JavaScript   Programming   Language"

Expected Output:

"JavaScriptProgrammingLanguage"

53. Capitalize the First Letter of Every Word

Description: Write a JavaScript program to convert the first letter of every word to uppercase.

Input:

"welcome to javascript programming"

Expected Output:

"Welcome To Javascript Programming"

54. Convert the First Letter of Every Word to Lowercase

Description: Write a JavaScript program to convert the first letter of every word to lowercase while keeping the remaining characters unchanged.

Input:

"Hello World JavaScript"

Expected Output:

"hello world javascript"

55. Find the ASCII Value of Each Character

Description: Write a JavaScript program to display the ASCII (Unicode) value of every character in a string.

Input:

"ABC"

Expected Output:

A : 65
B : 66
C : 67

56. Count the Number of Digits in a String

Description: Write a JavaScript program to count how many numeric digits are present in a string.

Input:

"Java123Script45"

Expected Output:

5

57. Remove All Digits from a String

Description: Write a JavaScript program to remove all numeric digits from a string.

Input:

"Java123Script45"

Expected Output:

"JavaScript"

58. Replace Spaces with Hyphens

Description: Write a JavaScript program to replace every space in a string with a hyphen (-).

Input:

"I love JavaScript"

Expected Output:

"I-love-JavaScript"

59. Count the Number of Words in a Sentence

Description: Write a JavaScript program to count the total number of words in a sentence.

Input:

"JavaScript is easy to learn"

Expected Output:

5

60. Find the Middle Character of a String

Description: Write a JavaScript program to display the middle character of a string. If the string length is even, display the two middle characters.

Input:

"Python"

Expected Output:

"th"

61. Remove the First Occurrence of a Character

Description: Write a JavaScript program to remove the first occurrence of a specified character from a string.

Input:

String: "programming"
Character: "r"

Expected Output:

"pogramming"

62. Remove the Last Occurrence of a Character

Description: Write a JavaScript program to remove the last occurrence of a specified character from a string.

Input:

String: "programming"
Character: "m"

Expected Output:

"programing"

63. Find All Positions of a Character

Description: Write a JavaScript program to display all index positions of a specified character.

Input:

String: "banana"
Character: "a"

Expected Output:

[1, 3, 5]

64. Find the First Non-Repeated Character

Description: Write a JavaScript program to find the first character that appears only once in a string.

Input:

"swiss"

Expected Output:

"w"

65. Find the First Repeated Character

Description: Write a JavaScript program to find the first character that appears more than once.

Input:

"programming"

Expected Output:

"r"

66. Reverse Every Word in a Sentence

Description: Write a JavaScript program to reverse every word individually without changing the word order.

Input:

"I love JavaScript"

Expected Output:

"I evol tpircSavaJ"

67. Reverse the Order of Words

Description: Write a JavaScript program to reverse the order of words in a sentence.

Input:

"I love JavaScript"

Expected Output:

"JavaScript love I"

68. Find the Longest Palindromic Word

Description: Write a JavaScript program to find the longest palindrome word from a sentence.

Input:

"madam level racecar apple"

Expected Output:

"racecar"

69. Count Uppercase and Lowercase Letters

Description: Write a JavaScript program to count the total number of uppercase and lowercase letters.

Input:

"JavaScript123"

Expected Output:

Uppercase: 2
Lowercase: 8

70. Check Whether a String Starts and Ends with the Same Character

Description: Write a JavaScript program to determine whether the first and last characters of a string are the same.

Input:

"level"

Expected Output:

Yes

71. Remove Consecutive Duplicate Characters

Description: Write a JavaScript program to remove consecutive duplicate characters from a string.

Input:

"aabbbccdaa"

Expected Output:

"abcda"

72. Compress a String Using Character Count

Description: Write a JavaScript program to compress a string by replacing repeated characters with their frequency.

Input:

"aaabbcccc"

Expected Output:

"a3b2c4"

73. Expand a Compressed String

Description: Write a JavaScript program to expand a compressed string into its original form.

Input:

"a3b2c4"

Expected Output:

"aaabbcccc"

74. Find the Common Characters Between Two Strings

Description: Write a JavaScript program to display all common characters present in two strings.

Input:

String 1: "javascript"
String 2: "typescript"

Expected Output:

"a, s, c, r, i, p, t"

75. Remove Common Characters from Two Strings

Description: Write a JavaScript program to remove all common characters from two given strings.

Input:

String 1: "apple"
String 2: "ample"

Expected Output:

String 1: "p"
String 2: "m"

JavaScript If-Condition Programs for Practice

Beginner Level

  1. Check whether a number is positive.
  2. Check whether a number is negative.
  3. Check whether a number is zero.
  4. Check whether a number is even.
  5. Check whether a number is odd.
  6. Check whether a person is eligible to vote (age >= 18).
  7. Check whether a student has passed (marks >= 35).
  8. Check whether a number is divisible by 5.
  9. Check whether a number is divisible by 10.
  10. Check whether a character is an uppercase letter.
  11. Check whether a character is a lowercase letter.
  12. Check whether a character is a vowel.
  13. Check whether a character is a consonant.
  14. Check whether a number is greater than 100.
  15. Check whether a person is eligible for a driving license (age >= 18).

Intermediate Level

  1. Check whether a number is divisible by both 3 and 5.
  2. Find the greater of two numbers.
  3. Find the smaller of two numbers.
  4. Check whether two numbers are equal.
  5. Check whether three numbers are all equal.
  6. Find the largest of three numbers.
  7. Find the smallest of three numbers.
  8. Check whether a year is a leap year.
  9. Check whether a number is a multiple of 7.
  10. Check whether a salary is greater than ₹50,000.
  11. Check whether a password length is at least 8 characters.
  12. Check whether a person is a teenager (age between 13 and 19).
  13. Check whether a number is within the range of 1 to 100.
  14. Check whether a product price is eligible for free shipping (price >= ₹500).
  15. Check whether a temperature is below the freezing point.

Advanced Beginner Level

  1. Assign a grade based on marks.
  2. Check whether a number is a three-digit number.
  3. Check whether a number is a four-digit number.
  4. Check whether a number is positive and even.
  5. Check whether a person can enter a movie (age >= 18 and has a ticket).
  6. Check whether a username is "admin".
  7. Check whether a user is logged in.
  8. Check whether an email contains "@".
  9. Check whether a mobile number has exactly 10 digits.
  10. Check whether a number is divisible by either 2 or 3.

Real-World Practice

  1. Check whether an account balance is sufficient for withdrawal.
  2. Check whether an OTP entered is correct.
  3. Check whether a coupon code is valid.
  4. Check whether a shopping cart has items.
  5. Check whether a student has attendance greater than or equal to 75%.
  6. Check whether a user is eligible for a senior citizen discount (age >= 60).
  7. Check whether a customer gets a discount (purchase amount > ₹2000).
  8. Check whether the current time is AM or PM.
  9. Check whether a file size exceeds 5 MB.
  10. Check whether a string is empty.

Challenge Exercises

  • Check whether a number is divisible by 2, 3, and 5.
  • Check whether a person is eligible for a loan (age and salary conditions).
  • Check whether a password is strong (length, uppercase, lowercase, number, special character).
  • Check whether a student passed all subjects.
  • Check whether a user can access an admin panel based on role.
  • Check whether a number lies between two given numbers.
  • Check whether today’s day is a weekend.
  • Check whether an item is in stock before placing an order.
  • Check whether a vehicle is eligible for pollution certification based on its age.
  • Check whether a customer qualifies for free delivery based on location and order amount.

Playwright Fixtures Explained Step by Step

If you are new to Playwright, fixtures may seem confusing. But once you understand them, you’ll realize they are one of the most powerful features in Playwright.

Think of fixtures as helpers that prepare everything your test needs before it starts and clean everything after it finishes.


Real-Life Example

Imagine you’re going to cook dinner.

Before cooking, you need:

  • Wash vegetables
  • Bring utensils
  • Turn on the stove
  • Prepare ingredients

After cooking, you need:

  • Clean utensils
  • Turn off the stove
  • Clean the kitchen

Instead of doing these steps every time, imagine someone does them for you.

That helper is exactly what a fixture is.


What is a Fixture?

A fixture is a function that

  • Creates something before the test
  • Gives it to the test
  • Cleans it after the test

Think of it as:

Prepare
      ↓
Run Test
      ↓
Cleanup

Without Fixtures

Imagine you have three tests.

test('Login Test', async ({ browser }) => {

    const context = await browser.newContext();

    const page = await context.newPage();

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

    // Test

    await context.close();

});

Second test

test('Search Test', async ({ browser }) => {

    const context = await browser.newContext();

    const page = await context.newPage();

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

    // Test

    await context.close();

});

Third test

test('Logout Test', async ({ browser }) => {

    const context = await browser.newContext();

    const page = await context.newPage();

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

    // Test

    await context.close();

});

Notice something?

The same code is repeated.

  • Create Context
  • Create Page
  • Open URL
  • Close Context

This is called duplicate code.

Fixtures solve this problem.


With Fixtures

Create the page only once.

import { test as base } from '@playwright/test';

export const test = base.extend({

    myPage: async ({ browser }, use) => {

        const context = await browser.newContext();

        const page = await context.newPage();

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

        await use(page);

        await context.close();

    }

});

Now every test becomes very small.

test('Login Test', async ({ myPage }) => {

    // use page

});

Another test

test('Search Test', async ({ myPage }) => {

    // use page

});

No duplicate setup.


Understanding the Life Cycle

A fixture always follows this order.

Fixture Starts

↓

Create Resource

↓

Give Resource to Test

↓

Test Executes

↓

Cleanup Resource

↓

Fixture Ends

The Most Important Line

Inside every fixture you’ll see

await use(page);

This is the heart of every fixture.

It separates

Setup from Cleanup

Everything before

await use(page);

is setup.

Everything after

await use(page);

is cleanup.

Example

myPage: async ({ browser }, use) => {

    console.log("Before Test");

    const page = await browser.newPage();

    await use(page);

    console.log("After Test");

    await page.close();

}

Output

Before Test

Test Runs

After Test

Visual Timeline

Fixture Starts

↓

Open Browser

↓

Create Page

↓

Open Website

↓

await use(page)

↓

Test Starts

↓

Test Ends

↓

Close Browser

↓

Fixture Ends

What is “use”?

Suppose someone gives you a laptop.

Friend
   ↓
Hands Laptop
   ↓
You Work
   ↓
Return Laptop

The laptop is available only while you are working.

Playwright does the same thing.

Fixture

↓

Creates Page

↓

use(page)

↓

Test Uses Page

↓

Fixture Gets Control Again

↓

Cleanup

Built-in Fixtures

Playwright already provides many fixtures.

Example

test('Example', async ({ page }) => {

});

Where did page come from?

Playwright created it automatically.

Built-in fixtures include

FixturePurpose
browserBrowser instance
pageNew page
contextBrowser context
requestAPI testing
browserNameBrowser name

Custom Fixture

You can create your own fixture.

Example

export const test = base.extend({

    username: async ({}, use) => {

        await use("Deepesh");

    }

});

Use it

test('Example', async ({ username }) => {

    console.log(username);

});

Output

Deepesh

The fixture can return anything.

  • String
  • Number
  • Object
  • Page
  • Database Connection
  • API Client
  • Login Session

Fixture Returning an Object

user: async ({}, use) => {

    await use({

        name: "Deepesh",

        role: "Admin"

    });

}

Use

test('Example', async ({ user }) => {

    console.log(user.name);

    console.log(user.role);

});

Output

Deepesh

Admin

Login Fixture Example

Instead of logging in inside every test,

Create a login fixture.

loginPage: async ({ page }, use) => {

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

    await page.fill("#username", "admin");

    await page.fill("#password", "admin123");

    await page.click("button");

    await use(page);

}

Now every test starts after login.

test('Dashboard Test', async ({ loginPage }) => {

    await loginPage.click("text=Dashboard");

});

Database Fixture Example

db: async ({}, use) => {

    const database = connectDB();

    await use(database);

    database.close();

}

Every test gets the database connection.


API Fixture Example

api: async ({ request }, use) => {

    const response = request;

    await use(response);

}

Worker Fixture vs Test Fixture

There are two types of fixtures.

Test Fixture

Created for every test.

Test1

Create

↓

Run

↓

Destroy

----------------

Test2

Create

↓

Run

↓

Destroy

Worker Fixture

Created only once for a worker (a process that runs tests).

Worker Starts

↓

Create Fixture

↓

Test1

↓

Test2

↓

Test3

↓

Destroy Fixture

↓

Worker Ends

Worker fixtures are useful for expensive setup, such as:

  • Starting a database
  • Connecting to a server
  • Creating a shared API client
  • Loading large configuration files

Fixture Execution Order

Imagine you have

Database Fixture

↓

Login Fixture

↓

Page Fixture

↓

Test

Execution

Database

↓

Login

↓

Page

↓

Test

↓

Page Cleanup

↓

Login Cleanup

↓

Database Cleanup

Notice cleanup happens in reverse order, like stacking plates.


Folder Structure

A common project structure is:

project

│

├── tests

│      login.spec.ts

│      dashboard.spec.ts

│

├── fixtures

│      baseFixture.ts

│      loginFixture.ts

│      apiFixture.ts

│

├── pages

│      LoginPage.ts

│      DashboardPage.ts

Best Practices

  • Keep fixtures focused on one responsibility (e.g., login, API client, database).
  • Avoid putting test assertions inside fixtures.
  • Reuse fixtures across multiple test files.
  • Use test fixtures for isolated resources and worker fixtures for expensive shared setup.
  • Clean up every resource you create (close pages, contexts, database connections, etc.).
  • Give fixtures meaningful names such as loggedInPage, adminUser, or apiClient.

Complete Flow Diagram

                Test Starts
                     │
                     ▼
         Playwright Reads Fixtures
                     │
                     ▼
         Execute Setup Code
   (Browser, Context, Page, Login)
                     │
                     ▼
             await use(resource)
                     │
                     ▼
          Test Receives Resource
                     │
                     ▼
          Test Executes Assertions
                     │
                     ▼
        Control Returns to Fixture
                     │
                     ▼
          Execute Cleanup Code
 (Close Page, Context, Database, etc.)
                     │
                     ▼
                 Test Ends

Automation Testing Fundamentals

What Is Automation Testing?

Automation testing is the process of using software tools, scripts, and frameworks to execute test cases automatically instead of relying entirely on human testers. Imagine having a robot assistant that can perform repetitive testing tasks every single day without getting tired or making careless mistakes. That is exactly what automation testing offers. It enables software teams to verify that applications continue to function correctly after every update, saving both time and effort.

Modern software development follows Agile and DevOps methodologies where applications are released weekly, daily, or even multiple times a day. Testing every feature manually under these conditions becomes nearly impossible. Automation testing bridges this gap by executing hundreds or even thousands of test cases within minutes. It validates application functionality, compares expected and actual results, and generates detailed reports for developers and QA engineers.

Automation testing is particularly valuable for repetitive scenarios such as regression testing, smoke testing, API validation, and cross-browser testing. Instead of repeatedly performing identical tasks, testers can focus on exploratory testing, usability evaluation, and identifying complex defects that require human creativity. The result is faster releases, higher software quality, and improved customer satisfaction.

Today’s automation testing ecosystem extends beyond simple UI automation. Modern frameworks support API testing, mobile testing, cloud testing, database validation, accessibility testing, and AI-assisted test generation. Organizations increasingly combine automation with Continuous Integration and Continuous Deployment (CI/CD) pipelines, allowing every code change to be validated automatically before reaching production. Industry reports published in 2026 also highlight AI-assisted test generation, self-healing locators, API automation, and QAOps as some of the fastest-growing trends in software quality engineering.


Evolution of Automation Testing

Automation testing has evolved dramatically over the last two decades. Early automation focused primarily on recording user actions and replaying them. These record-and-playback solutions reduced repetitive work but produced fragile scripts that frequently broke whenever the application’s user interface changed. Maintaining these scripts often became more expensive than executing manual tests.

The introduction of frameworks like Selenium transformed the industry by providing flexible browser automation capabilities. Testers could now build reusable frameworks using Java, Python, C#, or JavaScript. As Agile development became mainstream, automation shifted left, meaning testing started earlier during development rather than waiting until the end. Continuous Integration tools like Jenkins and GitHub Actions enabled automated test execution with every code commit.

Today, automation testing is entering a new phase powered by Artificial Intelligence. AI-driven tools automatically generate test cases, repair broken locators, prioritize high-risk test scenarios, and analyze historical failures. Self-healing automation significantly reduces maintenance costs, one of the biggest challenges traditional automation teams have faced. Testing is no longer isolated within QA departments; instead, developers, testers, DevOps engineers, and product owners collaborate within QAOps environments to ensure software quality throughout the delivery lifecycle.

Industry research published in 2026 indicates rapid investment in AI-powered testing technologies, low-code automation platforms, API automation, and infrastructure-aware testing. The global automation testing market continues to expand rapidly as organizations accelerate digital transformation and cloud-native application development. These trends demonstrate that automation testing has become a strategic business capability rather than simply another QA activity.


Types of Automation Testing

Automation testing includes multiple categories, each serving a unique purpose in maintaining software quality. Selecting the right type depends on application architecture, business requirements, release frequency, and project goals.

Functional Testing

Functional automation verifies whether application features behave according to business requirements. It validates login functionality, registration workflows, payment processing, search capabilities, user permissions, and other business processes. Automated functional tests ensure users receive the expected experience after every release.

Regression Testing

Regression testing confirms that recently introduced changes have not broken existing functionality. Since regression suites often contain hundreds or thousands of test cases, automation dramatically reduces execution time. Regression automation forms the backbone of nearly every mature automation strategy.

API Testing

Modern applications rely heavily on APIs. API automation validates request-response behavior, authentication, authorization, response time, error handling, and business logic before the user interface is even available. API testing executes faster than UI testing and provides earlier defect detection, making it an essential component of Shift-Left Testing.

Performance Testing

Performance automation measures system responsiveness under different workloads. Load testing, stress testing, endurance testing, and scalability testing help organizations identify bottlenecks before production deployment. Automated performance tests simulate thousands of concurrent users to ensure applications remain stable during peak traffic.

Testing TypePrimary GoalBest Use Case
Functional TestingValidate business functionalityUser workflows
Regression TestingPrevent existing defectsFrequent releases
API TestingValidate backend servicesMicroservices
Performance TestingMeasure scalabilityHigh-traffic systems

Combining these testing types creates comprehensive software validation while maximizing automation ROI.


Automation Testing Frameworks

An automation framework provides standardized guidelines, reusable components, reporting mechanisms, coding practices, and project structure. Without a framework, automation projects quickly become difficult to maintain as applications evolve.

The Data-Driven Framework separates test logic from test data. Test data resides in Excel files, JSON files, CSV files, XML documents, or databases, allowing the same test script to execute multiple scenarios efficiently. This approach significantly reduces duplicate code while improving maintainability.

The Keyword-Driven Framework uses predefined keywords such as Click, Enter Text, Verify Element, or Select Dropdown. Business analysts and manual testers can often contribute test cases without extensive programming knowledge. The automation engine interprets these keywords and executes corresponding actions, making collaboration easier across technical and non-technical teams.

The Hybrid Framework combines multiple approaches, typically integrating data-driven testing, keyword-driven testing, Page Object Model (POM), utilities, reusable libraries, reporting, logging, configuration management, and CI/CD integration. Hybrid frameworks are the most common enterprise solution because they balance flexibility, maintainability, scalability, and code reuse. Large organizations frequently build custom hybrid frameworks tailored to their technology stack, coding standards, and release processes.

A well-designed framework should emphasize modularity, maintainability, error handling, logging, reusable components, parallel execution, configuration management, and integration with version control systems and CI/CD pipelines. These characteristics reduce long-term maintenance costs while increasing automation reliability.


Popular Automation Testing Tools

Choosing the right automation tool depends on application technology, programming language preferences, team expertise, licensing requirements, and long-term maintenance considerations.

Selenium remains one of the most widely adopted open-source web automation frameworks. It supports multiple programming languages and browsers while integrating with TestNG, JUnit, PyTest, Maven, Gradle, Jenkins, and cloud platforms. Selenium’s extensive ecosystem and community support make it a preferred choice for enterprise web automation despite competition from newer frameworks.

Playwright has gained tremendous popularity due to its speed, reliability, automatic waiting mechanisms, built-in network interception, multi-browser support, and excellent debugging capabilities. It supports Chromium, Firefox, and WebKit from a single API while simplifying cross-browser automation. Many modern QA teams consider Playwright an excellent choice for new automation projects because of its stability and developer-friendly features.

Cypress focuses on front-end web testing with an intuitive developer experience. Its architecture allows real-time debugging, automatic waiting, and simplified test execution for modern JavaScript applications. Cypress is particularly popular among React, Angular, and Vue development teams.

Robot Framework provides keyword-driven automation with a readable syntax suitable for technical and non-technical users alike. Its extensible architecture supports Selenium, Playwright, API testing, database validation, and custom Python libraries, making it useful across diverse testing scenarios.

ToolBest ForLanguage Support
SeleniumEnterprise Web AutomationJava, Python, C#, JS
PlaywrightModern Web TestingTypeScript, JavaScript, Python, Java, .NET
CypressFront-end ApplicationsJavaScript, TypeScript
Robot FrameworkKeyword-Driven TestingPython Ecosystem

Best Practices and Future Scope

Successful automation projects require more than selecting the right tool. Organizations should automate stable and repetitive test cases rather than attempting to automate every scenario. Exploratory testing, usability testing, and rapidly changing features often remain better suited for manual execution.

Automation scripts should follow clean coding principles, reusable Page Object Models, centralized test data management, meaningful assertions, robust exception handling, and detailed reporting. Regular code reviews, version control, CI/CD integration, and parallel execution further improve efficiency. Teams should also avoid brittle locators by using stable identifiers whenever possible and periodically refactor automation frameworks as applications evolve.

The future of automation testing is closely tied to Artificial Intelligence. AI-assisted test generation, self-healing scripts, intelligent defect prediction, risk-based test selection, autonomous maintenance, and natural language automation are becoming increasingly practical. Industry surveys consistently show growing adoption of AI, API automation, cloud execution, containerized testing, and QAOps practices. Rather than replacing testers, AI enables them to focus on strategy, system thinking, exploratory testing, and quality engineering.

For aspiring QA professionals, automation testing remains an excellent career path. Employers increasingly seek engineers with expertise in programming, API testing, Playwright or Selenium, Git, CI/CD, cloud platforms, SQL, Docker, and AI-assisted testing workflows. The strongest professionals combine technical automation skills with deep testing fundamentals and business understanding, enabling them to deliver reliable, high-quality software at scale.

Conclusion

Automation testing has transformed software quality assurance from a slow, manual process into an intelligent, scalable, and highly efficient engineering discipline. It enables organizations to deliver faster releases, improve application reliability, reduce human error, and integrate quality throughout the software development lifecycle. Modern automation extends beyond UI testing into APIs, cloud platforms, performance testing, and AI-assisted quality engineering.

Learning automation testing fundamentals is the first step toward becoming a successful QA Automation Engineer or SDET. By mastering testing principles, selecting appropriate frameworks, understanding automation tools, and adopting industry best practices, professionals can build maintainable automation solutions that continue delivering value as software systems evolve. As AI reshapes software testing, strong fundamentals remain the foundation upon which every advanced automation skill is built.

Playwright Read Data From WebTable

Sample HTML Table

<table id="employeeTable">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Department</th>
            <th>Salary</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>101</td>
            <td>John</td>
            <td>QA</td>
            <td>50000</td>
        </tr>
        <tr>
            <td>102</td>
            <td>David</td>
            <td>Developer</td>
            <td>70000</td>
        </tr>
        <tr>
            <td>103</td>
            <td>Smith</td>
            <td>Manager</td>
            <td>90000</td>
        </tr>
    </tbody>
</table>

1. Read Entire Table

import { test } from '@playwright/test';

test('Read complete web table', async ({ page }) => {

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

    const rows = page.locator('#employeeTable tbody tr');

    const rowCount = await rows.count();

    for (let i = 0; i < rowCount; i++) {

        const cells = rows.nth(i).locator('td');

        const cellCount = await cells.count();

        for (let j = 0; j < cellCount; j++) {

            const value = await cells.nth(j).textContent();

            process.stdout.write(`${value}\t`);
        }

        console.log();
    }

});

Output

101     John     QA          50000
102     David    Developer   70000
103     Smith    Manager     90000

2. Read Specific Row

Example: Read the second row.

const secondRow = page.locator('#employeeTable tbody tr').nth(1);

const cells = secondRow.locator('td');

console.log(await cells.nth(0).textContent());
console.log(await cells.nth(1).textContent());
console.log(await cells.nth(2).textContent());
console.log(await cells.nth(3).textContent());

Output

102
David
Developer
70000

3. Read Specific Column

Example: Read all employee names.

const names = page.locator('#employeeTable tbody tr td:nth-child(2)');

const count = await names.count();

for (let i = 0; i < count; i++) {
    console.log(await names.nth(i).textContent());
}

Output

John
David
Smith

4. Read Cell by Row and Column

Example: Row 2, Column 3

const value = await page
    .locator('#employeeTable tbody tr')
    .nth(1)
    .locator('td')
    .nth(2)
    .textContent();

console.log(value);

Output

Developer

5. Find Row Using Text

Find employee “David”.

const row = page.locator('#employeeTable tbody tr').filter({
    hasText: 'David'
});

console.log(await row.textContent());

Output

102 David Developer 70000

6. Read Salary of a Specific Employee

const rows = page.locator('#employeeTable tbody tr');

const rowCount = await rows.count();

for (let i = 0; i < rowCount; i++) {

    const name = await rows.nth(i).locator('td').nth(1).textContent();

    if (name === 'David') {

        const salary = await rows.nth(i).locator('td').nth(3).textContent();

        console.log(salary);

        break;
    }
}

Output

70000

7. Store Table Data in an Array

const tableData: string[][] = [];

const rows = page.locator('#employeeTable tbody tr');

const rowCount = await rows.count();

for (let i = 0; i < rowCount; i++) {

    const rowData: string[] = [];

    const cells = rows.nth(i).locator('td');

    const cellCount = await cells.count();

    for (let j = 0; j < cellCount; j++) {

        rowData.push((await cells.nth(j).textContent())?.trim() || '');
    }

    tableData.push(rowData);
}

console.log(tableData);

Output

[
  ['101', 'John', 'QA', '50000'],
  ['102', 'David', 'Developer', '70000'],
  ['103', 'Smith', 'Manager', '90000']
]

8. Store Table Data as Objects

interface Employee {
    id: string;
    name: string;
    department: string;
    salary: string;
}

const employees: Employee[] = [];

const rows = page.locator('#employeeTable tbody tr');

const rowCount = await rows.count();

for (let i = 0; i < rowCount; i++) {

    const cells = rows.nth(i).locator('td');

    employees.push({
        id: (await cells.nth(0).textContent())?.trim() || '',
        name: (await cells.nth(1).textContent())?.trim() || '',
        department: (await cells.nth(2).textContent())?.trim() || '',
        salary: (await cells.nth(3).textContent())?.trim() || '',
    });
}

console.log(employees);

Output

[
  {
    id: '101',
    name: 'John',
    department: 'QA',
    salary: '50000'
  },
  {
    id: '102',
    name: 'David',
    department: 'Developer',
    salary: '70000'
  }
]

9. Verify Data Exists in the Table

import { expect } from '@playwright/test';

const employeeNames = page.locator('#employeeTable tbody tr td:nth-child(2)');

await expect(employeeNames).toContainText([
    'John',
    'David',
    'Smith'
]);

10. Read Table Headers

const headers = page.locator('#employeeTable thead th');

const count = await headers.count();

for (let i = 0; i < count; i++) {
    console.log(await headers.nth(i).textContent());
}

Output

ID
Name
Department
Salary