Showing posts with label Playwright. Show all posts
Showing posts with label Playwright. Show all posts

Tuesday, June 16

Playwright

 

Playwright Tutorial: Beginner to Advanced

Since you already work in automation testing, I'll cover Playwright from a QA Automation Engineer perspective, including interview-focused concepts and framework design.


1. What is Playwright?

Playwright is a modern automation framework developed by Microsoft Playwright for web application testing.

Features

  • Supports Chromium, Firefox, and WebKit
  • Cross-platform (Windows, Linux, macOS)
  • Auto-wait mechanism
  • Parallel execution
  • API Testing
  • Mobile emulation
  • Network interception
  • Visual testing
  • CI/CD integration

2. Installation

Install Node.js

Download Node.js:

Node.js Official Website

Verify:

node -v
npm -v

Create Project

mkdir PlaywrightFramework
cd PlaywrightFramework

npm init -y

Install Playwright

npm init playwright@latest

Select:

✔ TypeScript
✔ Tests Folder
✔ GitHub Actions
✔ Install Browsers

3. Project Structure

PlaywrightFramework

tests/
pages/
utils/
fixtures/
test-data/

playwright.config.ts

package.json

4. First Test

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

test('Login Page Title', async ({ page }) => {

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

await expect(page).toHaveTitle(/Example/);

});

Run:

npx playwright test

5. Playwright Inspector

Debug Test

npx playwright test --debug

Inspector opens.

Useful for:

  • Step execution
  • Locator identification
  • Debugging failures

6. Record Script

npx playwright codegen https://example.com

Playwright records actions automatically.


7. Locators

By Text

page.getByText('Login')

By Role

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

By Label

page.getByLabel('Email')

CSS

page.locator('#username')

XPath

page.locator('//input[@id="username"]')

8. Actions

Click

await page.locator('#login').click();

Fill

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

Type

await page.locator('#username').type('admin');

Dropdown

await page.selectOption('#country','India');

Checkbox

await page.check('#remember');

9. Assertions

await expect(page).toHaveTitle('Dashboard');

await expect(locator).toBeVisible();

await expect(locator).toContainText('Welcome');

await expect(locator).toBeEnabled();

10. Handling Waits

Auto Wait

await page.click('#login');

Playwright automatically waits.


Explicit Wait

await page.waitForSelector('#dashboard');

Network Wait

await page.waitForLoadState('networkidle');

11. Input Fields

await page.fill('#email','test@test.com');
await page.fill('#password','123456');

12. Mouse Actions

await page.hover('#menu');

await page.dragAndDrop(
'#source',
'#target'
);

13. Keyboard Actions

await page.keyboard.press('Enter');

await page.keyboard.press('Control+A');

await page.keyboard.press('Delete');

14. Frames

const frame =
page.frame({ name: 'frame1' });

await frame.fill('#username','admin');

Or:

const frame =
page.frameLocator('#frame');

await frame.locator('#login').click();

15. Multiple Tabs

const pagePromise =
context.waitForEvent('page');

await page.click('a');

const newPage =
await pagePromise;

16. File Upload

await page.setInputFiles(
'#upload',
'test.pdf'
);

17. Download File

const downloadPromise =
page.waitForEvent('download');

await page.click('#download');

const download =
await downloadPromise;

await download.saveAs('report.pdf');

18. Screenshot

await page.screenshot({
path:'home.png'
});

Element Screenshot:

await page.locator('#logo')
.screenshot({
path:'logo.png'
});

19. Handling Alerts

page.on('dialog',
async dialog => {

console.log(dialog.message());

await dialog.accept();

});

Reject:

await dialog.dismiss();

20. API Testing

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

test('GET API', async ({ request }) => {

const response =
await request.get(
'https://reqres.in/api/users/2'
);

expect(response.status())
.toBe(200);

});

21. Authentication

const response =
await request.post('/login', {

data:{
email:'admin@test.com',
password:'123'
}

});

22. Data Driven Testing

