Перейти к основному содержимому

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

Введение

примечание

Ознакомьтесь с основным руководством по локаторам для наиболее распространенных и рекомендуемых локаторов.

В дополнение к рекомендуемым локаторам, таким как Page.getByRole() и Page.getByText(), Playwright поддерживает множество других локаторов, описанных в этом руководстве.

CSS локатор

примечание

Мы рекомендуем отдавать приоритет локаторам, видимым пользователю, таким как текст или доступная роль, вместо использования CSS, который привязан к реализации и может сломаться при изменении страницы.

Playwright может находить элемент по CSS селектору.

page.locator("css=button").click();

Playwright расширяет стандартные CSS селекторы двумя способами:

  • CSS селекторы проникают в открытый теневой DOM.
  • Playwright добавляет пользовательские псевдоклассы, такие как :visible, :has-text(), :has(), :is(), :nth-match() и другие.

CSS: соответствие по тексту

Playwright включает ряд CSS псевдоклассов для соответствия элементов по их текстовому содержимому.

  • article:has-text("Playwright") - :has-text() соответствует любому элементу, содержащему указанный текст где-то внутри, возможно, в дочернем или потомке. Соответствие нечувствительно к регистру, обрезает пробелы и ищет подстроку.

    Например, article:has-text("Playwright") соответствует <article><div>Playwright</div></article>.

    Обратите внимание, что :has-text() следует использовать вместе с другими CSS спецификаторами, иначе он будет соответствовать всем элементам, содержащим указанный текст, включая <body>.

    // Неправильно, будет соответствовать многим элементам, включая <body>
    page.locator(":has-text(\"Playwright\")").click();
    // Правильно, соответствует только элементу <article>
    page.locator("article:has-text(\"Playwright\")").click();
  • #nav-bar :text("Home") - псевдокласс :text() соответствует наименьшему элементу, содержащему указанный текст. Соответствие нечувствительно к регистру, обрезает пробелы и ищет подстроку.

    Например, это найдет элемент с текстом "Home" где-то внутри элемента #nav-bar:

    page.locator("#nav-bar :text('Home')").click();
  • #nav-bar :text-is("Home") - псевдокласс :text-is() соответствует наименьшему элементу с точным текстом. Точное соответствие чувствительно к регистру, обрезает пробелы и ищет полную строку.

    Например, :text-is("Log") не соответствует <button>Log in</button>, потому что <button> содержит один текстовый узел "Log in", который не равен "Log". Однако, :text-is("Log") соответствует <button> Log <span>in</span></button>, потому что <button> содержит текстовый узел " Log ".

    Аналогично, :text-is("Download") не будет соответствовать <button>download</button>, потому что это чувствительно к регистру.

  • #nav-bar :text-matches("reg?ex", "i") - псевдокласс :text-matches() соответствует наименьшему элементу с текстовым содержимым, соответствующим регулярному выражению, подобному JavaScript.

    Например, :text-matches("Log\s*in", "i") соответствует <button>Login</button> и <button>log IN</button>.

примечание

Соответствие тексту всегда нормализует пробелы. Например, оно превращает несколько пробелов в один, превращает разрывы строк в пробелы и игнорирует начальные и конечные пробелы.

примечание

Элементы ввода типа button и submit соответствуют по их value, а не по текстовому содержимому. Например, :text("Log in") соответствует <input type=button value="Log in">.

CSS: соответствие только видимым элементам

Playwright поддерживает псевдокласс :visible в CSS селекторах. Например, css=button соответствует всем кнопкам на странице, в то время как css=button:visible соответствует только видимым кнопкам. Это полезно для различения элементов, которые очень похожи, но отличаются видимостью.

Рассмотрим страницу с двумя кнопками, первая невидима, а вторая видима.

<button style='display: none'>Invisible</button>
<button>Visible</button>
  • Это найдет обе кнопки и вызовет ошибку строгости:

    page.locator("button").click();
  • Это найдет только вторую кнопку, потому что она видима, и затем нажмет на нее.

    page.locator("button:visible").click();

CSS: элементы, содержащие другие элементы

Псевдокласс :has() является экспериментальным CSS псевдоклассом. Он возвращает элемент, если любой из селекторов, переданных в качестве параметров относительно :scope данного элемента, соответствует хотя бы одному элементу.

Следующий фрагмент возвращает текстовое содержимое элемента <article>, который имеет внутри <div class=promo>.

page.locator("article:has(div.promo)").textContent();

CSS: элементы, соответствующие одному из условий

Список CSS селекторов, разделенных запятыми, будет соответствовать всем элементам, которые могут быть выбраны одним из селекторов в этом списке.

