Chapter 3 – Playwright Core Building Blocks

Now that you’ve successfully installed Playwright and run your first test, it’s time to understand the core concepts that make Playwright work. In this chapter, we’ll break down Playwright’s architecture the Browser, Context, Page, and Locator.

Understanding these four parts is essential because they form the foundation for everything you’ll build with Playwright. Once you get comfortable with them, writing automation scripts will become intuitive.

Why these building blocks matter

Playwright’s structure is simple but powerful. It models how real browsers and users behave:

  • The Browser is the main application (like Chrome or Firefox).
  • A Browser Context is an isolated, independent browser session (like an incognito window).
  • A Page is a single tab in that browser context.
  • A Locator is how you find and interact with elements on that page.

With these four concepts, you can simulate any user behavior from opening multiple browser sessions to filling out forms, switching tabs, and testing user flows.

1. Browser

The browser object is Playwright’s connection to an actual browser engine (Chromium, Firefox, or WebKit). It’s responsible for launching, managing, and closing the browser instance.

Example:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: false }); // Start a visible browser
  await browser.close(); // Close it
})();

Key options:

OptionDescription
headless: trueRun browser in background (faster, default)
headless: falseRun browser visibly (for debugging)
slowMo: 100Slows down actions by 100ms for easier observation

2. Browser Context

A browser context represents an isolated session like a clean browser window without cookies, cache, or history. Each context behaves like a unique user.

Why is this useful?

Because you can run multiple contexts simultaneously without them interfering with each other. This means you can simulate multiple users logging into your app at the same time.

Example:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const context1 = await browser.newContext(); // User 1
  const context2 = await browser.newContext(); // User 2

  const page1 = await context1.newPage();
  const page2 = await context2.newPage();

  await page1.goto('https://example.com');
  await page2.goto('https://example.org');

  console.log(await page1.title()); // Example Domain
  console.log(await page2.title()); // Example Domain

  await browser.close();
})();

Each context acts like a separate browser window, completely independent.

3. Page

A page is a single browser tab. It’s where you’ll spend most of your time loading URLs, clicking buttons, typing into fields, and validating content.

Every Playwright test involves working with one or more pages inside a context.

Example:

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

test('navigate to Playwright homepage', async ({ page }) => {
  await page.goto('https://playwright.dev/');
  const title = await page.title();
  console.log('Page title:', title);
  await expect(page).toHaveTitle(/Playwright/);
});

The { page } object is provided automatically by the Playwright Test Runner, it’s your tab for that test.

4. Locator

A locator is how Playwright finds elements on a web page. It’s the equivalent of document.querySelector() in the browser, but smarter and more reliable.

Instead of acting immediately, locators wait for elements to appear, become stable, and be ready for interaction, this is one reason Playwright tests are so stable.

Example:

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

test('locator example', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Create a locator
  const getStartedButton = page.locator('text=Get started');

  // Click it
  await getStartedButton.click();

  // Verify navigation
  await expect(page).toHaveURL(/.*docs/);
});

Here, page.locator('text=Get started') finds the button by its visible text and clicks it. You can also use CSS or role-based selectors.

Locator strategies

Playwright supports many ways to find elements:

Selector TypeExampleDescription
Textpage.locator('text=Login')Finds element by visible text
CSSpage.locator('#username')Finds element by CSS selector
Rolepage.getByRole('button', { name: 'Submit' })Finds by accessible role (great for accessibility tests)
Test IDpage.locator('[data-testid="login-button"]')Best for stable automation tests
Chainedpage.locator('#form').locator('button')Finds nested elements

Putting it all together

Here’s a complete example showing all four building blocks working together:

const { chromium } = require('playwright');

(async () => {
  // Launch browser
  const browser = await chromium.launch({ headless: false });

  // Create two independent sessions
  const userContext = await browser.newContext();
  const adminContext = await browser.newContext();

  // Create pages (tabs)
  const userPage = await userContext.newPage();
  const adminPage = await adminContext.newPage();

  // Navigate to different sites
  await userPage.goto('https://example.com');
  await adminPage.goto('https://playwright.dev');

  // Locate and interact
  const getStarted = adminPage.locator('text=Get started');
  await getStarted.click();

  // Print titles
  console.log('User page title:', await userPage.title());
  console.log('Admin page title:', await adminPage.title());

  await browser.close();
})();

This small script launches a browser, creates two isolated sessions, opens different pages, interacts with elements, and prints titles showing Playwright’s versatility.

Common pitfalls to avoid

ProblemCauseSolution
TimeoutError: Element not foundLocator too earlyUse await page.waitForSelector() or rely on auto-waiting
Browser closed unexpectedlyForgot to await async actionsAdd await before Playwright methods
Elements overlap or moveAnimations or transitionsUse await expect(locator).toBeVisible() before clicking

Exercise

Task 1: Create a script that opens two different pages (e.g., Google and GitHub) and logs their titles.

Task 2: Use locators to click a visible link on one of the pages.

Bonus: Add a short delay between actions using slowMo when launching the browser to visualize your test.

Cheat Sheet

ConceptCode Example
Launch browserconst browser = await chromium.launch({ headless: false })
Create contextconst context = await browser.newContext()
Create pageconst page = await context.newPage()
Go to siteawait page.goto('https://example.com')
Create locatorconst button = page.locator('text=Login')
Click elementawait button.click()
Close browserawait browser.close()

Summary

In this chapter, you learned Playwright’s four essential building blocks:

  • Browser: The engine that runs everything.
  • Context: Isolated sessions for different users.
  • Page: Your working tab.
  • Locator: How you find and interact with elements.

These concepts form the foundation of every Playwright test you’ll ever write.