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

Проверки

Введение

Playwright включает в себя тестовые утверждения в виде функции expect. Чтобы сделать утверждение, вызовите expect(value) и выберите сопоставитель, который отражает ожидание. Существует множество общих сопоставителей, таких как toEqual, toContain, toBeTruthy, которые можно использовать для утверждения любых условий.

expect(success).toBeTruthy();

Playwright также включает в себя веб-специфичные асинхронные сопоставители, которые будут ждать, пока ожидаемое условие не будет выполнено. Рассмотрим следующий пример:

await expect(page.getByTestId('status')).toHaveText('Submitted');

Playwright будет повторно тестировать элемент с тестовым идентификатором status, пока извлеченный элемент не будет содержать текст "Submitted". Он будет повторно извлекать элемент и проверять его снова и снова, пока условие не будет выполнено или пока не истечет время ожидания. Вы можете либо передать это время ожидания, либо настроить его один раз через значение testConfig.expect в конфигурации теста.

По умолчанию время ожидания для утверждений установлено на 5 секунд. Узнайте больше о различных таймаутах.

Автоматическое повторение утверждений

Следующие утверждения будут повторяться до тех пор, пока утверждение не пройдет, или пока не истечет время ожидания утверждения. Обратите внимание, что повторяющиеся утверждения являются асинхронными, поэтому вы должны использовать await для них.

УтверждениеОписание
await expect(locator).toBeAttached()Элемент прикреплён к DOM
await expect(locator).toBeChecked()Чекбокс отмечен
await expect(locator).toBeDisabled()Элемент отключён
await expect(locator).toBeEditable()Элемент доступен для редактирования
await expect(locator).toBeEmpty()Контейнер пуст
await expect(locator).toBeEnabled()Элемент включён
await expect(locator).toBeFocused()Элемент в фокусе
await expect(locator).toBeHidden()Элемент не виден
await expect(locator).toBeInViewport()Элемент пересекается с viewport
await expect(locator).toBeVisible()Элемент видим
await expect(locator).toContainText()Элемент содержит текст
await expect(locator).toContainClass()У элемента есть указанные CSS-классы
await expect(locator).toHaveAccessibleDescription()У элемента есть соответствующее доступное описание
await expect(locator).toHaveAccessibleName()У элемента есть соответствующее доступное имя
await expect(locator).toHaveAttribute()У элемента есть DOM-атрибут
await expect(locator).toHaveClass()У элемента задан указанный CSS-класс
await expect(locator).toHaveCount()В списке точное количество дочерних элементов
await expect(locator).toHaveCSS()У элемента задано CSS-свойство
await expect(locator).toHaveId()У элемента есть ID
await expect(locator).toHaveJSProperty()У элемента есть JavaScript-свойство
await expect(locator).toHaveRole()У элемента задана определённая ARIA-роль
await expect(locator).toHaveScreenshot()У элемента есть скриншот
await expect(locator).toHaveText()Текст элемента соответствует ожидаемому
await expect(locator).toHaveValue()У поля ввода есть значение
await expect(locator).toHaveValues()У select выбраны значения (options)
await expect(locator).toMatchAriaSnapshot()Элемент соответствует ARIA-снимку
await expect(page).toHaveScreenshot()У страницы есть скриншот
await expect(page).toHaveTitle()У страницы есть заголовок
await expect(page).toHaveURL()У страницы есть URL
await expect(response).toBeOK()Ответ имеет статус OK

Утверждения без повторного выполнения

Эти утверждения позволяют тестировать любые условия, но не выполняются автоматически повторно. В большинстве случаев веб-страницы отображают информацию асинхронно, и использование утверждений без повторного выполнения может привести к нестабильным тестам.

Предпочитайте автоматически повторяющиеся утверждения, когда это возможно. Для более сложных утверждений, которые необходимо повторять, используйте expect.poll или expect.toPass.