// Нажимает на <button>, который имеет текст "Log in" или "Sign in".
page.locator("button:has-text(\"Log in\"), button:has-text(\"Sign in\")").click();

Псевдокласс :is() является экспериментальным CSS псевдоклассом, который может быть полезен для указания списка дополнительных условий на элементе.

CSS: соответствие элементов на основе макета

примечание

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

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

Например, input:right-of(:text("Password")) соответствует полю ввода, которое находится справа от текста "Password" - полезно, когда на странице есть несколько полей ввода, которые трудно различить между собой.

Обратите внимание, что псевдоклассы макета полезны в дополнение к чему-то еще, например, input. Если вы используете псевдокласс макета отдельно, например, :right-of(:text("Password")), скорее всего, вы получите не то поле ввода, которое ищете, а какой-то пустой элемент между текстом и целевым полем ввода.

Псевдоклассы макета используют bounding client rect для вычисления расстояния и относительного положения элементов.

  • :right-of(div > button) - Соответствует элементам, которые находятся справа от любого элемента, соответствующего внутреннему селектору, на любой вертикальной позиции.
  • :left-of(div > button) - Соответствует элементам, которые находятся слева от любого элемента, соответствующего внутреннему селектору, на любой вертикальной позиции.
  • :above(div > button) - Соответствует элементам, которые находятся выше любого из элементов, соответствующих внутреннему селектору, на любой горизонтальной позиции.
  • :below(div > button) - Соответствует элементам, которые находятся ниже любого из элементов, соответствующих внутреннему селектору, на любой горизонтальной позиции.
  • :near(div > button) - Соответствует элементам, которые находятся рядом (в пределах 50 CSS пикселей) с любым из элементов, соответствующих внутреннему селектору.

Обратите внимание, что полученные совпадения сортируются по их расстоянию до якорного элемента, поэтому вы можете использовать Locator.first(), чтобы выбрать ближайший. Это полезно только если у вас есть что-то вроде списка похожих элементов, где ближайший очевидно является правильным. Однако использование Locator.first() в других случаях, скорее всего, не сработает как ожидалось - он не будет нацелен на элемент, который вы ищете, а на какой-то другой элемент, который случайно оказался ближайшим, например, случайный пустой <div>, или элемент, который прокручен и в данный момент не виден.

// Заполните поле ввода справа от "Username".
page.locator("input:right-of(:text(\"Username\"))").fill("value");

// Нажмите на кнопку рядом с промо-картой.
page.locator("button:near(.promo-card)").click();

// Нажмите на радио-кнопку в списке, ближайшую к "Label 3".
page.locator("[type=radio]:left-of(:text(\"Label 3\"))").first().click();

Все псевдоклассы макета поддерживают необязательное максимальное расстояние в пикселях в качестве последнего аргумента. Например, button:near(:text("Username"), 120) соответствует кнопке, которая находится на расстоянии не более 120 CSS пикселей от элемента с текстом "Username".

CSS: выбор n-го совпадения из результата запроса

примечание

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

Иногда на странице содержится несколько похожих элементов, и сложно выбрать конкретный. Например:

<section> <button>Buy</button> </section>
<article><div> <button>Buy</button> </div></article>
<div><div> <button>Buy</button> </div></div>

В этом случае, :nth-match(:text("Buy"), 3) выберет третью кнопку из приведенного выше фрагмента. Обратите внимание, что индекс начинается с единицы.

// Нажмите на третью кнопку "Buy"
page.locator(":nth-match(:text('Buy'), 3)").click();

:nth-match() также полезен для ожидания, пока не появится указанное количество элементов, используя Locator.waitFor().

// Ожидание, пока все три кнопки не станут видимыми
page.locator(":nth-match(:text('Buy'), 3)").waitFor();
примечание

В отличие от :nth-child(), элементы не обязательно должны быть соседями, они могут находиться где угодно на странице. В приведенном выше фрагменте все три кнопки соответствуют селектору :text("Buy"), и :nth-match() выбирает третью кнопку.

Локатор n-го элемента

Вы можете сузить запрос до n-го совпадения, используя локатор nth=, передавая индекс, начиная с нуля.

// Нажмите на первую кнопку
page.locator("button").locator("nth=0").click();

// Нажмите на последнюю кнопку
page.locator("button").locator("nth=-1").click();

Локатор родительского элемента

Когда вам нужно нацелиться на родительский элемент какого-либо другого элемента, чаще всего следует Locator.filter() по локатору дочернего элемента. Например, рассмотрим следующую структуру DOM:

<li><label>Hello</label></li>
<li><label>World</label></li>

Если вы хотите нацелиться на родительский <li> элемента label с текстом "Hello", использование Locator.filter() работает лучше всего:

Locator child = page.getByText("Hello");
Locator parent = page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHas(child));

