🎯 Day 8 - Advanced Locators, Dropdowns, Checkboxes & Assertions

Mastering complex element interactions and validations

🕒 Topics to Cover

1. `.first()` vs `.nth()` locators

Understanding element selection strategies

2. `.allTextContents()`

Fetching multiple values efficiently

3. Dropdown handling

Using `.selectOption()` method

4. Debug with `page.pause()`

Interactive debugging techniques

5. Checkbox/Radio handling

State management and validation

6. Advanced Assertions

Truthy/Falsy validations

🔹 Real-time QA Scenarios

1. `.first()` vs `.nth()` Locators

// Selecting first email field await page.locator('.js-input-column input').first().fill("qa_first@example.com"); // Selecting specific field by index await page.locator('.js-input-column input').nth(0).fill("qa_nth0@example.com");
💡 QA Angle: Selecting the first text box on signup page vs picking specific field.

👉 Interview Q: What's the difference between `.first()`, `.nth(0)`, and `.all()`?

Answer:
• .first(): Selects the first element in a collection. More semantic and readable.
• .nth(0): Selects the element at index 0 (first element). Functionally same as .first().
• .all(): Returns all matching elements as an array of locators.

Key Difference: .first() and .nth(0) return a single locator, while .all() returns an array of locators.

2. Extracting Multiple Titles

// Get all product titles const allTitles = await page.locator('.product-title a').allTextContents(); console.log(allTitles); // Validate no blank titles const hasBlankTitles = allTitles.some(title => !title.trim()); await expect(hasBlankTitles).toBeFalsy();
💡 QA Angle: Collect all product names on homepage → validate none are blank/duplicates.

👉 Interview Q: What's the difference between `.textContent()` and `.allTextContents()`?

Answer:
• .textContent(): Works with a single element and returns a string.
• .allTextContents(): Works with multiple elements and returns an array of strings.

Example:
const singleText = await page.locator('.title').textContent(); // Returns: "Product Name"
const allTexts = await page.locator('.title').allTextContents(); // Returns: ["Product 1", "Product 2", "Product 3"]

3. Dropdown Handling

// Change currency dropdown const dropdown = page.locator("select#currency-selector"); await dropdown.selectOption("INR"); // Verify price updates const priceElement = page.locator('.product-price').first(); await expect(priceElement).toContainText("₹");
💡 QA Angle: Change site currency from default USD → INR, verify price update.

👉 Interview Q: What happens if you use `.fill()` instead of `.selectOption()` on a <select> element?

Answer:
Using .fill() on a select element will:
• Type the text into the field
• NOT change the selected option
• May cause test failures

Correct approach: Always use .selectOption() for dropdowns to properly change the selection.

4. Debug Pause

// Pause execution for debugging await page.pause(); // Continue with form interaction await page.locator('#email1').fill("test@example.com");
💡 QA Angle: Stop test mid-way, inspect product details form in PrestaShop.

👉 Interview Q: How is `page.pause()` different from running with `PWDEBUG=1`?

Answer:
• page.pause(): Pauses execution at a specific point in your test code.
• PWDEBUG=1: Runs the entire test in debug mode with step-by-step execution from start.

Use cases:
• Use page.pause() when you want to inspect a specific moment
• Use PWDEBUG=1 when you want to debug the entire test flow

5. Checkbox/Radio Handling

// Check newsletter subscription const newsletter = page.locator('#newsletter-checkbox'); await newsletter.check(); await expect(newsletter).toBeChecked(); // Uncheck if needed await newsletter.uncheck(); await expect(newsletter).not.toBeChecked(); // Radio button selection await page.locator('input[name="gender"][value="female"]').check(); await expect(page.locator('input[name="gender"][value="female"]')).toBeChecked();
💡 QA Angle: On checkout page, check/uncheck "Subscribe to Newsletter".

👉 Interview Q: What's the difference between `isChecked()`, `toBeChecked()`, and `check()`?

Answer:
• isChecked(): Returns the current state as a boolean (true/false).
• toBeChecked(): An assertion that validates the element is checked.
• check(): Action that changes the state by checking the element.

Example:
const state = await checkbox.isChecked(); // Returns: true/false
await expect(checkbox).toBeChecked(); // Assertion
await checkbox.check(); // Action

6. Assertions with Falsy/Truthy

// Check promo code field is hidden initially const promoCode = page.locator('#promo-code'); await expect(promoCode).toBeFalsy(); // field should not exist initially // Show promo code field after certain action await page.locator('#show-promo').click(); await expect(promoCode).toBeVisible(); // Validate form submission const isFormValid = await page.locator('#terms-checkbox').isChecked(); await expect(isFormValid).toBeTruthy();
💡 QA Angle: Check that promo code box is hidden until a certain step.

👉 Interview Q: When would you use `toBeFalsy()` vs `toBeHidden()`?

Answer:
• toBeFalsy(): Checks if an element doesn't exist or is null/undefined.
• toBeHidden(): Checks if an element exists but is not visible (display: none, visibility: hidden, etc.).

Use cases:
• Use toBeFalsy() when testing if an element should not exist in DOM
• Use toBeHidden() when testing if an element exists but is hidden by CSS

🎯 Practice Exercises

Exercise 1: Multi-field Form Validation

Create a test that:

  • Fills the first email field using `.first()`
  • Fills the second email field using `.nth(1)`
  • Selects a country from dropdown
  • Checks the newsletter checkbox
  • Validates all fields are properly filled

Exercise 2: Currency Conversion Test

Create a test that:

  • Changes currency to INR using dropdown
  • Extracts all product prices using `.allTextContents()`
  • Validates all prices show ₹ symbol
  • Changes to EUR and validates € symbol

Exercise 3: Form State Management

Create a test that:

  • Validates promo code field is initially hidden
  • Triggers promo code field visibility
  • Fills and validates promo code
  • Tests radio button selection
  • Uses `page.pause()` for debugging