Если ваши JavaScript-тесты работают дольше, чем ваш кофе, вы не одиноки. Многие команды сталкиваются с тем, что запуск тестового набора занимает 5, 10 или даже 15 минут - это не просто раздражает, это ломает поток разработки. Каждая задержка в обратной связи означает, что вы теряете концентрацию, отвлекаетесь, а потом тратите ещё время, чтобы снова войти в режим. Но есть реальные способы сократить это время в 5-7 раз. И они работают прямо сейчас - без сложных изменений в архитектуре.
Шардирование: разделяй и властвуй
Шардирование - это когда вы разбиваете весь набор тестов на несколько частей и запускаете их одновременно на разных процессах или машинах. Просто представьте: вместо того чтобы проходить через 800 тестов один за другим, вы запускаете три потока, каждый обрабатывает около 260 тестов. Результат? Время выполнения падает почти в три раза.Playwright - один из немногих фреймворков, который делает это встроенными командами. Никаких кастомных скриптов, никаких хаков. Просто:
npx playwright test --shard=1/3npx playwright test --shard=2/3npx playwright test --shard=3/3
Эти три команды запускаются параллельно в CI-системе, и вместе они выполняют весь набор тестов быстрее, чем одна команда. Playwright сам распределяет тесты между шардами. Это работает без лишней настройки, даже в бесплатной версии. Cypress, к примеру, требует платной подписки, чтобы получить такую же функциональность.
На практике, при трёх шардах, вы получаете 70-80% ускорения. Не 100%, потому что есть накладные расходы: синхронизация, передача данных, конкуренция за CPU и память. Но 70% - это не мелочь. Это значит, что 10-минутный прогон превращается в 3 минуты.
Selective-run: запускай только то, что изменилось
Запускать все тесты каждый раз - как чистить всю квартиру, потому что вы запачкали одну чашку. Это неэффективно. Selective-run - это стратегия, при которой вы запускаете только те тесты, которые зависят от кода, который вы только что изменили.Как это работает? Система анализирует, какие файлы вы изменили, и смотрит, какие тесты используют эти файлы. Если вы изменили функцию calculateTax(), то запускаются только тесты, которые проверяют эту функцию или код, который от неё зависит. Остальные - пропускаются.
В крупных проектах (100 000+ строк кода) это даёт 50-90% ускорения. В одном случае команда сократила время с 615 секунд до 101 секунды - почти в шесть раз. И это не потому что они купили новые серверы. Они просто перестали запускать тесты, которые не имели отношения к их изменениям.
Такой подход особенно мощен в CI/CD: вы запускаете полный набор тестов только на мастере, а в пул-реквестах - только те, что затронуты. Это экономит не только время, но и ресурсы CI-системы. А это значит, меньше очередей и быстрее деплой.
Мелкие правки, большие результаты
Не думайте, что ускорение - это только про инфраструктуру. Иногда самые большие выигрыши приходят от мелочей.Одна команда обнаружила, что в 25 тестах стояли таймауты по 10-11 секунд. При этом реальное время выполнения операции - 20 миллисекунд. Это как ставить 10-минутный таймер, чтобы проверить, закипела ли вода. Они заменили их на 200 мс - и сразу сэкономили 8 минут в каждом прогоне.
Другой пример: тест на гонку потоков делал 100 000 итераций с задержками. Каждая итерация ждала 350-450 мс. Всё это заняло 10 секунд на запись и ещё 10 - на чтение. После анализа оказалось: достаточно 10 записей и 30 чтений. Время упало с 20 секунд до 150 мс. Это не улучшение инфраструктуры - это улучшение логики теста.
Такие правки не требуют переписывания всего проекта. Просто посмотрите на самые медленные тесты - те, что тянут среднее время вверх. Их можно найти через кастомный отчёт, который записывает время выполнения каждого теста. Обычно 5-10 самых тяжёлых тестов отвечают за 50% времени выполнения всего набора.
Тестовая пирамида: меньше E2E, больше юнит-тестов
Если ваш набор тестов состоит из 70% end-to-end тестов, вы уже проиграли. E2E-тесты (например, через Playwright или Cypress) запускают браузер, загружают страницу, кликают, ждут загрузки - это может занимать 10-30 секунд на один тест. А юнит-тесты? Они просто вызывают функцию и проверяют возвращаемое значение. За 5-20 мс.Согласно принципу тестовой пирамиды, идеальное соотношение - 70% юнит-тестов, 20% интеграционных, 10% E2E. Большинство команд наоборот: 80% E2E. Это приводит к долгим запускам и нестабильности. Потому что E2E-тесты ломаются от малейших изменений в интерфейсе, даже если логика работает.
Если вы перепишете 30% E2E-тестов в юнит-тесты, вы сэкономите десятки минут в неделю. Это не теория - это практика. Команды, которые сделали этот переход, сообщают о снижении времени выполнения тестов на 40-60% без каких-либо изменений в CI-инфраструктуре.
Повторное использование состояния: не аутентифицируйтесь каждый раз
Если у вас есть 50 тестов, которые проверяют разные сценарии после входа в систему - вы не должны входить в систему 50 раз. Каждый вход занимает 1-3 секунды. 50 раз - это 50-150 секунд. Это просто слив.Современные фреймворки позволяют сохранять состояние аутентификации между тестами. Например, Playwright может сохранить куки после первого входа и использовать их для всех последующих тестов. Это называется test reuse. Вы получаете 10-30% ускорения без изменений в логике тестов.
Важно: нужно следить, чтобы состояние не «загрязнялось». Если один тест меняет данные, а другой их использует - могут возникнуть ложные срабатывания. Решение? Изолируйте данные. Используйте чистые сессии для каждого шарда или создавайте уникальных пользователей для каждого теста. Это не сложно - и это стоит того.
Инфраструктура: меньше контейнеров, меньше времени
В CI-системах часто запускают тесты в двух контейнерах: один для приложения, второй для базы данных. Это логично, но не всегда нужно. В одном случае команда объединила оба контейнера в один - и сэкономила 16 секунд на каждом запуске. Почему? Потому что запуск второго контейнера, сеть, ожидание готовности - всё это занимает время.Если ваше приложение работает с SQLite или встроенными БД (например, в тестах), то не нужно запускать PostgreSQL в отдельном контейнере. Это упрощает CI-конфигурацию, уменьшает нагрузку на сервер и ускоряет запуск. Это не всегда возможно, но если возможно - сделайте это.
Сколько параллельных потоков - оптимально?
Вы не можете просто запустить 20 потоков и ожидать, что всё будет в 20 раз быстрее. Есть закон Амдала: если часть процесса не может быть параллелизована, то ускорение ограничено. Но в тестах проблема не в этом. Проблема в конкуренции за ресурсы.Один из проектов выяснил: три параллельных потока - это идеал. Четвёртый и пятый не ускоряют, а замедляют. Почему? Потому что CPU перегружается, диски начинают тормозить, сеть переполняется. Слишком много одновременных запросов к базе - и все тесты начинают ждать. Это как 10 человек, пытающихся пройти через одну дверь.
Не гонитесь за числом. Проверьте на своей инфраструктуре. Запустите тесты с 1, 2, 3, 4 потоками. Замерьте время. Обычно максимум достигается на 2-4 потоках. Больше - только мусор.
Что работает лучше всего? Комбинация
Самый мощный результат - не от одного метода, а от их сочетания. Команда, которая сократила время с 615 секунд до 101 секунды, использовала:- Уменьшение таймаутов и итераций в тестах (68% ускорения)
- Шардирование на 3 потока (ещё 50% ускорения)
- Selective-run для пул-реквестов (ещё 40% ускорения)
- Повторное использование сессии аутентификации (ещё 15% ускорения)
Вместе - 6x ускорение. Ни один из этих методов по отдельности не дал бы такого эффекта. Это как собрать велосипед из лучших деталей - каждая важна.
Что делать прямо сейчас?
Если вы хотите начать ускорять тесты - вот простой план на неделю:- Запустите отчёт по времени выполнения каждого теста. Найдите 5 самых медленных.
- Проверьте, не стоят ли в них таймауты больше 1 секунды. Замените на реальное время.
- Включите шардирование в CI (если используете Playwright - это одна строчка в конфиге).
- Настройте selective-run для пул-реквестов (если используете GitHub Actions - есть готовые действия).
- Попробуйте повторно использовать аутентификацию между тестами.
Эти шаги займут не больше 2-3 дней. Результат - сокращение времени выполнения тестов на 40-60% уже в первую неделю. Не нужно ждать «идеального момента». Начните с одного теста. Потом с пяти. Потом с десяти. И вы удивитесь, насколько быстро всё изменится.
Будущее: ИИ и анализ влияния
Скоро тесты будут не просто запускаться, а предсказывать, какие из них нужно запустить. Системы на основе машинного обучения анализируют историю падений, изменения в коде и зависимости между модулями - и автоматически выбирают минимальный набор тестов для запуска. Уже сейчас есть инструменты, которые строят граф зависимостей кода и тестов. Они показывают: «Вы изменили файл X - запустите тесты Y, Z и Q».Это не фантастика. Это уже в продакшене у крупных компаний. Но даже без ИИ вы можете начать сегодня - с шардирования и selective-run. Это база. Остальное придет позже.
Какой фреймворк лучше для ускорения JavaScript-тестов - Playwright или Cypress?
Playwright быстрее и лучше подходит для ускорения. Он имеет встроенную поддержку шардирования и параллельного выполнения в бесплатной версии. Cypress требует платной подписки для этих функций. По замерам, Playwright выполняет тесты в среднем в 3 раза быстрее, чем Cypress, на одинаковых условиях. Если ваша цель - скорость, Playwright - выбор номер один.
Можно ли использовать selective-run без сложных инструментов?
Да. Даже в простых CI-системах, например, GitHub Actions, можно использовать скрипты, которые сравнивают изменения в git и определяют, какие тесты затронуты. Для этого не нужны дорогостоящие платформы. Достаточно команды git diff и простого скрипта на Node.js, который сопоставляет изменённые файлы с тестами. Многие команды реализуют это самостоятельно за пару дней.
Почему шардирование на 4 потока медленнее, чем на 3?
Потому что параллелизация не бесконечна. Когда вы запускаете слишком много процессов одновременно, они начинают конкурировать за ресурсы: CPU, память, сеть, диски. Это создаёт задержки. Вместо того чтобы ускорять тесты, вы замедляете их. Оптимальное число потоков зависит от вашей инфраструктуры. Лучше протестировать: 1, 2, 3, 4 - и выбрать тот, где время выполнения минимально.
Сколько времени занимает настройка selective-run?
От 1 до 3 дней. Если вы используете GitHub Actions и ваш проект имеет структурированную систему тестов - можно настроить за день. Нужно написать скрипт, который анализирует изменения в git и сопоставляет их с тестами. Для небольших проектов (менее 10 000 строк кода) это может не стоить усилий. Для крупных - это обязательная оптимизация.
Как узнать, какие тесты самые медленные?
Используйте отчёт с временем выполнения каждого теста. Playwright и Jest позволяют включить детальный вывод с временем. Например, в Playwright добавьте флаг --reporter=list. Он покажет, сколько секунд занял каждый тест. Найдите топ-10 самых долгих - и начните с них. Часто 5 тестов отвечают за 50% времени всего набора.