Первый взгляд на серию «Последний выпуск» — Автоматическое тестирование Python + Playwright — 6-элементный метод позиционирования — Часть 2
Первый взгляд на серию «Последний выпуск» — Автоматическое тестирование Python + Playwright — 6-элементный метод позиционирования — Часть 2

1. Введение

В предыдущей статье в основном объяснялись теоретические базовые знания о некоторых наиболее часто используемых методах позиционирования с использованием Playwright для позиционирования элементов в нашей повседневной работе, а также о том, при каких обстоятельствах их рекомендуется использовать. Сегодня в этой статье мы объясним и поделимся некоторыми позициями, которые редко используются или редко встречаются в повседневной жизни, но мы должны знать об этом, когда сталкиваемся с этим. Как говорится: не паникуйте, когда у вас в руке еда.

2. Позиционирование тени – Shadow DOM

При веб-автоматизации некоторые элементы находятся под теневым корневым узлом, что делает невозможным их обнаружение с помощью XPath в драматурге.

Тег теневого корня, показанный выше, на самом деле является теневым DOM. Что же такое теневой DOM?

Это технология инкапсуляции страниц во внешнем интерфейсе. ShadowDOM можно рассматривать как «DOM в DOM» (можно рассматривать как скрытый DOM).

Это независимое дерево DOM со своими элементами и стилями, полностью изолированное от исходного документа DOM.

ShadowDOM должен быть прикреплен к элементу HTML для хранения элементаshadowDOM. Мы можем назвать его хост-элементом. В HTML5 существует множество стилей тегов, реализованных через ShadowDOM.

Например: поле выбора даты, тег воспроизведения аудио и тег воспроизведения видео имеют свои собственные стили (хотя этот вид инкапсуляции хорош для внешней разработки, наши тестировщики столкнутся с некоторыми проблемами при автоматическом веб-рендеринге, метка ShadowDOM; в не может быть найден).

По умолчанию все локаторы в Playwright используют элементы из Shadow DOM. Исключения:

  • Позиционирование через XPath не проникнет в теневой корень.
  • Теневые корни закрытого режима не поддерживаются.

Например: следующие образцы и пользовательские веб-компоненты:

Язык кода:javascript
копировать
<x-details role=button aria-expanded=true aria-controls=inner-details>
  <div>Title</div>
  #shadow-root
    <div id=inner-details>Details</div>
</x-details>

Вы можете расположить его так же, как если бы теневого корня вообще не существовало.

Чтобы нажать :<div>Details</div>

Язык кода:javascript
копировать
page.get_by_text("Details").click()

Чтобы нажать :<x-details>

Язык кода:javascript
копировать
page.locator("x-details", has_text="Details" ).click()

Обязательно укажите текст «Подробнее».,Пожалуйста, сделайте следующее:<x-details>

Язык кода:javascript
копировать
expect(page.locator("x-details")).to_contain_text("Details")

3. Расположение фильтра – Фильтрация

Например, следующая структура DOM, в которой мы хотим нажать кнопку «Купить» на второй карточке продукта. У нас есть несколько вариантов фильтрации локаторов, чтобы получить правильный локатор.

3.1 Фильтрация текста

Локаторы можно фильтровать по тексту с помощью метода locator.filter(). Он будет искать определенную строку где-то внутри элемента, возможно, в элементе-потомке, без учета регистра. Вы также можете передать регулярное выражение.

1. Используйте текст

Язык кода:javascript
копировать
page.get_by_role("listitem").filter(has_text="Product 2").get_by_role(
    "button", name="Add to cart"
).click()

2. Используйте регулярные выражения

Язык кода:javascript
копировать
page.get_by_role("listitem").filter(has_text=re.compile("Product 2")).get_by_role(
    "button", name="Add to cart"
).click()

3. Фильтровать по тексту

Язык кода:javascript
копировать
# 5 in-stock items
expect(page.get_by_role("listitem").filter(has_not_text="Out of stock")).to_have_count(5)
3.2 Фильтрация детей/потомков

Локаторы поддерживают возможность выбирать только элементы с потомками или без них, которые соответствуют другим локаторам. Таким образом, вы можете фильтровать по любому другому локатору, например locator.get_by_role(), locator.get_by_test_id(), locator.get_by_text() и т. д.

1. Используйте подразделы

Язык кода:javascript
копировать
page.get_by_role("listitem").filter(
    has=page.get_by_role("heading", name="Product 2")
).get_by_role("button", name="Add to cart").click()

2. Используйте утверждения карточек товаров, чтобы убедиться, что существует только один

Язык кода:javascript
копировать
expect(
    page.get_by_role("listitem").filter(
        has=page.get_by_role("heading", name="Product 2")
    )
).to_have_count(1)

3. Фильтровать по элементам, у которых нет подходящих внутренних элементов.

Язык кода:javascript
копировать
expect(
    page.get_by_role("listitem").filter(
        has_not=page.get_by_role("heading", name="Product 2")
    )
).to_have_count(1)

