Skip to content

📘 Playwright

Features of Playwright

  • Free | Open Source
  • Multi-Browser | Multi-Language | Multi-OS
  • Easy Setup and Configuration
  • Functional | API | Accessibility testing
  • Built-in Reporters | Custom Reporters
  • CI CD | Docker support
  • Recording | Debugging | Explore selectors
  • Parallel testing
  • Auto-wait
  • Built-in assertions | Less Flaky tests
  • Test retry, logs, screenshots, videos
  • Multi-tab and multi-window
  • Frames | Shadow DOM
  • Emulate mobile devices, geolocations
  • Test parameterization
  • Fast

Primary Purpose

  • node - JavaScript runtime environment; executes JavaScript code.
  • npm (Node Package Manager) - Package manager; installs, manages, and publishes project dependencies.
  • npx (Node Package Execute) - Package runner; executes packages and their binaries directly without permanent installation.

✅ Phase 1: TypeScript Basics

Run typscript files with command

npx ts-node -P tsconfig.node.json ./TypescriptBasics/FileAndFoldersCRUD/index.ts

🔹 Variables & Data Types

  • number
  • string
  • boolean
  • null & undefined
  • any & unknown
  • Arrays
  • Tuple
  • Objects / Dictionary (Record<string, any>)

🔹 Files and Folders CRUD

Ref: TypescriptBasics/FileAndFoldersCRUD/index.ts

🔹 Conditions & Loops

  • if / else
  • switch
  • for loop
  • while / do-while
  • for...of
  • for...in

Ref: TypescriptBasics/ConditionsAndLoops.ts

🔹 Functions & Classes

  • Function declaration
  • Arrow functions
  • Parameters & return types
  • Classes & constructors
  • Access modifiers (public, private, protected)
  • Interfaces & Types

Ref: TypescriptBasics/FunctionsAndClasses.ts

🔹 Object-Oriented Programming

  • Objects
  • Inheritance
  • Polymorphism
  • Encapsulation

🔹 Exception Handling

  • try / catch / finally
  • Throwing errors
  • Custom errors

Ref: TypescriptBasics/ExceptionHandling.ts

🔹 Dependency Management

  • npm & npx
  • package.json
  • devDependencies
  • tsconfig.json
topic explanation
npm Node Package Manager used to install, manage, and version project dependencies.
npx Executes packages directly without globally installing them.
package.json Project configuration file that defines dependencies, scripts, and metadata.
devDependencies Packages needed only during development (e.g., testing, TypeScript, build tools).
tsconfig.json TypeScript configuration file that controls how TypeScript compiles your code.

✅ Phase 2: Playwright Fundamentals

🔹 Setup & Configuration

  • Install Playwright
  • Playwright project structure
  • playwright.config.ts
    const config: PlaywrightTestConfig = {
      testMatch: ["tests/recorded.test.ts"],
      use: {
        headless: false,
        screenshot: "only-on-failure",
        video: "retain-on-failure",
      },
      retries: 2,
      reporter: [["dot"], ["json", {
        outputFile: "jsonReports/jsonReport.json"
      }], ["html", {
        open: "never"
      }]]
    }
    
  • Browser configuration

🔹 Writing Tests

  • test()
  • expect()
    Ref: https://playwright.dev/docs/test-assertions
  • Test structure
  • Debugging tests

when we run tests in debug mode, it runs in headed mode

  • page.pause()

🔹 Assertions

  • Visibility assertions
  • Text assertions
  • URL assertions
  • Attribute checks
  • Soft vs Hard assertions

🔹 Reporting & Logging

  • HTML reports
  • Screenshots on failure
  • Video recording
  • Trace viewer
  • Console logging

🔹 Setup & Teardown

  • beforeAll
  • beforeEach
  • afterEach
  • afterAll

Ref: tests/Hooks/File-Level Hooks.spec.ts

Key takeaways

Hook Throws What happens to tests in the file
beforeAll Throws All tests skipped / not executed; first test may briefly appear in report depending on reporter
beforeEach Throws Only current test fails; other tests run normally
afterEach Throws Current test may fail; other tests run normally
afterAll Throws Last test marked failed; other tests already run normally
---
  • Test fixtures

