Локаторы 2.1.0+
Локатор представляет собой элемент или набор элементов. Каждый локатор определяется строкой, называемой селектором. Vitest абстрагирует этот селектор, предоставляя удобные методы, которые генерируют их в фоновом режиме.
API локаторов основан на форке локаторов Playwright под названием Ivya. Однако Vitest предоставляет этот API каждому провайдеру.
getByRole
function getByRole(
role: ARIARole | string,
options?: LocatorByRoleOptions
): Locator;
Предоставляет способ поиска элемента по его роли ARIA, атрибутам ARIA и доступному имени.
TIP
Если вы запрашиваете только один элемент с помощью getByText('The name')
, зачастую лучше использовать getByRole(expectedRole, { name: 'The name' })
. Поиск по доступному имени не заменяет другие методы поиска, такие как *ByAltText
или *ByTitle
. Хотя доступное имя может быть равно этим атрибутам, оно не заменяет функциональность этих атрибутов.
Рассмотрим следующую структуру DOM.
<h3>Sign up</h3>
<label>
Login
<input type="text" />
</label>
<label>
Password
<input type="password" />
</label>
<br />
<button>Submit</button>
Вы можете найти каждый элемент по его неявной роли:
await expect
.element(page.getByRole('heading', { name: 'Sign up' }))
.toBeVisible();
await page.getByRole('textbox', { name: 'Login' }).fill('admin');
await page.getByRole('textbox', { name: 'Password' }).fill('admin');
await page.getByRole('button', { name: /submit/i }).click();
WARNING
Роли сравниваются по точному совпадению строк, без наследования из иерархии ролей ARIA. В результате запрос роли суперкласса, такой как checkbox
, не будет включать элементы с ролью подкласса, такой как switch
.
Многие семантические элементы HTML по умолчанию имеют роль; например, <input type="radio">
имеет роль "radio". Несемантические элементы в HTML не имеют роли; <div>
и <span>
без добавленной семантики возвращают null
. Атрибут role
может предоставлять семантику.
Предоставление ролей через атрибуты role
или aria-*
встроенным элементам, которые уже имеют неявную роль, крайне не рекомендуется согласно рекомендациям ARIA.
Опции
exact: boolean
Совпадает ли
name
точно: с учетом регистра и всей строки. По умолчанию не включено. Эта опция игнорируется, еслиname
является регулярным выражением. Обратите внимание, что точное совпадение все равно обрезает пробелы.tsx<button>Hello World</button>; page.getByRole('button', { name: 'hello world' }); // ✅ Да page.getByRole('button', { name: 'hello world', exact: true }); // ❌ Нет page.getByRole('button', { name: 'Hello World', exact: true }); // ✅ Да
checked: boolean
Включать ли отмеченные элементы (установленные с помощью
aria-checked
или<input type="checkbox"/>
). По умолчанию фильтр не применяется.См.
aria-checked
для получения дополнительной информации.tsx<> <button role="checkbox" aria-checked="true" /> <input type="checkbox" checked /> </>; page.getByRole('checkbox', { checked: true }); // ✅ Да page.getByRole('checkbox', { checked: false }); // ❌ Нет
disabled: boolean
Включать ли отключенные элементы. По умолчанию фильтр не применяется. Обратите внимание, что в отличие от других атрибутов, состояние
disabled
наследуется.См.
aria-disabled
для получения дополнительной информации.tsx<input type="text" disabled />; page.getByRole('textbox', { disabled: true }); // ✅ Да page.getByRole('textbox', { disabled: false }); // ❌ Нет
expanded: boolean
Включать ли развернутые элементы. По умолчанию фильтр не применяется.
См.
aria-expanded
для получения дополнительной информации.tsx<a aria-expanded="true" href="example.com"> Link </a>; page.getByRole('link', { expanded: true }); // ✅ Да page.getByRole('link', { expanded: false }); // ❌ Нет
includeHidden: boolean
Следует ли запрашивать элементы, которые обычно исключаются из дерева доступности. По умолчанию по селектору роли сопоставляются только нескрытые элементы.
Обратите внимание, что роли
none
иpresentation
всегда включаются.tsx<button style="display: none" />; page.getByRole('button'); // ❌ Нет page.getByRole('button', { includeHidden: false }); // ❌ Нет page.getByRole('button', { includeHidden: true }); // ✅ Да
level: number
Числовой атрибут, который обычно присутствует для ролей
heading
,listitem
,row
,treeitem
со значениями по умолчанию для элементов<h1>-<h6>
. По умолчанию фильтр не применяется.См.
aria-level
для получения дополнительной информации.tsx<> <h1>Heading Level One</h1> <div role="heading" aria-level="1"> Second Heading Level One </div> </>; page.getByRole('heading', { level: 1 }); // ✅ Да page.getByRole('heading', { level: 2 }); // ❌ Нет
name: string | RegExp
Доступное имя. По умолчанию сопоставление нечувствительно к регистру и ищет подстроку. Используйте опцию
exact
для управления этим поведением.tsx<button>Click Me!</button>; page.getByRole('button', { name: 'Click Me!' }); // ✅ Да page.getByRole('button', { name: 'click me!' }); // ✅ Да page.getByRole('button', { name: 'Click Me?' }); // ❌ Нет
pressed: boolean
Включать ли нажатые элементы. По умолчанию фильтр не применяется.
См.
aria-pressed
для получения дополнительной информации.tsx<button aria-pressed="true">👍</button>; page.getByRole('button', { pressed: true }); // ✅ Да page.getByRole('button', { pressed: false }); // ❌ Нет
selected: boolean
Включать ли выбранные элементы. По умолчанию фильтр не применяется.
См.
aria-selected
для получения дополнительной информации.tsx<button role="tab" aria-selected="true"> Vue </button>; page.getByRole('button', { selected: true }); // ✅ Да page.getByRole('button', { selected: false }); // ❌ Нет
См. также
getByAltText
function getByAltText(text: string | RegExp, options?: LocatorOptions): Locator;
Создает локатор, способный найти элемент с атрибутом alt
, который соответствует тексту. В отличие от реализации в testing-library, Vitest будет сопоставлять любой элемент, имеющий соответствующий атрибут alt
.
<img alt="Incredibles 2 Poster" src="/incredibles-2.png" />;
page.getByAltText(/incredibles.*? poster/i); // ✅ Да
page.getByAltText('non existing alt text'); // ❌ Нет
Опции
exact: boolean
Совпадает ли
text
точно: с учетом регистра и всей строки. По умолчанию не включено. Эта опция игнорируется, еслиtext
является регулярным выражением. Обратите внимание, что точное совпадение все равно обрезает пробелы.
См. также
getByLabelText
function getByLabelText(
text: string | RegExp,
options?: LocatorOptions
): Locator;
Создает локатор, способный найти элемент, имеющий связанную метку.
Локатор page.getByLabelText('Username')
найдет каждый ввод в примере ниже:
<!-- for/htmlFor relationship between label and form element id -->
<label for="username-input">Username</label>
<input id="username-input" />
<!-- The aria-labelledby attribute with form elements -->
<label id="username-label">Username</label>
<input aria-labelledby="username-label" />
<!-- Wrapper labels -->
<label>Username <input /></label>
<!-- Wrapper labels where the label text is in another child element -->
<label>
<span>Username</span>
<input />
</label>
<!-- aria-label attributes -->
<!-- Take care because this is not a label that users can see on the page, -->
<!-- so the purpose of your input must be obvious to visual users. -->
<input aria-label="Username" />
Опции
exact: boolean
Совпадает ли
text
точно: с учетом регистра и всей строки. По умолчанию не включено. Эта опция игнорируется, еслиtext
является регулярным выражением. Обратите внимание, что точное совпадение все равно обрезает пробелы.
См. также
getByPlaceholder
function getByPlaceholder(
text: string | RegExp,
options?: LocatorOptions
): Locator;
Создает локатор, способный найти элемент, имеющий указанный атрибут placeholder
. Vitest будет сопоставлять любой элемент, имеющий соответствующий атрибут placeholder
, а не только input
.
<input placeholder="Username" />;
page.getByPlaceholder('Username'); // ✅ Да
page.getByPlaceholder('not found'); // ❌ Нет
WARNING
Как правило, лучше полагаться на метку с помощью getByLabelText
, чем на заполнитель.
Опции
exact: boolean
Совпадает ли
text
точно: с учетом регистра и всей строки. По умолчанию не включено. Эта опция игнорируется, еслиtext
является регулярным выражением. Обратите внимание, что точное совпадение все равно обрезает пробелы.
См. также
getByText
function getByText(text: string | RegExp, options?: LocatorOptions): Locator;
Создает локатор, способный найти элемент, содержащий указанный текст. Текст будет сопоставляться со значением nodeValue
текстового узла или значением ввода, если тип — button
или reset
. Сопоставление по тексту всегда нормализует пробелы, даже при точном совпадении. Например, оно превращает несколько пробелов в один, превращает разрывы строк в пробелы и игнорирует начальные и конечные пробелы.
<a href="/about">About ℹ️</a>;
page.getByText(/about/i); // ✅ Да
page.getByText('about', { exact: true }); // ❌ Нет
TIP
Этот локатор полезен для поиска неинтерактивных элементов. Если вам нужно найти интерактивный элемент, такой как кнопка или ввод, предпочтительнее использовать getByRole
.
Опции
exact: boolean
Совпадает ли
text
точно: с учетом регистра и всей строки. По умолчанию не включено. Эта опция игнорируется, еслиtext
является регулярным выражением. Обратите внимание, что точное совпадение все равно обрезает пробелы.
См. также
getByTitle
function getByTitle(text: string | RegExp, options?: LocatorOptions): Locator;
Создает локатор, способный найти элемент, имеющий указанный атрибут title
. В отличие от getByTitle
из testing-library, Vitest не может найти элементы title
внутри SVG.
<span title="Delete" id="2"></span>;
page.getByTitle('Delete'); // ✅ Да
page.getByTitle('Create'); // ❌ Нет
Опции
exact: boolean
Совпадает ли
text
точно: с учетом регистра и всей строки. По умолчанию не включено. Эта опция игнорируется, еслиtext
является регулярным выражением. Обратите внимание, что точное совпадение все равно обрезает пробелы.
См. также
getByTestId
function getByTestId(text: string | RegExp): Locator;
Создает локатор, способный найти элемент, соответствующий указанному атрибуту тестового идентификатора. Вы можете настроить имя атрибута с помощью browser.locators.testIdAttribute
.
<div data-testid="custom-element" />;
page.getByTestId('custom-element'); // ✅ Да
page.getByTestId('non-existing-element'); // ❌ Нет
WARNING
Рекомендуется использовать это только после того, как другие локаторы не подходят для вашего случая использования. Использование атрибутов data-testid
не отражает то, как используется ваше программное обеспечение, и по возможности следует избегать этого.
Опции
exact: boolean
Совпадает ли
text
точно: с учетом регистра и всей строки. По умолчанию не включено. Эта опция игнорируется, еслиtext
является регулярным выражением. Обратите внимание, что точное совпадение все равно обрезает пробелы.
См. также
Методы
Все методы асинхронны и должны быть ожидаемы. Начиная с Vitest 2.2, тесты будут завершаться с ошибкой, если метод не ожидается.
click
function click(options?: UserEventClickOptions): Promise<void>;
Нажимает на элемент. Вы можете использовать опции для установки положения курсора.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).click();
dblClick
function dblClick(options?: UserEventDoubleClickOptions): Promise<void>;
Генерирует событие двойного щелчка на элементе. Вы можете использовать опции для установки положения курсора.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).dblClick();
tripleClick
function tripleClick(options?: UserEventTripleClickOptions): Promise<void>;
Вызывает событие тройного щелчка на элементе. Поскольку в API браузера нет tripleclick
, этот метод вызовет три события щелчка подряд.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).tripleClick();
clear
function clear(): Promise<void>;
Очищает содержимое элемента ввода.
import { page } from '@vitest/browser/context';
await page.getByRole('textbox', { name: 'Full Name' }).clear();
hover
function hover(options?: UserEventHoverOptions): Promise<void>;
Перемещает положение курсора к выбранному элементу.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).hover();
unhover
function unhover(options?: UserEventHoverOptions): Promise<void>;
Работает так же, как locator.hover
, но перемещает курсор к элементу document.body
.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).unhover();
fill
function fill(text: string, options?: UserEventFillOptions): Promise<void>;
Устанавливает значение текущего элемента input
, textarea
или conteneditable
.
import { page } from '@vitest/browser/context';
await page.getByRole('input', { name: 'Full Name' }).fill('Mr. Bean');
dropTo
function dropTo(
target: Locator,
options?: UserEventDragAndDropOptions
): Promise<void>;
Перемещает текущий элемент методом перетаскивания в целевое местоположение.
import { page } from '@vitest/browser/context';
const paris = page.getByText('Paris');
const france = page.getByText('France');
await paris.dropTo(france);
selectOptions
function selectOptions(
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;
Выбирает одно или несколько значений из элемента <select>
.
import { page } from '@vitest/browser/context';
const languages = page.getByRole('select', { name: 'Languages' });
await languages.selectOptions('EN');
await languages.selectOptions(['ES', 'FR']);
await languages.selectOptions([
languages.getByRole('option', { name: 'Spanish' }),
languages.getByRole('option', { name: 'French' }),
]);
screenshot
function screenshot(
options: LocatorScreenshotOptions & { base64: true }
): Promise<{
path: string;
base64: string;
}>;
function screenshot(
options?: LocatorScreenshotOptions & { base64?: false }
): Promise<string>;
Создает скриншот элемента, соответствующего селектору локатора.
Вы можете указать место сохранения скриншота с помощью опции path
, которая является относительной к текущему тестовому файлу. Если опция path
не установлена, Vitest по умолчанию будет использовать browser.screenshotDirectory
(по умолчанию __screenshot__
), а также имена файла и теста для определения пути к файлу скриншота.
Если вам также нужно содержимое скриншота, вы можете указать base64: true
, чтобы вернуть его вместе с путем к файлу, где сохранен скриншот.
import { page } from '@vitest/browser/context';
const button = page.getByRole('button', { name: 'Click Me!' });
const path = await button.screenshot();
const { path, base64 } = await button.screenshot({
path: './button-click-me.png',
base64: true, // also return base64 string
});
// path - полный путь к скриншоту
// base64 - строка скриншота в кодировке base64
query
function query(): Element | null;
Данный метод возвращает один элемент, соответствующий селектору локатора, или null
, если элемент не найден.
Если селектору соответствует несколько элементов, этот метод вызывает ошибку. Используйте .elements()
, когда вам нужны все соответствующие элементы DOM, или .all()
, если вам нужен массив локаторов, соответствующих селектору.
Рассмотрим следующую структуру DOM:
<div>Hello <span>World</span></div>
<div>Hello</div>
Эти локаторы не вызовут ошибку:
page.getByText('Hello World').query(); // ✅ HTMLDivElement
page.getByText('Hello Germany').query(); // ✅ null
page.getByText('World').query(); // ✅ HTMLSpanElement
page.getByText('Hello', { exact: true }).query(); // ✅ HTMLSpanElement
Эти локаторы вызовут ошибку:
// returns multiple elements
page.getByText('Hello').query(); // ❌
page.getByText(/^Hello/).query(); // ❌
element
function element(): Element;
Этот метод возвращает один элемент, соответствующий селектору локатора.
Если ни один элемент не соответствует селектору, выдается ошибка. Рассмотрите возможность использования .query()
, когда вам просто нужно проверить, существует ли элемент.
Если несколько элементов соответствуют селектору, выдается ошибка. Используйте .elements()
, когда вам нужны все соответствующие элементы DOM, или .all()
, если вам нужен массив локаторов, соответствующих селектору.
TIP
Этот метод может быть полезен, если вам нужно передать его во внешнюю библиотеку. Он вызывается автоматически, когда локатор используется с expect.element
при каждой повторной попытке утверждения:
await expect.element(page.getByRole('button')).toBeDisabled();
Рассмотрим следующую структуру DOM:
<div>Hello <span>World</span></div>
<div>Hello Germany</div>
<div>Hello</div>
Эти локаторы не вызовут ошибку:
page.getByText('Hello World').element(); // ✅
page.getByText('Hello Germany').element(); // ✅
page.getByText('World').element(); // ✅
page.getByText('Hello', { exact: true }).element(); // ✅
Эти локаторы вызовут ошибку:
// returns multiple elements
page.getByText('Hello').element(); // ❌
page.getByText(/^Hello/).element(); // ❌
// returns no elements
page.getByText('Hello USA').element(); // ❌
elements
function elements(): Element[];
Этот метод возвращает массив элементов, соответствующих селектору локатора.
Данный метод никогда не вызывает ошибку. Если нет элементов, соответствующих селектору, этот метод вернет пустой массив.
Рассмотрим следующую структуру DOM:
<div>Hello <span>World</span></div>
<div>Hello</div>
Эти локаторы всегда будут успешными:
page.getByText('Hello World').elements(); // ✅ [HTMLElement]
page.getByText('World').elements(); // ✅ [HTMLElement]
page.getByText('Hello', { exact: true }).elements(); // ✅ [HTMLElement]
page.getByText('Hello').element(); // ✅ [HTMLElement, HTMLElement]
page.getByText('Hello USA').elements(); // ✅ []
all
function all(): Locator[];
Этот метод возвращает массив новых локаторов, соответствующих селектору.
Внутри этот метод вызывает .elements
и оборачивает каждый элемент с помощью page.elementLocator
.