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

Повторные попытки

Введение

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

Ошибки

Playwright Test запускает тесты в рабочих процессах. Эти процессы являются процессами ОС, работающими независимо, под управлением тестового раннера. Все рабочие процессы имеют идентичные окружения, и каждый из них запускает свой собственный браузер.

Рассмотрим следующий фрагмент:

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

test.describe('suite', () => {
test.beforeAll(async () => { /* ... */ });
test('first good', async ({ page }) => { /* ... */ });
test('second flaky', async ({ page }) => { /* ... */ });
test('third good', async ({ page }) => { /* ... */ });
test.afterAll(async () => { /* ... */ });
});

Когда все тесты проходят, они выполняются по порядку в одном и том же рабочем процессе.

  • Рабочий процесс запускается
    • Выполняется хук beforeAll
    • first good проходит
    • second flaky проходит
    • third good проходит
    • Выполняется хук afterAll

Если любой тест не проходит, Playwright Test удалит весь рабочий процесс вместе с браузером и запустит новый. Тестирование продолжится в новом рабочем процессе, начиная со следующего теста.

  • Рабочий процесс #1 запускается
    • Выполняется хук beforeAll
    • first good проходит
    • second flaky не проходит
    • Выполняется хук afterAll
  • Рабочий процесс #2 запускается
    • Выполняется хук beforeAll снова
    • third good проходит
    • Выполняется хук afterAll

Если вы включите повторные попытки, второй рабочий процесс начнет с повторной попытки неудачного теста и продолжит с этого момента.

  • Рабочий процесс #1 запускается
    • Выполняется хук beforeAll
    • first good проходит
    • second flaky не проходит
    • Выполняется хук afterAll
  • Рабочий процесс #2 запускается
    • Выполняется хук beforeAll снова
    • second flaky повторяется и проходит
    • third good проходит
    • Выполняется хук afterAll

Эта схема отлично работает для независимых тестов и гарантирует, что неудачные тесты не могут повлиять на успешные.

Повторные попытки

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

# Дать неудачным тестам 3 попытки
npx playwright test --retries=3

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

playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
// Дать неудачным тестам 3 попытки
retries: 3,
});

Playwright Test будет классифицировать тесты следующим образом:

  • "passed" - тесты, которые прошли с первого раза;
  • "flaky" - тесты, которые не прошли с первого раза, но прошли при повторной попытке;
  • "failed" - тесты, которые не прошли с первого раза и не прошли все повторные попытки.
Running 3 tests using 1 worker

✓ example.spec.ts:4:2 › first passes (438ms)
x example.spec.ts:5:2 › second flaky (691ms)
✓ example.spec.ts:5:2 › second flaky (522ms)
✓ example.spec.ts:6:2 › third passes (932ms)

1 flaky
example.spec.ts:5:2 › second flaky
2 passed (4s)

Вы можете обнаружить повторные попытки во время выполнения с помощью testInfo.retry, который доступен любому тесту, хуку или фикстуре. Вот пример, который очищает некоторое состояние на сервере перед повторной попыткой.

import { test, expect } from '@playwright/test';

test('my test', async ({ page }, testInfo) => {
if (testInfo.retry)
await cleanSomeCachesOnTheServer();
// ...
});

Вы можете указать повторные попытки для определенной группы тестов или одного файла с помощью test.describe.configure().

import { test, expect } from '@playwright/test';

test.describe(() => {
// Все тесты в этой группе описания получат 2 попытки.
test.describe.configure({ retries: 2 });

test('test 1', async ({ page }) => {
// ...
});

test('test 2', async ({ page }) => {
// ...
});
});

Последовательный режим

Используйте test.describe.serial() для группировки зависимых тестов, чтобы гарантировать, что они всегда будут выполняться вместе и в порядке. Если один из тестов не проходит, все последующие тесты пропускаются. Все тесты в группе повторяются вместе.

Рассмотрим следующий фрагмент, который использует test.describe.serial:

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

test.describe.configure({ mode: 'serial' });

test.beforeAll(async () => { /* ... */ });
test('first good', async ({ page }) => { /* ... */ });
test('second flaky', async ({ page }) => { /* ... */ });
test('third good', async ({ page }) => { /* ... */ });

При запуске без повторных попыток, все тесты после неудачи пропускаются:

  • Рабочий процесс #1:
    • Выполняется хук beforeAll
    • first good проходит
    • second flaky не проходит
    • third good полностью пропускается

При запуске с повторными попытками, все тесты повторяются вместе:

  • Рабочий процесс #1:
    • Выполняется хук beforeAll
    • first good проходит
    • second flaky не проходит
    • third good пропускается
  • Рабочий процесс #2:
    • Выполняется хук beforeAll снова
    • first good проходит снова
    • second flaky проходит
    • third good проходит
примечание

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

Повторное использование одной страницы между тестами

Playwright Test создает изолированный объект Page для каждого теста. Однако, если вы хотите повторно использовать один объект Page между несколькими тестами, вы можете создать его в test.beforeAll() и закрыть в test.afterAll().

example.spec.ts
import { test, type Page } from '@playwright/test';

test.describe.configure({ mode: 'serial' });

let page: Page;

test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});

test.afterAll(async () => {
await page.close();
});

test('runs first', async () => {
await page.goto('https://playwright.dev/');
});

test('runs second', async () => {
await page.getByText('Get Started').click();
});