«В этой небольшой статье мы рассмотрим, как применять функцию шардинга в Playwright для разделения тестов по частям-шардам, чтобы ускорить выполнение и сократить время обратной связи в CI. Но сначала хочу обсудить параллелизм в Playwright.
Параллелизм
В Playwright предусмотрен параллельный запуск тестов, и по умолчанию в файле playwright.config.js установлено значение true. При включении этой опции запускается несколько worker-процессов, выполняющихся одновременно. Тесты в одном файле запускаются последовательно в одном worker-процессе.

Параллельные тесты выполняются в отдельных рабочих процессах и могут не иметь общих состояний или общих глобальных переменных.
Существует несколько способов настроить параллельное выполнение тестов.
- Использование
test.describe.configure({ mode: 'parallel' }); - Также можем использовать
fullyParallel: true, чтобы включить параллельность для всех тестов - Или включить
fullyParallel: trueдля некоторых проектов, например chromium, firefox, webkit и т. д.
Чтобы отключить этот параллелизм, мы можем настроить запуск тестов с использованием только одного worker-а, через конфигурационный файл, установив для worker-ов значение 1, или передать то же самое из командной строки: npx playwright test — workers=1.
Подробнее о параллельном запуске — на сайте Playwright.
Что такое шардинг
Sharding происходит от концепции архитектуры баз данных, в которой мы разбиваем большую базу данных на несколько «кусков» или шардов, чтобы распределить и оптимизировать нагрузку, повысить эффективность и масштабируемость системы. Это можно назвать горизонтальным масштабированием, когда каждый шард ведет себя как независимая единица со своими собственными ресурсами и управляет данными соответствующим образом. Таким образом улучшается производительность запросов и устраняются точки отказа при использовании отдельного сервера базы данных, который обрабатывает огромные объемы данных.
Подробнее о шардинге здесь, а также замечательное видео.
Теперь, перейдя в мир Playwright, мы можем использовать концепцию шардинга для ускорения выполнения тестов путем разделения этих тестов по отдельным шардам, то есть машинам. Мы можем сделать это с помощью параметра shard, то есть shard=x/y, где x — индекс-shard, а y — общее количество шардов.
npx playwright test --shard=1/4 npx playwright test --shard=2/4 npx playwright test --shard=3/4 npx playwright test --shard=4/4
В данном случае мы разделили тесты на 4 шарда, поэтому указанное в конфигурации количество worker-ов будет работать с каждым из этих блоков, сокращая общее время выполнения.
Для демонстрационных целей я установил Playwright на локальной машине и буду использовать пример boilerplate-кода, представленный в папке tests-examples, где у нас есть несколько тестов, которые настроены для запуска на сайте playwright to-do mvc (URL: https://demo.playwright.dev/todomvc )
Здесь у нас 24 теста, которые запускаются на 3 браузерах, поэтому в целом 72 теста для одного файла, я скопировал один и тот же файл дважды, поэтому с 3 файлами спецификаций у нас 216 тестов в 3 браузерах — chromium, firefox и webkit. Я переименовал файлы спецификаций, как показано ниже.

В файле playwright.config.js я задал следующие конфигурации, установив значение parallel в true и значение workers в 6.
fullyParallel: true workers: process.env.CI ? 6 : 6
Это означает, что когда я выполню команду: npx playwright test, все 216 тестов будут запущены 6 worker-ами локально и в CI. Приведенные ниже тесты выполняются на локальной машине с использованием 6 worker-ов.

Теперь, когда я выполню команду npx playwright test вместе с параметром shard, указав общее количество шардов как 4, то сначала 216 тестов будут разделены на 4 куска по 54 теста в каждом. Затем эти 54 теста будут выполнены с помощью 6 worker-а в шарде 1, 54 теста с помощью 6 worker-ов в шарде 2, как показано ниже. Поскольку каждый шард будет выполняться на своей собственной машине-агенте, уровень параллелизма будет гораздо выше, и наши тесты будут выполняться значительно быстрее, чем при использовании 6 worker-ов в стандартной конфигурации.

Но с шардингом мы столкнулись с проблемой при создании репортов (с помощью стандартной опции html-репорта). После выполнения теста, выполнив команду ‘npx playwright show-report‘, мы увидим, что в сгенерированном отчете будут показаны только результаты последнего запущенного шарда, содержащего всего 54 теста, как показано ниже. А как быть с остальными, в предыдущих шардах?

Чтобы решить эту проблему, нам нужно сконфигурировать наш репортер как ‘blob’, когда мы используем шардинг. По умолчанию каждый шард будет генерировать свои собственные blob-репорты в папку под названием blob-report. Затем нам нужно будет объединить все эти отдельные blob-репорты со всех шардов, чтобы получить консолидированный репорт по всем тестам, которые были выполнены на всех шардах.
export default defineConfig({
reporter: process.env.CI ? 'blob' : 'html'
});
Чтобы объединить репорты из нескольких шардов, поместите файлы blob-репортов в один каталог, например, в нашем случае all-blob-reports, тогда окончательный HTML-репорт будет доступен в папке playwright-report.
npx playwright merge-reports --reporter html ./all-blob-reports
Шардинг в CI с помощью Github Actions
Теперь, чтобы еще эффективнее использовать шардинг, применим такие инструменты CI, как Github Actions, которые позволяют удобно настраивать и запускать тесты на нескольких машинах-агентах. Для этого нам нужно включить следующие пункты в наш файл рабочего процесса Github actions:
- Добавление стратегии с опцией
matrixв задачу со значениямиshardIndexиshardTotal. - Запуск команды
npx playwright testс указанием параметровshardindexиshardTotal. - Загрузить блоб-репорт отдельных шардов в артефакты Github actions, чтобы задача merge-report могла подхватить его и сгенерировать консолидированный HTML-отчет.
name: Sharding Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
run-tests:
timeout-minutes: 60
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4, 5, 6 ]
shardTotal: [6]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload blob report to GitHub Actions Artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: blob-report-${{ matrix.shardIndex }}
path: blob-report
retention-days: 1
Для задачи «run-tests» мы будем использовать в общей сложности 6 шардов, указанных в matrix, с параметром fail-fast, установленным на false. Затем мы выполним npx playwright test, используя определенные значения shardIndex и shardTotal, например 1/6, 2/6 и т. д. Наконец, когда все шарды будут выполнены, blob-репорты по каждому шарду будут загружены в артефакты Actions в разделе blob-report с суффиксом shardIndex.
Далее нам нужно добавить задачу «merge-reports«, которая будет зависеть от задачи run-tests. Эта задача будет загружать все отдельные blob-репорты шардов в указанную папку под названием all-blob-reports, а затем выполнять команду merge-reports, чтобы получить объединенный HTML-репорт и загрузить его на вкладку GitHub Actions Artifacts.
merge-reports:
if: always()
needs: [run-tests]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge into HTML Report
run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: Upload HTML report
uses: actions/upload-artifact@v4
with:
name: html-report--attempt-${{ github.run_attempt }}
path: playwright-report
retention-days: 7
Вот мой полный файл workflow вместе с задачами:
name: Playwright tests using sharding
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
run-tests:
timeout-minutes: 60
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4, 5, 6 ]
shardTotal: [6]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload blob report to GitHub Actions Artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: blob-report-${{ matrix.shardIndex }}
path: blob-report
retention-days: 1
merge-reports:
if: always()
needs: [run-tests]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge into HTML Report
run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: Upload HTML report
uses: actions/upload-artifact@v4
with:
name: html-report--attempt-${{ github.run_attempt }}
path: playwright-report
retention-days: 7
Как только файл workflow будет отправлен на Github, все тесты (216) будут распределены и запущены на определенных машинах шарда, в нашем случае на 6 машинах. Как видно ниже, 36 тестов выполняются на машине run-tests (1,6). Аналогично 36 тестов будут выполнены с помощью 6 worker-ов на другой машине шарда. После выполнения всех тестов будет запущена задача слияния репортов, которая сгенерирует консолидированный HTML-репорт.


Ниже приведены артефакты, которые были загружены в рамках выполнения workflow: индивидуальный блоб-репорт по шардам и итоговый консолидированный html-репорт.

Загрузив и открыв репорт, вы обнаружите полный отчет о прогоне тестов, содержащий 216 тестов, выполненных на 6 шард-машинах.

Вот что умеет Playwright. Спасибо за прочтение и надеемся, что эта статья была вам полезна.»
Официальная документация Playwright