Advanced Locator Operations

Loading concept...

🎯 Playwright Advanced Locator Operations

The Treasure Hunter’s Toolkit

Imagine you’re a treasure hunter in a huge museum. You need to find specific artifacts. Sometimes the artifact is easy to find. But sometimes, you need special tools to narrow down exactly which treasure you want.

Playwright locators are like your treasure-hunting toolkit. Today, we learn the advanced tools that help you find elements with laser precision!


đź”— Locator Chaining: Following the Trail

What Is It?

Think of a trail of breadcrumbs. Each breadcrumb leads to the next, until you reach the treasure.

Locator chaining means: Start somewhere, then go deeper step by step.

Simple Example

Imagine a house with many rooms. Inside one room, there’s a toy box. Inside the toy box, there’s a red ball.

// Find the room first
const room = page.locator('.bedroom');

// Then find the toy box inside that room
const toyBox = room.locator('.toy-box');

// Then find the red ball inside
const ball = toyBox.locator('.red-ball');

Real World Use

// Find a table, then a specific row,
// then a button in that row
const table = page.locator('table.users');
const row = table.locator('tr:has-text("John")');
const editBtn = row.locator('button.edit');

await editBtn.click();

Why It’s Powerful

  • You break down complex searches into simple steps
  • Each step narrows your search
  • Makes your code easy to read and debug
graph TD A[Page] --> B[Table] B --> C[Row with "John"] C --> D[Edit Button] style D fill:#4CAF50,color:white

🔍 The .filter() Method: Be Picky!

What Is It?

You have a basket of fruits. You want only red apples. The .filter() method helps you pick exactly what you want.

How It Works

The .filter() method takes a locator and keeps only the ones that match your conditions.

Example: Filter by Text

// Find all buttons
const buttons = page.locator('button');

// Keep only the one that says "Submit"
const submitBtn = buttons.filter({
  hasText: 'Submit'
});

Example: Filter by Child Element

// Find all product cards
const cards = page.locator('.product-card');

// Keep only cards that have a sale badge
const saleCards = cards.filter({
  has: page.locator('.sale-badge')
});

Example: Filter by NOT Having

// Find all items
const items = page.locator('.item');

// Keep items WITHOUT a "sold out" label
const available = items.filter({
  hasNot: page.locator('.sold-out')
});

Quick Reference

Filter Option What It Does
hasText Matches text content
has Must contain element
hasNot Must NOT contain element

📍 Locator Positioning Methods: Neighbors & Family

What Is It?

Sometimes you want to find something based on its neighbors. Like finding your friend’s house because it’s next to the park.

.first() - The First One

// Get the first button on the page
const firstBtn = page.locator('button').first();

.last() - The Last One

// Get the last item in a list
const lastItem = page.locator('li').last();

.nth(index) - Pick by Position

// Get the third image (index starts at 0)
const thirdImg = page.locator('img').nth(2);

Family Tree Diagram

graph TD A[List of Items] --> B["first#40;#41; → Item 1"] A --> C["nth#40;1#41; → Item 2"] A --> D["nth#40;2#41; → Item 3"] A --> E["last#40;#41; → Item 4"] style B fill:#2196F3,color:white style E fill:#FF9800,color:white

Pro Tip

Avoid using position methods when you can use better filters. Positions can change if the page changes!


âž• The .and() Method: Both Must Be True

What Is It?

Imagine you’re looking for a friend who is tall AND has red hair. Both conditions must be true.

How It Works

.and() combines two locators. The element must match both.

Example

// Find a button
const button = page.locator('button');

// That is also visible
const visibleBtn = button.and(
  page.locator(':visible')
);

// That also has specific class
const submitBtn = page.locator('button').and(
  page.locator('.primary')
);

Real World Use

// Find an input field
const input = page.locator('input');

// That is ALSO a required field
const required = input.and(
  page.locator('[required]')
);

await required.fill('Hello');

Visual Explanation

graph LR A[Locator A] --> C{AND} B[Locator B] --> C C --> D[Must Match Both!] style C fill:#9C27B0,color:white style D fill:#4CAF50,color:white

🔀 The .or() Method: Either One Works

What Is It?

Now you’re looking for someone who is a teacher OR a doctor. Either condition is fine!

How It Works

.or() combines two locators. The element can match either one.

Example

// Find submit button OR save button
const saveOrSubmit = page.locator('button.submit')
  .or(page.locator('button.save'));

await saveOrSubmit.click();

Real World Use