const users = [

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

{
username:'user',
password:'user123'
}

];

for(const user of users){

test(`Login ${user.username}`,
async ({ page }) => {

});

}

23. Page Object Model (POM)

LoginPage.ts

export class LoginPage {

constructor(page){

this.page = page;

this.username =
page.locator('#username');

this.password =
page.locator('#password');

this.loginBtn =
page.locator('#login');

}

async login(user,pass){

await this.username.fill(user);

await this.password.fill(pass);

await this.loginBtn.click();

}

}

Test

import { LoginPage }
from '../pages/LoginPage';

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

const login =
new LoginPage(page);

await login.login(
'admin',
'admin123'
);

});

24. Parallel Execution

npx playwright test --workers=4

Config:

workers: 4

25. Retry Failed Tests

retries: 2

26. Cross Browser Testing

projects: [

{
name:'Chrome'
},

{
name:'Firefox'
},

{
name:'Safari'
}

]

Run:

npx playwright test

27. CI/CD with GitHub Actions

name: Playwright

on:
push:

jobs:
test:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v3

- uses: actions/setup-node@v3

- run: npm ci

- run: npx playwright install

- run: npx playwright test

28. Network Interception

await page.route('**/users',

route => route.fulfill({

status:200,

body:JSON.stringify({
name:'Pushkar'
})

})

);

29. Mock API

await page.route(
'**/api/login',

route => route.fulfill({

status:200,

body:'Success'

})

);

30. Advanced Framework Structure

PlaywrightFramework

pages/
LoginPage.ts
HomePage.ts

tests/
login.spec.ts

utils/
logger.ts
helper.ts

fixtures/
baseFixture.ts

data/
users.json

reports/

playwright.config.ts

31. Playwright Interview Questions

Why Playwright over Selenium?

Answer:

  • Faster execution
  • Auto-waiting
  • Better handling of modern web apps
  • Multiple browser engines
  • Built-in API testing
  • Parallel execution support

What is auto-waiting?

Playwright automatically waits for:

  • Element visibility
  • Stability
  • Clickability
  • Navigation completion

Difference between Locator and ElementHandle?

Locator:

  • Dynamic
  • Recommended
  • Auto waits

ElementHandle:

  • Static reference
  • Can become stale

32. Advanced Topics for Senior QA

  • Playwright with TypeScript
  • POM + Fixtures
  • Custom Reporter
  • Allure Integration
  • API + UI Hybrid Testing
  • Docker Execution
  • Jenkins Pipeline
  • BrowserStack Integration
  • Visual Regression Testing
  • Network Mocking
  • Contract Testing
  • Accessibility Testing
  • Performance Metrics Collection
  • Microservices API Automation

Recommended Learning Path

  1. Basics & Locators
  2. Actions & Assertions
  3. Frames & Windows
  4. API Testing
  5. Data-Driven Testing
  6. POM Design Pattern
  7. Fixtures
  8. Parallel Execution
  9. Network Mocking
  10. CI/CD Integration
  11. Allure Reporting
  12. BrowserStack Execution
  13. Enterprise Framework Design

Given your 6+ years of QA experience and automation background, the next valuable step would be building a real-world Playwright framework with TypeScript, POM, API testing, Allure reporting, Jenkins, GitHub Actions, and BrowserStack integration.

Yes

Excellent. Since you're already experienced in automation testing, I'll focus on an Enterprise-Level Playwright Framework that is commonly expected for Senior QA Engineer, QA Lead, and SDET interviews.

Phase 1: Create Playwright Framework

Project Structure

PlaywrightFramework

├── tests
│ ├── login.spec.ts
│ ├── dashboard.spec.ts

├── pages
│ ├── LoginPage.ts
│ ├── DashboardPage.ts

├── fixtures
│ ├── baseFixture.ts

├── utils
│ ├── Logger.ts
│ ├── APIHelper.ts

├── testdata
│ ├── users.json

├── reports

├── playwright.config.ts

