Параллелизм
Введение
Playwright Test выполняет тесты параллельно. Для этого он запускает несколько рабочих процессов, которые работают одновременно. По умолчанию, тестовые файлы выполняются параллельно. Тесты в одном файле выполняются по порядку, в одном и том же рабочем процессе.
- Вы можете настроить тесты с помощью
test.describe.configure
, чтобы выполнять тесты в одном файле параллельно. - Вы можете настроить весь проект, чтобы все тесты во всех файлах выполнялись параллельно, используя testProject.fullyParallel или testConfig.fullyParallel.
- Чтобы отключить параллелизм, ограничьте количество рабочих процессов до одного.
Вы можете контролировать количество параллельных рабочих процессов и ограничить количество сбоев во всем наборе тестов для повышения эффективности.
Рабочие процессы
Все тесты выполняются в рабочих процессах. Эти процессы являются процессами операционной системы, работающими независимо, под управлением тестового раннера. Все рабочие процессы имеют идентичные окружения, и каждый запускает свой собственный браузер.
Вы не можете общаться между рабочими процессами. Playwright Test повторно использует один рабочий процесс настолько, насколько это возможно, чтобы ускорить тестирование, поэтому несколько тестовых файлов обычно выполняются в одном рабочем процессе один за другим.
Рабочие процессы всегда завершаются после сбоя теста, чтобы гарантировать чистую среду для последующих тестов.
Ограничение рабочих процессов
Вы можете контролировать максимальное количество параллельных рабочих процессов через командную строку или в файле конфигурации.
Из командной строки:
npx playwright test --workers 4
В файле конфигурации:
import { defineConfig } from '@playwright/test';
export default defineConfig({
// Ограничьте количество рабочих процессов на CI, используйте значение по умолчанию локально
workers: process.env.CI ? 2 : undefined,
});
Отключение параллелизма
Вы можете отключить любой параллелизм, разрешив только один рабочий процесс в любой момент времени. Либо установите опцию workers: 1
в файле конфигурации, либо передайте --workers=1
в командную строку.
npx playwright test --workers=1
Параллелизация тестов в одном файле
По умолчанию тесты в одном файле выполняются по порядку. Если у вас много независимых тестов в одном файле, вы можете захотеть выполнить их параллельно с помощью test.describe.configure().
Обратите внимание, что параллельные тесты выполняются в отдельных рабочих процессах и не могут разделять состояние или глобальные переменные. Каждый тест выполняет все соответствующие хуки только для себя, включая beforeAll
и afterAll
.
import { test } from '@playwright/test';
test.describe.configure({ mode: 'parallel' });
test('runs in parallel 1', async ({ page }) => { /* ... */ });
test('runs in parallel 2', async ({ page }) => { /* ... */ });
В качестве альтернативы, вы можете включить этот полностью параллельный режим для всех тестов в файле конфигурации:
import { defineConfig } from '@playwright/test';
export default defineConfig({
fullyParallel: true,
});
Вы также можете включить полностью параллельный режим только для нескольких проектов:
import { defineConfig } from '@playwright/test';
export default defineConfig({
// выполняет все тесты во всех файлах конкретного проекта параллельно
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
fullyParallel: true,
},
]
});
Последовательный режим
Вы можете аннотировать взаимозависимые тесты как последовательные. Если один из последовательных тестов не проходит, все последующие тесты пропускаются. Все тесты в группе повторяются вместе.
Использование последовательного режима не рекомендуется. Обычно лучше сделать ваши тесты изолированными, чтобы их можно было выполнять независимо.
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();
});
Разделение тестов между несколькими машинами
Playwright Test может разделить набор тестов, чтобы он мог выполняться на нескольких машинах. См. руководство по разделению для получения более подробной информации.
npx playwright test --shard=2/3
Ограничение сбоев и быстрое завершение
Вы можете ограничить количество неудачных тестов во всем наборе тестов, установив опцию конфигурации maxFailures
или передав флаг командной строки --max-failures
.
При запуске с установленным "максимальным количеством сбоев" Playwright Test остановится после достижения этого количества неудачных тестов и пропустит любые тесты, которые еще не были выполнены. Это полезно, чтобы избежать траты ресурсов на сломанные наборы тестов.
Передача опции командной строки:
npx playwright test --max-failures=10
Установка в файле конфигурации:
import { defineConfig } from '@playwright/test';
export default defineConfig({
// Ограничьте количество сбоев на CI, чтобы сэкономить ресурсы
maxFailures: process.env.CI ? 10 : undefined,
});
Индекс рабочего процесса и параллельный индекс
Каждому рабочему процессу присваиваются два идентификатора: уникальный индекс рабочего процесса, который начинается с 1, и параллельный индекс, который находится в диапазоне от 0
до workers - 1
. Когда рабочий процесс перезапускается, например, после сбоя, новый рабочий процесс имеет тот же parallelIndex
и новый workerIndex
.
Вы можете прочитать индекс из переменных окружения process.env.TEST_WORKER_INDEX
и process.env.TEST_PARALLEL_INDEX
, или получить к ним доступ через testInfo.workerIndex и testInfo.parallelIndex.
Изоляция данных теста между параллельными рабочими процессами
Вы можете использовать process.env.TEST_WORKER_INDEX
или testInfo.workerIndex, упомянутые выше, чтобы изолировать данные пользователя в базе данных между тестами, выполняемыми на разных рабочих процессах. Все тесты, выполняемые рабочим процессом, используют одного и того же пользователя.
Создайте файл playwright/fixtures.ts
, который будет создавать фикстуру dbUserName
и инициализировать нового пользователя в тестовой базе данных. Используйте testInfo.workerIndex, чтобы различать рабочие процессы.
import { test as baseTest, expect } from '@playwright/test';
// Импортируйте утилиты проекта для управления пользователями в тестовой базе данных.
import { createUserInTestDatabase, deleteUserFromTestDatabase } from './my-db-utils';
export * from '@playwright/test';
export const test = baseTest.extend<{}, { dbUserName: string }>({
// Возвращает имя пользователя базы данных, уникальное для рабочего процесса.
dbUserName: [async ({ }, use) => {
// Используйте workerIndex как уникальный идентификатор для каждого рабочего процесса.
const userName = `user-${test.info().workerIndex}`;
// Инициализируйте пользователя в базе данных.
await createUserInTestDatabase(userName);
await use(userName);
// Очистите после завершения тестов.
await deleteUserFromTestDatabase(userName);
}, { scope: 'worker' }],
});
Теперь каждый тестовый файл должен импортировать test
из нашего файла фикстур вместо @playwright/test
.
// Важно: импортируйте наши фикстуры.
import { test, expect } from '../playwright/fixtures';
test('test', async ({ dbUserName }) => {
// Используйте имя пользователя в тесте.
});
Управление порядком тестов
Playwright Test выполняет тесты из одного файла в порядке их объявления, если вы не параллелизируете тесты в одном файле.
Нет гарантии порядка выполнения тестов между файлами, так как Playwright Test по умолчанию выполняет тестовые файлы параллельно. Однако, если вы отключите параллелизм, вы можете управлять порядком тестов, либо называя ваши файлы в алфавитном порядке, либо используя файл "списка тестов".
Сортировка тестовых файлов в алфавитном порядке
Когда вы отключаете параллельное выполнение тестов, Playwright Test выполняет тестовые файлы в алфавитном порядке. Вы можете использовать какую-то конвенцию именования, чтобы управлять порядком тестов, например 001-user-signin-flow.spec.ts
, 002-create-new-document.spec.ts
и так далее.
Использование файла "списка тестов"
Списки тестов не рекомендуются и поддерживаются только на уровне лучших усилий. Некоторые функции, такие как расширение VS Code и трассировка, могут не работать должным образом со списками тестов.
Вы можете разместить ваши тесты в вспомогательных функциях в нескольких файлах. Рассмотрите следующий пример, где тесты не определены напрямую в файле, а скорее в обертке функции.
import { test, expect } from '@playwright/test';
export default function createTests() {
test('feature-a example test', async ({ page }) => {
// ... тест здесь
});
}
import { test, expect } from '@playwright/test';
export default function createTests() {
test.use({ viewport: { width: 500, height: 500 } });
test('feature-b example test', async ({ page }) => {
// ... тест здесь
});
}
Вы можете создать файл списка тестов, который будет управлять порядком тестов - сначала выполнить тесты feature-b
, затем тесты feature-a
. Обратите внимание, как каждый тестовый файл обернут в блок test.describe()
, который вызывает функцию, где определены тесты. Таким образом, вызовы test.use()
влияют только на тесты из одного файла.
import { test } from '@playwright/test';
import featureBTests from './feature-b.spec.ts';
import featureATests from './feature-a.spec.ts';
test.describe(featureBTests);
test.describe(featureATests);
Теперь отключите параллельное выполнение, установив количество рабочих процессов равным одному, и укажите ваш файл списка тестов.
import { defineConfig } from '@playwright/test';
export default defineConfig({
workers: 1,
testMatch: 'test.list.ts',
});
Не определяйте ваши тесты напрямую во вспомогательном файле. Это может привести к неожиданным результатам, так как ваши тесты теперь зависят от порядка import
/require
выражений. Вместо этого оберните тесты в функцию, которая будет явно вызвана файлом списка тестов, как в примере выше.