// Some sites use different selectors
// for mobile vs desktop
const menu = page.locator('.mobile-menu')
  .or(page.locator('.desktop-menu'));

// Clicks whichever exists!
await menu.click();

Visual Explanation

graph LR A[Locator A] --> C{OR} B[Locator B] --> C C --> D[Match Either One] style C fill:#FF5722,color:white style D fill:#4CAF50,color:white

When To Use .or()

  • Different pages have different layouts
  • Handling mobile vs desktop elements
  • Fallback options for clicking

🔢 The .count() Method: How Many?

What Is It?

Before picking apples, you want to know: How many apples are there?

How It Works

.count() returns the number of matching elements.

Example

// How many products are shown?
const products = page.locator('.product');
const total = await products.count();

console.log(`Found ${total} products!`);

Use Cases

// Check if search has results
const results = page.locator('.result');
const count = await results.count();

if (count === 0) {
  console.log('No results found!');
} else {
  console.log(`Found ${count} results`);
}

Loop Through All Matches

const items = page.locator('.item');
const count = await items.count();

for (let i = 0; i < count; i++) {
  const text = await items.nth(i).textContent();
  console.log(`Item ${i}: ${text}`);
}

Remember

  • .count() is async - always use await
  • Returns 0 if nothing matches
  • Great for validating search results

⚠️ Strict Mode: One and Only One

What Is It?

Strict mode is like saying: “I expect exactly one answer. If there are more or none, tell me!”

How It Works

By default, Playwright locators are strict. When you try to interact with a locator that matches multiple elements, Playwright throws an error.

The Strict Rule

// âś… GOOD: Only one element matches
await page.locator('#unique-button').click();

// ❌ ERROR: Multiple elements match!
// This will fail in strict mode
await page.locator('button').click();
// Error: strict mode violation

Why Strict Mode Exists

Imagine clicking a button, but there are 3 buttons that match. Which one gets clicked? That’s confusing!

Strict mode protects you from accidental clicks on wrong elements.

Working With Multiple Elements

When you intentionally want multiple elements:

// Get all buttons (returns locator,
// no strict violation)
const buttons = page.locator('button');

// Use .first(), .last(), or .nth()
await buttons.first().click();

// Or use .count() and loop
const count = await buttons.count();

Checking Before Acting

const btn = page.locator('.submit-btn');

// Check count first
if (await btn.count() === 1) {
  await btn.click();
} else if (await btn.count() > 1) {
  // Handle multiple matches
  await btn.first().click();
} else {
  console.log('Button not found!');
}

Visual Summary

graph TD A[Locator Action] --> B{How many matches?} B -->|0| C[❌ Error: Not Found] B -->|1| D[✅ Success!] B -->|2+| E[❌ Error: Strict Mode] style D fill:#4CAF50,color:white style C fill:#f44336,color:white style E fill:#f44336,color:white

🎯 Putting It All Together

Combo Example

Let’s use all the tools in one search!

// Start with a table
const table = page.locator('table.orders');

// Chain: find rows in the table
const rows = table.locator('tr');

// Filter: only rows with "Pending" status
const pending = rows.filter({
  has: page.locator('.status:has-text("Pending")')
});

// Count them
const count = await pending.count();
console.log(`${count} pending orders`);

// Get the first one's action button
const firstPending = pending.first();
const actionBtn = firstPending.locator('.action');

// Or use .and() for extra safety
const safeBtn = actionBtn.and(
  page.locator('[data-action="approve"]')
);

await safeBtn.click();

Cheat Sheet

Method Purpose Example
Chaining Go deeper parent.locator(child)
.filter() Be picky .filter({hasText: 'X'})
.first() First match .first()
.last() Last match .last()
.nth(n) Specific position .nth(2)
.and() Both conditions a.and(b)
.or() Either condition a.or(b)
.count() How many await loc.count()
Strict Mode Expect exactly 1 (default behavior)

🏆 You Did It!

You now have the complete treasure hunter toolkit! You can:

  • Chain locators to follow a trail
  • Filter to be super picky
  • Use positioning to grab by order
  • Combine with and/or for complex searches
  • Count before you act
  • Understand strict mode safety

Go forth and locate elements like a pro! 🚀

Loading story...

No Story Available

This concept doesn't have a story yet.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

Interactive Preview

Interactive - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Interactive Content

This concept doesn't have interactive content yet.

Cheatsheet Preview

Cheatsheet - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Cheatsheet Available

This concept doesn't have a cheatsheet yet.

Quiz Preview

Quiz - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Quiz Available

This concept doesn't have a quiz yet.