top of page

Understanding DOM and Locators in Playwright: A Beginner’s Guide to Stable Test Automation

Updated: Feb 18


If you are new to Playwright and modern web automation, one of the most important concepts you must understand is the DOM (Document Object Model).

Playwright does not interact with the page the way humans do. It does not “see” buttons, textboxes, or labels visually. Instead, it interacts with the structured HTML representation of the page — the DOM.


Before writing stable and reliable automation scripts, you must clearly understand:

  • What is a DOM tree?

  • What are element nodes, attribute nodes, and text nodes?

  • How does the browser represent a web page internally?

  • What is a locator?

  • Why do some selectors fail even when the UI looks correct?


In this post, we will:

  • Break down DOM terminology using a simple HTML example

  • Learn how to inspect and analyse elements using Chrome Developer Tools

  • Understand what makes a selector unique

  • Write a basic Playwright test to fill text inputs using identified CSS selectors


We will intentionally focus only on DOM clarity and locator fundamentals in this article. This forms the foundation for everything that follows in modern Playwright test automation.




Why DOM Knowledge Is a Prerequisite for Test Automation


Before we even talk about writing test cases, we must understand:

  • What is a web element?

  • How is it structured?

  • How does automation find it?

  • What is a locator?

  • Why do some tests fail even when the UI looks correct?

All these questions are directly related to DOM understanding.

If you understand DOM basics:

  • You will write stable locators

  • You will debug faster

  • You will avoid flaky tests

  • You will understand automation errors clearly


What Is the DOM?


DOM stands for Document Object Model.

When a browser loads HTML, it converts it into a tree-like structure called the DOM.


Let's take an example of this simple HTML file - simple.html

<!DOCTYPE html>
<html>
<head>
  <title>Simple Demo Page</title>
</head>
<body>
  <h1 id="title">Welcome</h1>
  <input type="text" id="username" placeholder="Enter your name">
  <button class="primary-btn">Login</button>
  <button class="secondary-btn">Cancel</button
</body>
</html>

This is loaded in the browser as


Let's give styling to buttons using class names :