УтверждениеОписание
expect(value).toBe()Значение совпадает
expect(value).toBeCloseTo()Число приблизительно равно
expect(value).toBeDefined()Значение не равно undefined
expect(value).toBeFalsy()Значение falsy (например, false, 0, null и т. д.)
expect(value).toBeGreaterThan()Число больше
expect(value).toBeGreaterThanOrEqual()Число больше или равно
expect(value).toBeInstanceOf()Объект является экземпляром класса
expect(value).toBeLessThan()Число меньше
expect(value).toBeLessThanOrEqual()Число меньше или равно
expect(value).toBeNaN()Значение равно NaN
expect(value).toBeNull()Значение равно null
expect(value).toBeTruthy()Значение truthy (то есть не false, 0, null и т. д.)
expect(value).toBeUndefined()Значение равно undefined
expect(value).toContain()Строка содержит подстроку
expect(value).toContain()Массив или set содержит элемент
expect(value).toContainEqual()Массив или set содержит похожий элемент
expect(value).toEqual()Значение похоже (глубокое сравнение и сопоставление по шаблону)
expect(value).toHaveLength()У массива или строки есть длина
expect(value).toHaveProperty()У объекта есть свойство
expect(value).toMatch()Строка соответствует регулярному выражению
expect(value).toMatchObject()Объект содержит указанные свойства
expect(value).toStrictEqual()Значение похоже, включая типы свойств
expect(value).toThrow()Функция выбрасывает ошибку

Asymmetric matchers

These expressions can be nested in other assertions to allow more relaxed matching against a given condition.

MatcherDescription
expect.any()Matches any instance of a class/primitive
expect.anything()Matches anything
expect.arrayContaining()Array contains specific elements
expect.arrayOf()Array contains elements of specific type
expect.closeTo()Number is approximately equal
expect.objectContaining()Object contains specific properties
expect.stringContaining()String contains a substring
expect.stringMatching()String matches a regular expression

Отрицание сопоставителей

В общем случае, мы можем ожидать противоположное, добавив .not перед сопоставителями:

expect(value).not.toEqual(0);
await expect(locator).not.toContainText('some text');

Мягкие утверждения

По умолчанию, неудачное утверждение завершает выполнение теста. Playwright также поддерживает мягкие утверждения: неудачные мягкие утверждения не завершают выполнение теста, но помечают тест как неудачный.

// Сделайте несколько проверок, которые не остановят тест при неудаче...
await expect.soft(page.getByTestId('status')).toHaveText('Success');
await expect.soft(page.getByTestId('eta')).toHaveText('1 day');

// ... и продолжайте тест, чтобы проверить больше вещей.
await page.getByRole('link', { name: 'next page' }).click();
await expect.soft(page.getByRole('heading', { name: 'Make another order' })).toBeVisible();

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

// Сделайте несколько проверок, которые не остановят тест при неудаче...
await expect.soft(page.getByTestId('status')).toHaveText('Success');
await expect.soft(page.getByTestId('eta')).toHaveText('1 day');

// Избегайте дальнейшего выполнения, если были неудачи мягких утверждений.
expect(test.info().errors).toHaveLength(0);

Обратите внимание, что мягкие утверждения работают только с тестовым раннером Playwright.

Пользовательское сообщение expect

Вы можете указать пользовательское сообщение expect в качестве второго аргумента функции expect, например:

await expect(page.getByText('Name'), 'should be logged in').toBeVisible();

Это сообщение будет отображаться в отчетах, как для успешных, так и для неудачных expect, предоставляя больше контекста об утверждении.

Когда expect проходит, вы можете увидеть успешный шаг, подобный этому:

✅ should be logged in    @example.spec.ts:18

Когда expect не проходит, ошибка будет выглядеть так:

    Error: should be logged in

Call log:
- expect.toBeVisible with timeout 5000ms
- waiting for "getByText('Name')"


2 |
3 | test('example test', async({ page }) => {
> 4 | await expect(page.getByText('Name'), 'should be logged in').toBeVisible();
| ^
5 | });
6 |

Мягкие утверждения также поддерживают пользовательское сообщение:

expect.soft(value, 'my soft assertion').toBe(56);

expect.configure

Вы можете создать собственный предварительно настроенный экземпляр expect с его собственными значениями по умолчанию, такими как timeout и soft.

const slowExpect = expect.configure({ timeout: 10000 });
await slowExpect(locator).toHaveText('Submit');

// Всегда выполняйте мягкие утверждения.
const softExpect = expect.configure({ soft: true });
await softExpect(locator).toHaveText('Submit');

expect.poll

Вы можете преобразовать любой синхронный expect в асинхронный с помощью expect.poll.

Следующий метод будет опрашивать данную функцию, пока она не вернет HTTP статус 200:

await expect.poll(async () => {
const response = await page.request.get('https://api.example.com');
return response.status();
}, {
// Пользовательское сообщение expect для отчетности, необязательно.
message: 'make sure API eventually succeeds',
// Опрос в течение 10 секунд; по умолчанию 5 секунд. Установите 0, чтобы отключить таймаут.
timeout: 10000,
}).toBe(200);

