✅ Решения

← К оглавлению урока

⚡ Кратко

Приоритет: role → label/placeholder/text → test_id → CSS/XPath. Проверки — через expect().

Часть 1. Ответы

  1. role → label/placeholder/text → test_id → CSS/XPath (крайний случай).
  2. «Ленивый» локатор ищет элемент заново при каждом действии, поэтому не «протухает» после перерисовки DOM; снимок из find_element устаревает.
  3. Strict mode violation — локатор нашёл >1 элемента. Устранение: уточнить (name=, .filter(), .nth()).
  4. get_by_text ищет элемент по тексту; .filter(has_text=...) сужает уже найденный набор (например, нужный listitem).
  5. expect(locator).to_have_count(n).

Часть 2. Локаторы — эталон

page.get_by_role("button", name="Оформить заказ")
page.get_by_label("Электронная почта")
page.get_by_role("link", name="Личный кабинет")
page.get_by_label("Запомнить меня")
page.locator(".product").nth(2)   # третий (индекс с 0)

Часть 3 и 4. Форма и список — эталон

# test_saucedemo.py
from playwright.sync_api import Page, expect

def test_login_and_cart(page: Page):
    page.goto("https://www.saucedemo.com/")
    page.get_by_placeholder("Username").fill("standard_user")
    page.get_by_placeholder("Password").fill("secret_sauce")
    page.get_by_role("button", name="Login").click()

    expect(page.get_by_text("Products")).to_be_visible()
    expect(page).to_have_url("https://www.saucedemo.com/inventory.html")

    items = page.locator(".inventory_item")
    expect(items).to_have_count(6)

    items.filter(has_text="Sauce Labs Backpack") \
         .get_by_role("button", name="Add to cart").click()
    expect(page.locator(".shopping_cart_badge")).to_have_text("1")
⚠️ Классы/тестиды реального сайта могут отличаться — проверяйте через инспектор/codegen. Здесь важен подход.