Локаторы 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 - строка скриншота в кодировке base64query
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.