!DOCTYPE html>
<html>
<head>
  <title>Simple Demo Page</title>
  <style>
    .primary-btn {
      background-color: orange;
      color: white;
      padding: 10px 20px;
      border: none;
      cursor: pointer;
      margin-right: 10px;
    }
    .secondary-btn {
      background-color: gray;
      color: white;
      padding: 10px 20px;
      border: none;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <h1 id="title">Welcome</h1>
  <input type="text" id="username" placeholder="Enter your name">
  <button class="primary-btn">Login</button>
  <button class="secondary-btn">Cancel</button>
</body>
</html>

which is loaded in the browser as

When a browser loads HTML, it converts it into a tree-like structure called the DOM.

You can simple paste your html code in this website to see how the DOM looks for this HTML page


The image above shows the live DOM structure generated by the browser from our simple HTML example.
The image above shows the live DOM structure generated by the browser from our simple HTML example.

What Happens When Browser Loads This Page?


The browser converts HTML into a tree structure:


Document
└── html
    ├── head
    │   ├── title → "Simple Demo Page"
    │   └── style
    │
    └── body
        ├── h1 id="title" → "Welcome"
        ├── input id="username"
        ├── button class="primary-btn" → "Login"
        └── button class="secondary-btn" → "Cancel"

Every item here is called a node. Before learning Playwright locators and test automation, it is essential to understand basic DOM terminology, as it forms the foundation for identifying and interacting with web elements.


1️⃣ Document Node (Root Owner)


The top-most node.

Document
  • Represents the entire webpage

  • Owns all elements

  • Starting point of automation



2️⃣ Element Nodes (HTML Tags)


These are actual HTML tags.

From our example:

<html>
<head>
<body>
<h1>
<input>
<button>

Element nodes define page structure.

Playwright interacts mostly with element nodes.

Example:

page.locator("button")

3️⃣ Attribute Nodes (Extra Information About Elements)


Attributes provide additional details about elements.

From our example:

id="title"
id="username" (unique identifier)
class="primary-btn" (for styling purpose)
class="secondary-btn"
placeholder="Enter your name"

Attributes help automation identify elements uniquely.

Example:

page.locator("#username")
page.locator(".primary-btn")

4️⃣ Text Nodes (Visible Content)


Text inside elements becomes text nodes.

Examples:

"Welcome"
"Login"
"Cancel"

Playwright validates text using assertions.

await expect(page.locator("h1")).toHaveText("Welcome")


How to View DOM in Chrome (Inspect Tool)


Understanding the DOM becomes easier using browser developer tools.


Hovering elements highlights them on screen. This shows exactly what automation interacts with.



What is a Locator?



Now that we understand the DOM structure, the next important concept in Playwright automation is a locator.

A locator is a way to identify and find a specific element in the DOM so that automation can interact with it.


Why Do We Need Locators?


A webpage contains many elements:

  • Multiple buttons

  • Multiple input fields

  • Multiple text elements

  • Multiple links


An automation tool must know exactly which element to interact with.

For example:

  • Which button should be clicked?

  • Which input field should receive text?

  • Which heading should be validated?

Locators solve this problem.


How Locators Work Internally


When you write:

page.locator("#username")

Playwright:

  1. Starts from the document node

  2. Searches the DOM tree

  3. Finds the matching element node

  4. Acts on that element


This is why understanding DOM structure is essential.


Types of Information Used by Locators


Locators typically use:

  • id attribute → #username

  • class attribute → .primary-btn

  • text content → "Login"

  • element type → button

  • roles and accessibility attributes

  • CSS selectors or XPath


All of these come from the DOM structure we just learned.


Example Using Our HTML Page

From our example:

<input type="text" id="username">
<button class="primary-btn">Login</button>

Possible locators:

#username
.primary-btn
button

Playwright uses these to find elements inside the DOM tree.


Why Locator Strategy Matters


If you look at the dom structure of the Automation Playground page or the Test Demo Store, you will notice that these applications closely resemble real-world web applications. Unlike our simple HTML example, identifying elements in such applications is not always straightforward.

This is why having a clear locator strategy becomes critical in UI test automation.


In real-world applications:

  • Pages often contain duplicate elements

  • Some attributes are dynamically generated

  • Certain elements may be hidden or conditionally rendered

  • The DOM structure may change frequently


Using poor or unstable locators can lead to flaky tests, unreliable automation, and frequent test failures.


Good automation practices always focus on using stable, unique, and maintainable locators to ensure reliable test execution.


Identifying Elements Before Using Playwright Locators


Before we start using Playwright’s built-in methods for locating or interacting with elements, it is important to understand how to identify elements in the browser uniquely.


As we discussed earlier, real-world applications contain:


  • multiple similar elements

  • dynamic attributes

  • nested DOM structures

  • hidden or duplicate components


Because of this complexity, we must first learn how to identify elements correctly using browser tools.


Using Chrome Inspect Tool and SelectorHub


To understand how elements are identified in real applications, we will use:

  • Chrome Developer Tools (Inspect) — to view the DOM structure(already seen)

  • SelectorHub — a browser extension that helps generate and validate selectors


SelectorHub helps us:

  • Identify unique selectors

  • Verify whether a selector matches one element or multiple elements

  • Choose stable attributes for automation


Practical Example — Identifying the First Name Field


We will use our Automation Playground page for practice:



Using Chrome Inspect and SelectorHub, we will:

  1. Inspect the First Name input field

  2. Analyse its attributes (id, class, name, placeholder, etc.)

  3. Identify a unique CSS selector for the element

  4. Verify the selector’s uniqueness


A CSS selector is a pattern used to locate elements based on attributes such as:

  • id

  • class

  • name

  • placeholder

  • element type


This selector will serve as the element’s unique identity for automation.


From Selector to Playwright Test


Once we identify a stable CSS selector, we will use it in our Playwright test to:

  • locate the element

  • interact with the element

  • validate its behavior


This shows the complete workflow:

Inspect Element → Identify Unique Selector → Use in Playwright → Automate Action

So let's first install the selector hub if you don't have it already


Install SelectorHub


  1. Open Chrome Web Store

  2. Search "SelectorHub"

  3. Install extension

  4. Open Inspect → SelectorHub tab appears



Using SelectorHub


  1. Open Inspect

  2. Click element

  3. SelectorHub suggests a locator

  4. Verify uniqueness


For example, if we need to reach the username input text field in our automationplayground page, through the inspect tool after highlighting, we can see:



To find a unique identifier, we can take the help of a selector hub, like below



Creating a Unique Identity for First Name Field

From the DOM, we observed:

<input name="first-name" id="input_comp-ml6m44v5" type="text">

We can identify the element using different attributes.


Not Reliable — Generic Selector

input

Matches many elements → not unique.


Risky — Dynamic ID

#input_comp-ml6m44v5

May be auto-generated and change → not stable.


Better — Meaningful Attribute

input[name="first-name"]

Create a Simple Playwright Test Using Our Identified Selector


Now that we have identified a unique CSS selector for the First Name field, let’s use it inside a Playwright test and input a value.

We will use this selector:

input[name="first-name"]

This means:

  • input → the element type

  • [name="first-name"] → an attribute filter

  • So Playwright finds the input element whose name attribute equals first-name


Playwright Test: Fill First Name Field


Create a test file inside your tests folder, for example:

tests/automationplayground-form.spec.ts

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

test('Fill form fields on Automation Playground', async ({ page }) => {
  await page.goto('https://www.anuradhaagarwal.com/automationplayground');

  // Fill First Name
  await page.locator('input[name="first-name"]').fill('Anuradha');

  // Optional: verify the value was entered
  await expect(page.locator('input[name="first-name"]')).toHaveValue('Anuradha');
});

Run the test:

npx playwright test

Hands-On Exercise: Locator for Feedback Textbox


Now that you know how we identified the First Name selector using Chrome Inspect and SelectorHub, try the same for:


Feedback field

Your task:

  1. Inspect each field in the browser

  2. Use SelectorHub to find a unique CSS selector

  3. Update the same Playwright test to fill values for all three fields

// Fill Feedback (replace selector based on what you identify)
await page.locator('YOUR_FEEDBACK_SELECTOR').fill('This is my feedback message.');

That must be easy and would have added output something like below

// Fill Textbox feedback
  await page.locator("textarea[placeholder='How can we improve?']").fill("keep working with your best..")
  await expect(page.locator("textarea[placeholder='How can we improve?']")).toHaveValue("keep working with your best..")

Surprisingly if you try to find css selector for the email field with input[name='email'], selectorhub will show 2 elements:

Can you guess where the second element with the same tag and attribute

Use the Elements Tab Search to find the other email


  1. Go to the Elements tab

  2. Press:

Ctrl + F
  1. Type:

input[name='email']

Chrome will jump to the first match.

Press Enter again to go to the next match. You will find this highlighted.



Clearly, this is not a unique CSS selector for the email field. Before we find which is the other email, let's find a unique CSS selector for this email input field by trying other attribute filters.

I can't use IDs, they seem to be dynamic in nature. I can try placeholder and it works:


Now modify your Playwright script to input a value in the email field, and also add an assertion


Final code so far

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

test('Test fields on Automation Playground', async ({ page }) => {
    await page.goto('https://www.anuradhaagarwal.com/automationplayground');

    // Fill First Name
    await page.locator('input[name="first-name"]').fill('Anuradha');

    // Optional: verify the value was entered
    await expect(page.locator('input[name="first-name"]')).toHaveValue('Anuradha');

    //Fill email field
    await page.locator("input[placeholder='example@domain.com']").fill("anuradha.learn@gmail.com")
    await expect(page.locator("input[placeholder='example@domain.com']")).toHaveValue("anuradha.learn@gmail.com")

    // Fill Textbox feedback

  // await page.locator("textarea[placeholder='How can we improve?']:visible").fill("keep working with your best..")
    // const feedback = page.locator("textarea[placeholder='How can we improve?']")
    // console.log("Feedback value:", await feedback.inputValue());
    // await expect(page.locator("textarea[placeholder='How can we improve?']")).toHaveValue("keep working with your best..")
//press sequential and press key method
    const feedback = page.locator("textarea[placeholder='How can we improve?']")
    await feedback.pressSequentially('Hello'); // Types instantly
    await feedback.pressSequentially('World', { delay: 100 });
    await feedback.press('Enter'); // Types slower, like a user
});


At this stage, you should now clearly understand:


  • How a browser converts HTML into a DOM tree

  • The difference between document, element, attribute, and text nodes

  • How to inspect elements using Chrome Developer Tools

  • Why unique selectors are critical for stable automation

  • How Playwright uses those selectors to interact with text input fields


This is not just theory — this is the backbone of reliable test automation.

Many beginners jump directly into framework features and built-in locator methods without understanding what is happening underneath. That often leads to fragile tests, confusing errors, and unnecessary debugging.

By mastering DOM structure and locator fundamentals first, you are building strong automation thinking — not just learning syntax.

In the next post, we will move deeper into CSS selector fundamentals and UI controls, and start building more structured Playwright tests for real-world elements like radio buttons, checkboxes, dropdowns, and buttons on our demo-store.


And now that your DOM foundation is solid, everything ahead will feel much clearer and more powerful.

Comments


Never Miss a Post. Subscribe Now!

Thanks for submitting!

©anuradha agarwal

    bottom of page