A wrapper around the test function where you control what runs before and after the test.

alt text


Closer comparison

setup statements;
try {
   runTest();
} finally {
   runYourTeardown();
}

✅ Phase 3: Test Management

🔹 Tagging

  • @smoke
  • @regression
  • @sanity

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

test('login test @smoke @regression @sanity', async ({ page }) => {
  // test code
});
#Run only smoke tests:
npx playwright test --grep @smoke

#Run everything except smoke:
npx playwright test --grep-invert @smoke

🔹 Parameterization

  • test.describe()
  • test.each()
  • Data-driven testing

Generate Separate Parameterized Tests

✔ This creates 3 independent tests
✔ Each can run on a different worker

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

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

users.forEach(({ username, password }) => {
  test(`login test for ${username}`, async ({ page }) => {
    await page.goto('https://example.com/login');
    await page.fill('#username', username);
    await page.fill('#password', password);
    await page.click('#login');

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



### 🔹 Skip tests
- Skip run based on specific browser.  Below skip logic tested and works as expected 
```typescript
test('Iterate over table and print 3 column value when first 2 columns matches with the given value', async({page}, testInfo)=> {

  //condition to run only on google chrome browser. 
  test.skip(
    testInfo.project.name !== 'Google Chrome',
    'Runs only in Google Chrome'
  );
  } )
- Skip run on CI tool. ✅ Below skip logic tested on Github and works as expected
test('page title', async () => {
  //skip test only on CI run  
  test.skip(process.env.CI === 'true', 'Skipping in CI');

  let browser = await chromium.connectOverCDP('http://localhost:9222');

🔹 Execute tests

Command Comments
npx playwright tests To run alls tests within playwright folder
npx playwright test tests/tests.spec.ts -g "testcase name/partial name" To run specific testcase

  • how to run tests against different version of same browser

🔹 Parallel Execution

  • Workers
  • Parallel execution
  • Serial execution

By default, Playwright runs test files in parallel.

//If tests are inside the same file and you want them parallel:
test.describe.configure({ mode: 'parallel' });

const users = ['user1', 'user2', 'admin'];

for (const user of users) {
  test(`login test for ${user}`, async ({ page }) => {
    // test logic
  });
}
test.describe.configure({ mode: 'parallel' });

const testData = require('./users.json');

for (const data of testData) {
  test(`@smoke login for ${data.username}`, async ({ page }) => {
    // test logic
  });
}
npx playwright test --workers=4
Workers hardware requirement 
1 Worker needs 1 logical CPU and 2 GB RAM

🔹 CI/CD Integration

  • GitHub Actions
  • Jenkins
  • GitLab CI
  • Headless execution

✅ Phase 4: Browser Automation

🔹 Locators

  • getByRole
  • getByText
  • getByTestId
  • CSS selectors
  • XPath

🔹 User Actions

  • Click
  • Type
  • Keyboard actions
  • Mouse actions
  • Drag & Drop
  • File upload

🔹 Web Handling

  • Dropdowns
  • Checkboxes
  • Radio buttons
  • Auto-suggestions

🔹 Data Retrieval

  • Get text
  • Get attributes
  • Tables

🔹 Browser Events

  • Alerts
  • Frames
  • Windows
  • Popups

🔹 Cheat sheet

Element Best Locator Common Actions Retrieve Value Assertions
Button getByRole('button', { name: 'Submit' }) click() dblclick() hover() innerText() toBeVisible() toBeEnabled() toHaveText()
Textbox / Input getByRole('textbox', { name: 'First Name' }) fill() type() clear() inputValue() toHaveValue() toBeEditable()
Textarea locator('textarea') fill() inputValue() toHaveValue()
Checkbox getByRole('checkbox', { name: 'Accept' }) check() uncheck() isChecked() toBeChecked()
Radio Button getByRole('radio', { name: 'Male' }) check() isChecked() toBeChecked()
Dropdown (select) locator('select#country') selectOption() inputValue() / locator('option:checked').innerText() toHaveValue()
Link getByRole('link', { name: 'Home' }) click() getAttribute('href') toHaveAttribute()
Table Rows locator('table tbody tr') nth(i) count() allTextContents() toHaveCount()
Table Cell row.locator('td').nth(i) innerText() toContainText()
Div / Span locator('#id') click() hover() innerText() toHaveText() toContainText()
Image locator('img') getAttribute('src') toHaveAttribute()
File Upload locator('input[type=file]') setInputFiles() inputValue() toHaveValue()
Dialog (Alert) page.on('dialog', handler) accept() dismiss() dialog.message()
Page page goto() reload() url() title() toHaveURL() toHaveTitle()

🪟 Browser Window Handling

Scenario Code
New browser context const context = await browser.newContext();
New window manually const newPage = await context.newPage();
Get window title await page.title();
Get window URL page.url();
Close window await page.close();

🖼 Frames / iFrames

Scenario Code
Get frame by name const frame = page.frame({ name: 'frameName' });
Get frame by URL const frame = page.frame({ url: /partial-url/ });
Locate inside iframe (recommended) const frameLocator = page.frameLocator('#frameId');
Click inside iframe await frameLocator.locator('button').click();
Fill inside iframe await frameLocator.locator('#input').fill('text');

✅ Phase 5: Framework Design

🔹 Page Object Model

  • Page classes
  • Reusable methods

🔹 Test Data Management

  • JSON
  • Environment variables
  • .env file

🔹 Screenshots & Videos

  • On failure
  • Manual screenshots

✅ Phase 6: Advanced Topics

🔹 Authentication

  • Storage state
  • Token login

🔹 Network Handling

  • API mocking
  • Request interception

🔹 Performance

  • Page load metrics

🔹 Accessibility

  • WCAG checks

🔹 Cross Browser

  • Chromium
  • Firefox
  • WebKit

✅ Phase 7: Best Practices

  • Use data-testid
  • Avoid hard waits
  • Clean code
  • Reusable components
  • Maintainable framework

Practise sites

https://ecommerce-playground.lambdatest.io/index.php?route=account/login

Certification

2) How to use functions and selectors

const browser = await chromium.launch({
  headless: false
});

const context = await browser.newContext();
const page = await context.newPage();


// Navigate to homepage
await page.goto("https://ecommerce-playground.lambdatest.io/");

// Hover over 'My account' dropdown
await page.hover("//a[@data-toggle='dropdown']/span[contains(.,'My account')]");

// Click Login button
// await page.click("text=Login")
await page.click("input[value='Login']");

// Fill login form
await page.fill("input[name='email']", "koushik350@gmail.com");
await page.fill("input[name='password']", "Pass123$");
await page.click("input[value='Login']");

// Wait for 5 seconds
await page.waitForTimeout(5000);

// Create a new browser context
const newContext = await browser.newContext();

// Open a new page in the new context
const newPage = await newContext.newPage();
await newPage.goto("https://ecommerce-playground.lambdatest.io/index.php?route=account/account");

// Wait for 5 seconds
await newPage.waitForTimeout(5000);

3) Playwright Testing Features

  • playwright.config.ts
    const config: PlaywrightTestConfig = {
      testMatch: ["tests/recorded.test.ts"],
      use: {
        headless: false,
        screenshot: "only-on-failure",
        video: "retain-on-failure",
        timeout: 30000, // Timeout for each test in milliseconds (30s)
      },
      retries: 2,
      reporter: [["dot"], ["json", {
        outputFile: "jsonReports/jsonReport.json"
      }], ["html", {
        open: "never"
      }]]
    }
    
  • Auto wait
    https://playwright.dev/docs/actionability

4) How to Handle Alerts and Dropdowns

page.on("dialog", async (alert) => {
  const text = alert.defaultValue();
  console.log(text);
  await alert.accept("koushik");
});

await page.locator("button:has-text('Click Me')").nth(2).click();
// expect(page.locator("id=confirm-demo")).toContainText("Cancel!");
expect(page.locator("id=prompt-demo")).toContainText("'koushik'");
await page.selectOption("#select-demo", {
  // label: "Tuesday"
  // value: "Friday"
  index: 5
})


await selectCountry();
async function selectCountry() {
  await page.click("#countryspan");
  await page.locator("ul#select2-country-results")
    .locator("li", {
      hasText: "India"
    }).click();
}

Ref: https://github.com/ortoniKC/playwright-ts-lambdatest