В качестве альтернативы, если вы не можете найти подходящий локатор для родительского элемента, используйте xpath=... Обратите внимание, что этот метод не так надежен, потому что любые изменения в структуре DOM сломают ваши тесты. Предпочитайте Locator.filter(), когда это возможно.

Locator parent = page.getByText("Hello").locator("xpath=..");

React локатор

примечание

React локатор является экспериментальным и имеет префикс _. Функциональность может измениться в будущем.

React локатор позволяет находить элементы по имени их компонента и значениям свойств. Синтаксис очень похож на CSS селекторы атрибутов и поддерживает все операторы селекторов атрибутов CSS.

В React локаторе имена компонентов записываются в CamelCase.

page.locator("_react=BookItem").click();

Больше примеров:

  • соответствие по компоненту: _react=BookItem
  • соответствие по компоненту и точному значению свойства, чувствительно к регистру: _react=BookItem[author = "Steven King"]
  • соответствие только по значению свойства, нечувствительно к регистру: _react=[author = "steven king" i]
  • соответствие по компоненту и истинному значению свойства: _react=MyButton[enabled]
  • соответствие по компоненту и логическому значению: _react=MyButton[enabled = false]
  • соответствие по подстроке значения свойства: _react=[author *= "King"]
  • соответствие по компоненту и нескольким свойствам: _react=BookItem[author *= "king" i][year = 1990]
  • соответствие по вложенному значению свойства: _react=[some.nested.value = 12]
  • соответствие по компоненту и префиксу значения свойства: _react=BookItem[author ^= "Steven"]
  • соответствие по компоненту и суффиксу значения свойства: _react=BookItem[author $= "Steven"]
  • соответствие по компоненту и ключу: _react=BookItem[key = '2']
  • соответствие по значению свойства регулярным выражением: _react=[author = /Steven(\\s+King)?/i]

Чтобы найти имена React элементов в дереве, используйте React DevTools.

примечание

React локатор поддерживает React 15 и выше.

примечание

React локатор, как и React DevTools, работает только с неминифицированными сборками приложений.

Vue локатор

примечание

Vue локатор является экспериментальным и имеет префикс _. Функциональность может измениться в будущем.

Vue локатор позволяет находить элементы по имени их компонента и значениям свойств. Синтаксис очень похож на CSS селекторы атрибутов и поддерживает все операторы селекторов атрибутов CSS.

В Vue локаторе имена компонентов записываются в kebab-case.

page.locator("_vue=book-item").click();

Больше примеров:

  • соответствие по компоненту: _vue=book-item
  • соответствие по компоненту и точному значению свойства, чувствительно к регистру: _vue=book-item[author = "Steven King"]
  • соответствие только по значению свойства, нечувствительно к регистру: _vue=[author = "steven king" i]
  • соответствие по компоненту и истинному значению свойства: _vue=my-button[enabled]
  • соответствие по компоненту и логическому значению: _vue=my-button[enabled = false]
  • соответствие по подстроке значения свойства: _vue=[author *= "King"]
  • соответствие по компоненту и нескольким свойствам: _vue=book-item[author *= "king" i][year = 1990]
  • соответствие по вложенному значению свойства: _vue=[some.nested.value = 12]
  • соответствие по компоненту и префиксу значения свойства: _vue=book-item[author ^= "Steven"]
  • соответствие по компоненту и суффиксу значения свойства: _vue=book-item[author $= "Steven"]
  • соответствие по значению свойства регулярным выражением: _vue=[author = /Steven(\\s+King)?/i]

Чтобы найти имена Vue элементов в дереве, используйте Vue DevTools.

примечание

Vue локатор поддерживает Vue2 и выше.

примечание

Vue локатор, как и Vue DevTools, работает только с неминифицированными сборками приложений.

XPath локатор

warning

Мы рекомендуем отдавать приоритет локаторам, видимым пользователю, таким как текст или доступная роль, вместо использования XPath, который привязан к реализации и легко ломается при изменении страницы.

XPath локаторы эквивалентны вызову Document.evaluate.

page.locator("xpath=//button").click();
примечание

Любая строка селектора, начинающаяся с // или .., считается xpath селектором. Например, Playwright преобразует '//html/body' в 'xpath=//html/body'.

примечание

XPath не проникает в теневые корни.

XPath объединение

Оператор pipe (|) может использоваться для указания нескольких селекторов в XPath. Он будет соответствовать всем элементам, которые могут быть выбраны одним из селекторов в этом списке.

// Ожидает либо диалог подтверждения, либо индикатор загрузки.
page.locator("//span[contains(@class, 'spinner__loading')]|//div[@id='confirmation']").waitFor();