├── package.json

Phase 2: Install Dependencies

npm init playwright@latest

Install additional packages:

npm install dotenv
npm install allure-playwright
npm install axios
npm install winston

Phase 3: Page Object Model

LoginPage.ts

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

export class LoginPage {

constructor(private page: Page) {}

username = this.page.locator('#username');
password = this.page.locator('#password');
loginBtn = this.page.locator('#login');

async login(user: string, pass: string) {
await this.username.fill(user);
await this.password.fill(pass);
await this.loginBtn.click();
}
}

DashboardPage.ts

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

export class DashboardPage {

constructor(private page: Page) {}

dashboardTitle = this.page.locator('.dashboard');

async verifyDashboard() {
return this.dashboardTitle.isVisible();
}
}

Phase 4: Test Data Management

users.json

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

"invalidUser": {
"username": "test",
"password": "wrong"
}
}

Test Example

import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';

const data = require('../testdata/users.json');

test('Valid Login', async ({ page }) => {

const loginPage = new LoginPage(page);

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

await loginPage.login(
data.validUser.username,
data.validUser.password
);

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

Phase 5: Fixtures

baseFixture.ts

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

type MyFixtures = {
loginPage: LoginPage;
};

export const test = base.extend<MyFixtures>({
loginPage: async ({ page }, use) => {
await use(new LoginPage(page));
}
});

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

Usage

import { test, expect } from '../fixtures/baseFixture';

test('Login', async ({ page, loginPage }) => {

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

await loginPage.login(
'admin',
'admin123'
);
});

Phase 6: API Testing

APIHelper.ts

import axios from 'axios';

export class APIHelper {

async getUser() {

const response = await axios.get(
'https://reqres.in/api/users/2'
);

return response;
}
}

API Test

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

test('Get User API', async ({ request }) => {

const response =
await request.get(
'https://reqres.in/api/users/2'
);

expect(response.status()).toBe(200);

const body = await response.json();

expect(body.data.id).toBe(2);

});

Phase 7: Environment Configuration

.env

QA_URL=https://qa.site.com
UAT_URL=https://uat.site.com
PROD_URL=https://prod.site.com

playwright.config.ts

import * as dotenv from 'dotenv';

dotenv.config();

export default {

use: {

baseURL: process.env.QA_URL,

headless: false

}

};

Phase 8: Retry & Parallel Execution

export default {

retries: 2,

workers: 4

}

Run:

npx playwright test --workers=4

Phase 9: Screenshots & Videos

use: {

screenshot: 'only-on-failure',

video: 'retain-on-failure',

trace: 'retain-on-failure'

}

Phase 10: Allure Reporting

Install:

npm install allure-playwright

Config:

reporter: [

['list'],

['allure-playwright']

]

Generate Report:

npx allure generate allure-results --clean

npx allure open

Phase 11: Network Mocking

test('Mock Login API', async ({ page }) => {

await page.route(
'**/login',

async route => {

await route.fulfill({

status: 200,

body: JSON.stringify({

success: true

})

});

}
);

});

Phase 12: Visual Testing

test('Homepage Snapshot',
async ({ page }) => {

await page.goto('/');

await expect(page)
.toHaveScreenshot();

});

Phase 13: BrowserStack Integration

Install:

npm install browserstack-node-sdk

browserstack.yml

userName: USERNAME

accessKey: ACCESS_KEY

framework: playwright

Run:

browserstack-node-sdk playwright test

Phase 14: Jenkins Integration

Jenkinsfile

pipeline {

agent any

stages {

stage('Install') {

steps {

sh 'npm install'

}

}

stage('Test') {

steps {

sh 'npx playwright test'

}

}

stage('Allure') {

steps {

allure([
includeProperties: false
])
}

}
}
}

Phase 15: Advanced Interview Questions

What is a Fixture in Playwright?

A fixture provides reusable setup and teardown logic that can be injected into tests.


What is Trace Viewer?

Playwright Trace Viewer records:

  • Screenshots
  • Network calls
  • Console logs
  • DOM snapshots

Open trace:

npx playwright show-trace trace.zip

How do you handle flaky tests?

  • Use stable locators
  • Avoid hard waits
  • Use retries
  • Network mocking
  • Explicit assertions
  • Test isolation

Playwright vs Selenium

FeaturePlaywrightSelenium
Auto WaitYesNo
SpeedFastModerate
API TestingBuilt-inExternal
Parallel ExecutionNativeGrid
Mobile EmulationBuilt-inLimited
Network MockingYesNo

Enterprise-Level Framework Features

A mature Playwright framework should include:

✅ TypeScript

✅ POM Design Pattern

✅ Fixtures

✅ API + UI Testing

✅ Allure Reports

✅ Jenkins Pipeline

✅ GitHub Actions

✅ BrowserStack

✅ Docker

✅ Environment Management

✅ Data-Driven Testing

✅ Retry Mechanism

✅ Screenshot/Video Capture

✅ Trace Viewer

✅ Network Mocking

✅ Visual Testing

✅ Slack/Email Notifications

Since your background includes game automation and QA leadership, the next advanced step would be a Playwright + TypeScript Hybrid Framework with UI, API, Database Validation, Allure, Jenkins, BrowserStack, Docker, and GitHub Actions, similar to what large product companies use.

Yes

Enterprise Playwright Framework (UI + API + DB + Allure + Jenkins + Docker)

This is the kind of framework architecture commonly used in product companies and expected from Senior QA, QA Lead, and SDET candidates.


Folder Structure

playwright-enterprise-framework

├── tests
│ ├── ui
│ │ ├── login.spec.ts
│ │ ├── dashboard.spec.ts
│ │
│ ├── api
│ │ ├── userApi.spec.ts
│ │
│ └── db
│ ├── userValidation.spec.ts

├── pages
│ ├── LoginPage.ts
│ ├── DashboardPage.ts

├── api
│ ├── UserAPI.ts

├── database
│ ├── DBHelper.ts

├── fixtures
│ ├── baseFixture.ts

├── utils
│ ├── Logger.ts
│ ├── ConfigReader.ts
│ ├── ScreenshotUtil.ts

├── testdata
│ ├── users.json

├── reports
├── allure-results
├── allure-report

├── .env
├── Dockerfile
├── Jenkinsfile
├── playwright.config.ts

└── package.json

Step 1: Install Dependencies

npm install

npm install dotenv

npm install allure-playwright

npm install axios

npm install mysql2

npm install pg

npm install winston

npm install faker

Step 2: Environment Configuration

.env

BASE_URL=https://qa.myapp.com

DB_HOST=localhost
DB_USER=root
DB_PASSWORD=password
DB_NAME=testdb

API_URL=https://api.myapp.com

Config Reader

import dotenv from 'dotenv';

dotenv.config();

export const config = {

baseUrl: process.env.BASE_URL,

apiUrl: process.env.API_URL,

dbHost: process.env.DB_HOST,

dbUser: process.env.DB_USER,

dbPassword: process.env.DB_PASSWORD,

dbName: process.env.DB_NAME

};

Step 3: Logger Utility

Logger.ts

import winston from 'winston';

export const logger = winston.createLogger({

transports: [

new winston.transports.Console(),

new winston.transports.File({
filename: 'execution.log'
})

]

});

Usage:

logger.info('Login Started');

logger.error('Login Failed');

Step 4: Database Validation

MySQL Example

DBHelper.ts

import mysql from 'mysql2/promise';

export class DBHelper {

async executeQuery(query: string) {

const connection =
await mysql.createConnection({

host: process.env.DB_HOST,

user: process.env.DB_USER,

password: process.env.DB_PASSWORD,

database: process.env.DB_NAME

});

const [rows] =
await connection.execute(query);

await connection.end();

return rows;
}
}

Database Validation Test

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

import { DBHelper }
from '../../database/DBHelper';

test('Validate User In DB',
async () => {

const db = new DBHelper();

const users =
await db.executeQuery(

"SELECT * FROM users WHERE id=1"

);

expect(users.length)
.toBeGreaterThan(0);

});

Step 5: API Layer

UserAPI.ts

import axios from 'axios';

export class UserAPI {

async getUser(id:number) {

return await axios.get(

`${process.env.API_URL}/users/${id}`

);

}
}

API Test

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

import { UserAPI }
from '../../api/UserAPI';

test('Get User API',
async () => {

const api = new UserAPI();

const response =
await api.getUser(2);

expect(response.status)
.toBe(200);

});

Step 6: UI + API Validation

A common interview question.

Scenario

  1. Create User via API
  2. Login UI
  3. Search User
  4. Validate Data
test('End-to-End Validation',
async ({ page, request }) => {

const response =
await request.post('/users', {

data: {

name:'Pushkar'

}

});

const body =
await response.json();

const userId =
body.id;

await page.goto('/users');

await page.fill(
'#search',
userId
);

await page.click('#searchBtn');

await expect(
page.locator('.username')
)
.toContainText('Pushkar');

});

Step 7: Custom Fixture

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

import { LoginPage }
from '../pages/LoginPage';

type MyFixture = {

loginPage: LoginPage

};

export const test =
base.extend<MyFixture>({

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

await use(
new LoginPage(page)
);

}

});

Step 8: Screenshot Utility

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

export async function captureScreenshot(
page: Page,
name: string
){

await page.screenshot({

path:
`reports/${name}.png`

});

}

Step 9: Retry Failed Tests

retries: 2

Step 10: Parallel Execution

workers: 6

Step 11: Allure Reporting

Config:

reporter: [

['list'],

['allure-playwright']

]

Generate Report:

npx allure generate

npx allure open

Step 12: Docker Integration

Dockerfile

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

WORKDIR /app

COPY . .

RUN npm install

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

Build:

docker build -t playwright .

docker run playwright

Step 13: GitHub Actions

name: Playwright

on:

push:

jobs:

test:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: actions/setup-node@v4

- run: npm ci

- run: npx playwright install

- run: npx playwright test

Step 14: Jenkins Pipeline

pipeline {

agent any

stages {

stage('Install') {

steps {

sh 'npm install'

}

}

stage('Execute') {

steps {

sh 'npx playwright test'

}

}

stage('Allure') {

steps {

allure()

}

}

}

}

Step 15: BrowserStack Parallel Execution

browserstack.yml

platforms:

- os: Windows
osVersion: 11
browserName: chrome

- os: OS X
osVersion: Ventura
browserName: safari

Execute:

browserstack-node-sdk playwright test

Step 16: Advanced Playwright Concepts

Network Interception

await page.route(
'**/users',
route => route.fulfill({

status:200,

body:'mocked'

})
);

Request Monitoring

page.on(
'request',
request => {

console.log(
request.url()
);

});

Response Monitoring

page.on(
'response',
response => {

console.log(
response.status()
);

});

Step 17: Visual Regression Testing

await expect(page)
.toHaveScreenshot(
'homepage.png'
);

Step 18: Playwright Interview Questions for QA Lead

What framework architecture would you choose?

  • POM
  • Fixtures
  • API Layer
  • Utility Layer
  • Reporting Layer
  • CI/CD Layer
  • Test Data Layer

How do you reduce flaky tests?

  • Stable locators
  • Avoid hard waits
  • Network mocking
  • Retry strategy
  • Test isolation
  • Independent test data

How do you run tests in parallel safely?

  • Separate test data
  • Unique users
  • Independent environments
  • Cleanup after execution

How do you integrate UI, API, and DB testing?

  1. Create data via API
  2. Validate in UI
  3. Validate in DB
  4. Clean up via API

selenium with python

 Certainly! I'll be happy to guide you through learning Selenium step by step. Selenium is a popular open-source framework used for auto...