Постучите по доске! ! ! ! Примечание. Внутренние локаторы соответствуют внешнему локатору, а не корню документа.

3.3 Фильтрация по совпадению с другим позиционированием

Метод locator.and_() сужает область действия существующего локатора, сопоставляя другие локаторы. Например, вы можете объединить page.get_by_role() и page.get_by_title() для сопоставления по роли и заголовку.

Язык кода:javascript
копировать
button = page.get_by_role("button").and_(page.getByTitle("Subscribe"))

4. Поиск ссылок

Вы можете объединить методы, создающие локаторы (например, page.get_by_text() или locator.get_by_role()), чтобы сузить поиск до определенной части страницы.

В этом примере,Мы сначалапроходитьопределить свою роль:listitem чтобы создать файл с именем product локатор. Затем фильтруем по тексту. Мы можем снова использовать локатор продукта, чтобы получить роль кнопки, и щелкнуть ее, а затем использовать утверждение, чтобы убедиться, что существует только одна кнопка с текстом «Продукт». 2” продукт.

Язык кода:javascript
копировать
product = page.get_by_role("listitem").filter(has_text="Product 2")

product.get_by_role("button", name="Add to cart").click()

Вы также можете связать два локатора вместе, например, чтобы найти кнопку «Сохранить» в определенном диалоговом окне:

Язык кода:javascript
копировать
save_button = page.get_by_role("button", name="Save")
# ...
dialog = page.get_by_test_id("settings-dialog")
dialog.locator(save_button).click()

5. Список

5.1 Подсчет элементов в списке

Локаторы могут использоваться для подсчета элементов в списке. Например: посмотрите на структуру DOM

Используйте утверждение подсчета, чтобы убедиться, что список содержит 3 элемента.

Язык кода:javascript
копировать
expect(page.get_by_role("listitem")).to_have_count(3)
5.2 Подтвердить весь текст в списке

Локаторы могут быть утверждены для поиска всего текста в списке. Используйте ожидаемый(локатор).to_have_text(), чтобы убедиться, что список содержит текст «яблоко», «банан» и «апельсин».

Язык кода:javascript
копировать
expect(page.get_by_role("listitem")).to_have_text(["apple", "banana", "orange"])
5.3 Целевые конкретные проекты

Существует множество способов найти определенные элементы в списке.

5.3.1 Позиционирование по тексту

Используйте метод page.get_by_text(), чтобы найти элемент в списке по текстовому содержимому и щелкнуть по нему.

Найдите элемент по его текстовому содержимому и нажмите на него.

Язык кода:javascript
копировать
page.get_by_text("orange").click()
5.3.2 Позиционирование посредством фильтрации текста

Используйте locator.filter() для поиска определенных элементов в списке. Найдите элемент по роли «Элемент списка», отфильтруйте его по тексту «Оранжевый» и щелкните по нему.

Язык кода:javascript
копировать
page.get_by_role("listitem").filter(has_text="orange").click()
5.3.3 Позиционирование по идентификатору теста

Используйте метод page.get_by_test_id(), чтобы найти элемент в списке. Если у вас еще нет идентификатора теста, возможно, вам придется изменить HTML-код и добавить идентификатор теста.

Найдите предмет по идентификатору теста «оранжевый» и нажмите на него.

Язык кода:javascript
копировать
page.get_by_test_id("orange").click()
5.3.4 Позиционирование по n-му элементу

Если у вас есть список идентичных элементов и отличить их можно только по порядку, вы можете выбрать конкретный элемент из списка с помощью locator.first, locator.last или locator.nth().

Язык кода:javascript
копировать
banana = page.get_by_role("listitem").nth(1)

Однако используйте этот метод с осторожностью. Часто страница может измениться, и локатор будет указывать на совершенно другой элемент, чем ожидалось. Вместо этого попытайтесь придумать уникальный локатор, отвечающий строгим критериям.

5.4 Фильтр ссылок

Если у вас есть элементы с различным сходством, вы можете использовать метод locator.filter() для выбора правильного элемента. Вы также можете связать несколько фильтров, чтобы сузить выбор.

Чтобы сделать скриншот строк с «Мэри» и «Попрощайся»:

Язык кода:javascript
копировать
row_locator = page.get_by_role("listitem")

row_locator
    .filter(has_text="Mary")
    .filter(has=page.get_by_role("button", name="Say goodbye"))
    .screenshot(path="screenshot.png")
5.5 Редкие примеры
5.5.1 Выполнение операций над каждым элементом списка

Итерация элементов

Язык кода:javascript
копировать
for row in page.get_by_role("listitem").all():
    print(row.text_content())

Выполните итерацию, используя обычный цикл for:

Язык кода:javascript
копировать
rows = page.get_by_role("listitem")
count = rows.count()
for i in range(count):
    print(rows.nth(i).text_content())