Перенаправление метки на элемент управления формой

warning

Мы рекомендуем находить по тексту метки вместо того, чтобы полагаться на перенаправление метки на элемент управления.

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

Например, рассмотрим следующую структуру DOM: <label for="password">Password:</label><input id="password" type="password">. Вы можете нацелиться на метку по ее тексту "Password", используя Page.getByText(). Однако следующие действия будут выполнены на поле ввода, а не на метке:

// Заполните поле ввода, нацелившись на метку.
page.getByText("Password").fill("secret");

Однако другие методы будут нацелены на саму метку, например, assertThat(locator).hasText() будет проверять текстовое содержимое метки, а не поля ввода.

// Заполните поле ввода, нацелившись на метку.
assertThat(page.locator("label")).hasText("Password");

Устаревший текстовый локатор

warning

Мы рекомендуем использовать современный текстовый локатор вместо этого.

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

page.locator("text=Log in").click();

Устаревший текстовый локатор имеет несколько вариаций:

  • text=Log in - соответствие по умолчанию нечувствительно к регистру, обрезает пробелы и ищет подстроку. Например, text=Log соответствует <button>Log in</button>.

    page.locator("text=Log in").click();
  • text="Log in" - текстовое содержимое может быть экранировано одинарными или двойными кавычками для поиска текстового узла с точным содержимым после обрезки пробелов.

    Например, text="Log" не соответствует <button>Log in</button>, потому что <button> содержит один текстовый узел "Log in", который не равен "Log". Однако, text="Log" соответствует <button> Log <span>in</span></button>, потому что <button> содержит текстовый узел " Log ". Этот точный режим подразумевает чувствительность к регистру, поэтому text="Download" не будет соответствовать <button>download</button>.

    Заключенное в кавычки содержимое следует обычным правилам экранирования, например, используйте \" для экранирования двойной кавычки в строке с двойными кавычками: text="foo\"bar".

    page.locator("text='Log in'").click();
  • /Log\s*in/i - содержимое может быть регулярным выражением, подобным JavaScript, заключенным в символы /. Например, text=/Log\s*in/i соответствует <button>Login</button> и <button>log IN</button>.

    page.locator("text=/Log\\s*in/i").click();
примечание

Строковые селекторы, начинающиеся и заканчивающиеся кавычкой (либо " либо '), считаются устаревшими текстовыми локаторами. Например, "Log in" внутренне преобразуется в text="Log in".

примечание

Соответствие всегда нормализует пробелы. Например, оно превращает несколько пробелов в один, превращает разрывы строк в пробелы и игнорирует начальные и конечные пробелы.

примечание

Элементы ввода типа button и submit соответствуют по их value, а не по текстовому содержимому. Например, text=Log in соответствует <input type=button value="Log in">.

id, data-testid, data-test-id, data-test селекторы

warning

Мы рекомендуем находить по тестовому id вместо этого.

Playwright поддерживает сокращенную запись для выбора элементов с использованием определенных атрибутов. В настоящее время поддерживаются только следующие атрибуты:

  • id
  • data-testid
  • data-test-id
  • data-test
// Заполните поле ввода с id "username"
page.locator("id=username").fill("value");

// Нажмите на элемент с data-test-id "submit"
page.locator("data-test-id=submit").click();
примечание

Атрибутные селекторы не являются CSS селекторами, поэтому все, что специфично для CSS, например, :enabled, не поддерживается. Для получения дополнительных возможностей используйте правильный css селектор, например, css=[data-test="login"]:enabled.

Цепочка селекторов

warning

Мы рекомендуем цепочку локаторов вместо этого.

Селекторы, определенные как engine=body или в краткой форме, могут быть объединены с помощью токена >>, например, selector1 >> selector2 >> selectors3. Когда селекторы объединены в цепочку, следующий селектор запрашивается относительно результата предыдущего.

Например,

css=article >> css=.bar > .baz >> css=span[attr=value]

эквивалентно

document
.querySelector('article')
.querySelector('.bar > .baz')
.querySelector('span[attr=value]');

Если селектору нужно включить >> в тело, его следует экранировать внутри строки, чтобы не путать с разделителем цепочки, например, text="some >> text".

Промежуточные совпадения

warning

Мы рекомендуем фильтрацию по другому локатору для нахождения элементов, содержащих другие элементы.

По умолчанию, цепочные селекторы разрешаются в элемент, запрашиваемый последним селектором. Селектор может быть префиксирован *, чтобы захватить элементы, запрашиваемые промежуточным селектором.

Например, css=article >> text=Hello захватывает элемент с текстом Hello, а *css=article >> text=Hello (обратите внимание на *) захватывает элемент article, который содержит какой-то элемент с текстом Hello.