Вы также можете указать пользовательские интервалы опроса:

await expect.poll(async () => {
const response = await page.request.get('https://api.example.com');
return response.status();
}, {
// Пробовать, ждать 1с, пробовать, ждать 2с, пробовать, ждать 10с, пробовать, ждать 10с, пробовать
// ... По умолчанию [100, 250, 500, 1000].
intervals: [1_000, 2_000, 10_000],
timeout: 60_000
}).toBe(200);

You can combine expect.configure({ soft: true }) with expect.poll to perform soft assertions in polling logic.

const softExpect = expect.configure({ soft: true });
await softExpect.poll(async () => {
const response = await page.request.get('https://api.example.com');
return response.status();
}, {}).toBe(200);

This allows the test to continue even if the assertion inside poll fails.

expect.toPass

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

await expect(async () => {
const response = await page.request.get('https://api.example.com');
expect(response.status()).toBe(200);
}).toPass();

Вы также можете указать пользовательский таймаут и интервалы повторов:

await expect(async () => {
const response = await page.request.get('https://api.example.com');
expect(response.status()).toBe(200);
}).toPass({
// Пробовать, ждать 1с, пробовать, ждать 2с, пробовать, ждать 10с, пробовать, ждать 10с, пробовать
// ... По умолчанию [100, 250, 500, 1000].
intervals: [1_000, 2_000, 10_000],
timeout: 60_000
});

Обратите внимание, что по умолчанию toPass имеет таймаут 0 и не учитывает пользовательский таймаут expect.

Добавление пользовательских сопоставителей с помощью expect.extend

Вы можете расширить утверждения Playwright, предоставив пользовательские сопоставители. Эти сопоставители будут доступны в объекте expect.

В этом примере мы добавляем пользовательскую функцию toHaveAmount. Пользовательский сопоставитель должен возвращать флаг pass, указывающий, прошло ли утверждение, и обратный вызов message, который используется, когда утверждение не проходит.

fixtures.ts
import { expect as baseExpect } from '@playwright/test';
import type { Locator } from '@playwright/test';

export { test } from '@playwright/test';

export const expect = baseExpect.extend({
async toHaveAmount(locator: Locator, expected: number, options?: { timeout?: number }) {
const assertionName = 'toHaveAmount';
let pass: boolean;
let matcherResult: any;
try {
const expectation = this.isNot ? baseExpect(locator).not : baseExpect(locator);
await expectation.toHaveAttribute('data-amount', String(expected), options);
pass = true;
} catch (e: any) {
matcherResult = e.matcherResult;
pass = false;
}

if (this.isNot) {
pass =!pass;
}

const message = pass
? () => this.utils.matcherHint(assertionName, undefined, undefined, { isNot: this.isNot }) +
'\n\n' +
`Locator: ${locator}\n` +
`Expected: not ${this.utils.printExpected(expected)}\n` +
(matcherResult ? `Received: ${this.utils.printReceived(matcherResult.actual)}` : '')
: () => this.utils.matcherHint(assertionName, undefined, undefined, { isNot: this.isNot }) +
'\n\n' +
`Locator: ${locator}\n` +
`Expected: ${this.utils.printExpected(expected)}\n` +
(matcherResult ? `Received: ${this.utils.printReceived(matcherResult.actual)}` : '');

return {
message,
pass,
name: assertionName,
expected,
actual: matcherResult?.actual,
};
},
});

Теперь мы можем использовать toHaveAmount в тесте.

example.spec.ts
import { test, expect } from './fixtures';

test('amount', async () => {
await expect(page.locator('.cart')).toHaveAmount(4);
});

Совместимость с библиотекой expect

примечание

Не путайте expect Playwright с библиотекой expect. Последняя не полностью интегрирована с тестовым раннером Playwright, поэтому убедитесь, что вы используете собственный expect Playwright.

Комбинирование пользовательских сопоставителей из нескольких модулей

Вы можете комбинировать пользовательские сопоставители из нескольких файлов или модулей.

fixtures.ts
import { mergeTests, mergeExpects } from '@playwright/test';
import { test as dbTest, expect as dbExpect } from 'database-test-utils';
import { test as a11yTest, expect as a11yExpect } from 'a11y-test-utils';

export const expect = mergeExpects(dbExpect, a11yExpect);
export const test = mergeTests(dbTest, a11yTest);
test.spec.ts
import { test, expect } from './fixtures';

test('passes', async ({ database }) => {
await expect(database).toHaveDatabaseUser('admin');
});