Утверждения
Введение
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
для них.
Утверждения без повторного выполнения
Эти утверждения позволяют тестировать любые условия, но не выполняются автоматически повторно. В большинстве случаев веб-страницы отображают информацию асинхронно, и использование утверждений без повторного выполнения может привести к нестабильным тестам.
Предпочитайте автоматически повторяющиеся утверждения, когда это возможно. Для более сложных утверждений, которые необходимо повторять, используйте expect.poll
или expect.toPass
.
Утверждение | Описание |
---|---|
expect(value).toBe() | Значение такое же |
expect(value).toBeCloseTo() | Число приблизительно равно |
expect(value).toBeDefined() | Значение не undefined |
expect(value).toBeFalsy() | Значение ложно, например, 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() | Значение истинно, т.е. не false , 0 , null и т.д. |
expect(value).toBeUndefined() | Значение undefined |
expect(value).toContain() | Строка содержит подстроку |
expect(value).toContain() | Массив или набор содержит элемент |
expect(value).toContainEqual() | Массив или набор содержит похожий элемент |
expect(value).toEqual() | Значение похоже - глубокое равенство и сопоставление шаблонов |
expect(value).toHaveLength() | Массив или строка имеют длину |
expect(value).toHaveProperty() | Объект имеет свойство |
expect(value).toMatch() | Строка соответствует регулярному выражению |
expect(value).toMatchObject() | Объект содержит указанные свойства |
expect(value).toStrictEqual() | Значение похоже, включая типы свойств |
expect(value).toThrow() | Функция выбрасывает ошибку |
expect(value).any() | Соответствует любому экземпляру класса/примитива |
expect(value).anything() | Соответствует чему угодно |
expect(value).arrayContaining() | Массив содержит определенные элементы |
expect(value).closeTo() | Число приблизительно равно |
expect(value).objectContaining() | Объект содержит определенные свойства |
expect(value).stringContaining() | Строка содержит подстроку |
expect(value).stringMatching() | Строка соответствует регулярному выражению |
Отрицание сопоставителей
В общем случае, мы можем ожидать противоположное, добавив .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);
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
, который используется, когда утверждение не проходит.
import { expect as baseExpect } from '@playwright/test';
import type { Page, 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 {
await baseExpect(locator).toHaveAttribute('data-amount', String(expected), options);
pass = true;
} catch (e: any) {
matcherResult = e.matcherResult;
pass = false;
}
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
в тесте.
import { test, expect } from './fixtures';
test('amount', async () => {
await expect(page.locator('.cart')).toHaveAmount(4);
});
Совместимость с библиотекой expect
Не путайте expect
Playwright с библиотекой expect
. Последняя не полностью интегрирована с тестовым раннером Playwright, поэтому убедитесь, что вы используете собственный expect
Playwright.
Комбинирование пользовательских сопоставителей из нескольких модулей
Вы можете комбинировать пользовательские сопоставители из нескольких файлов или модулей.
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);
import { test, expect } from './fixtures';
test('passes', async ({ database }) => {
await expect(database).toHaveDatabaseUser('admin');
});