5.5.2 Оценка на странице

Код в locator.evaluate_all() выполняется на странице, где вы можете вызвать любой API DOM.

Язык кода:javascript
копировать
rows = page.get_by_role("listitem")
texts = rows.evaluate_all("list => list.map(element => element.textContent)")

6. Резюме

Локатор очень строгий. Это означает, что все операции с локатором, которые подразумевают какой-либо целевой элемент DOM, будут вызывать исключение, если совпадают несколько элементов. Например, если в DOM имеется несколько кнопок, выполняется следующий вызов:

Если кнопок несколько, выдать ошибку
Язык кода:javascript
копировать
page.get_by_role("button").click()

С другой стороны, Playwright понимает, когда следует выполнять операции с несколькими элементами, поэтому следующий вызов работает нормально, когда локатор разрешается для нескольких элементов.

Работает с несколькими элементами
Язык кода:javascript
копировать
page.get_by_role("button").count()

Вы можете явно отказаться от проверки строгости, сообщив Playwright, какой элемент использовать, когда несколько элементов совпадают, с помощью locator.first, locator.last и locator.nth(). Эти методы не рекомендуются, поскольку Playwright может щелкнуть ненужные вам элементы при изменении страницы. Вместо этого следуйте приведенным выше рекомендациям, чтобы создать локатор, который однозначно идентифицирует целевой элемент.

6.1 Другие локаторы

Для менее часто используемых локаторов,Пожалуйста, проверьте официальный сайтДругие локаторыгид。из-за ограничений по времени,Брат Хун не будет здесь представлять и объяснять это. Ладно, уже поздно,Давайте сегодня поделимся методом позиционирования элемента! ! ! Только для справки,Спасибо за ваше терпеливое чтение.

boy illustration
.NET Как загрузить файлы через HttpWebRequest
boy illustration
[Веселый проект Docker] Обновленная версия 2023 года! Создайте эксклюзивный инструмент управления паролями за 10 минут — Vaultwarden
boy illustration
Высокопроизводительная библиотека бревен Golang zap + компонент для резки бревен лесоруба подробное объяснение
boy illustration
Концепция и использование Springboot ConstraintValidator
boy illustration
Новые функции Go 1.23: точная настройка основных библиотек, таких как срезы и синхронизация, значительно улучшающая процесс разработки.
boy illustration
[Весна] Введение и базовое использование AOP в Spring, SpringBoot использует AOP.
boy illustration
Чтобы начать работу с рабочим процессом Flowable, этой статьи достаточно.
boy illustration
Байтовое интервью: как решить проблему с задержкой сообщений MQ?
boy illustration
ASP.NET Core использует функциональные переключатели для управления реализацией доступа по маршрутизации.
boy illustration
[Проблема] Решение Невозможно подключиться к Redis; вложенное исключение — io.lettuce.core.RedisConnectionException.
boy illustration
От теории к практике: проектирование чистой архитектуры в проектах Go
boy illustration
Решение проблемы искажения китайских символов при чтении файлов Net Core.
boy illustration
Реализация легких независимых конвейеров с использованием Brighter
boy illustration
Как удалить и вернуть указанную пару ключ-значение из ассоциативного массива в PHP
boy illustration
Feiniu fnos использует Docker для развертывания учебного пособия по AList
boy illustration
Принципы и практика использования многопоточности в различных версиях .NET.
boy illustration
Как использовать PaddleOCRSharp в рамках .NET
boy illustration
CRUD используется уже два или три года. Как читать исходный код Spring?
boy illustration
Устраните проблему совместимости между версией Spring Boot и Gradle Java: возникла проблема при настройке корневого проекта «demo1» > Не удалось.
boy illustration
Научите вас шаг за шагом, как настроить Nginx.
boy illustration
Это руководство — все, что вам нужно для руководства по автономному развертыванию сервера для проектов Python уровня няни (рекомендуемый сборник).
boy illustration
Не удалось запустить docker.service — Подробное объяснение идеального решения ️
boy illustration
Настройка файлового сервера Samba в системе Linux Centos. Анализ NetBIOS (супер подробно)
boy illustration
Как настроить метод ssh в Git, как получить и отправить код через метод ssh
boy illustration
RasaGpt — платформа чат-ботов на основе Rasa и LLM.
boy illustration
Nomic Embed: воспроизводимая модель внедрения SOTA с открытым исходным кодом.
boy illustration
Улучшение YOLOv8: EMA основана на эффективном многомасштабном внимании, основанном на межпространственном обучении, и эффект лучше, чем у ECA, CBAM и CA. Малые цели имеют очевидные преимущества | ICASSP2023
boy illustration
Урок 1 серии Libtorch: Тензорная библиотека Silky C++
boy illustration
Руководство по локальному развертыванию Stable Diffusion: подробные шаги и анализ распространенных проблем
boy illustration
Полностью автоматический инструмент для работы с видео в один клик: VideoLingo