За 10 лет работы с сайтами я насмотрелся на самые разные косяки: от падения интернет-магазина в пятницу вечером до багов, которые обнаруживались только через месяц после релиза. И честно говоря, большинство из них можно было предотвратить с помощью автоматического тестирования.
Что такое автоматическое тестирование сайта
Автоматическое тестирование — это процесс проверки работоспособности сайта с помощью специальных программ без участия человека. Грубо говоря, вместо того чтобы каждый раз вручную кликать по кнопкам и формам, вы пишете сценарии, которые делают это за вас.
На моей практике был клиент с интернет-магазином на Bitrix, где после каждого обновления что-то ломалось. То корзина не работает, то форма заказа глючит. Мы внедрили автотесты — и количество багов на проде сократилось в разы.
Автотесты бывают разных уровней:
- Unit-тесты — проверяют отдельные функции и методы
- Интеграционные тесты — тестируют взаимодействие компонентов
- E2E-тесты — проверяют весь пользовательский путь от начала до конца
- Тесты производительности — замеряют скорость работы
- Тесты безопасности — ищут уязвимости
Для веб-сайтов чаще всего используются E2E-тесты и интеграционные. Они покрывают основные пользовательские сценарии: регистрацию, авторизацию, оформление заказа, отправку форм.
Почему автотесты необходимы
Ручное тестирование — это боль. Особенно когда у вас сложный сайт с кучей функций. Я помню проект на Laravel, где после каждого деплоя приходилось час тестировать админку вручную. А если что-то находили — откатывали и тестировали заново.
Основные проблемы ручного тестирования:
- Занимает много времени — на полную проверку сложного сайта может уйти 2-3 часа
- Человеческий фактор — можно пропустить баг или протестировать не все сценарии
- Дорого — время разработчика стоит денег
- Нельзя тестировать часто — никто не будет проверять сайт после каждого коммита
Автотесты решают эти проблемы кардинально. На том же Laravel-проекте мы настроили CI/CD pipeline с автотестами — теперь каждый коммит автоматически проверяется за 5 минут. Если что-то сломалось, сразу получаем уведомление в Slack.
Конкретные преимущества автотестирования:
Быстрая обратная связь. Вместо часа ручного тестирования — 5-10 минут автоматической проверки. У одного клиента мы сократили время тестирования с 2 часов до 15 минут.
Постоянная проверка. Автотесты можно запускать хоть каждый час. Особенно полезно для сайтов с частыми обновлениями контента.
Покрытие edge cases. Автотесты не забывают проверить редкие сценарии, которые человек может пропустить. Например, что происходит, если в корзину добавить товар с нулевой ценой.
Регрессионное тестирование. Автотесты гарантируют, что новый функционал не сломал старый. Это особенно критично для сложных проектов на Bitrix с множественными доработками.
Виды автотестов для сайтов
За годы работы я перепробовал разные подходы к тестированию. Некоторые оказались полезными, другие — пустой тратой времени. Расскажу про те, которые реально работают в веб-разработке.
End-to-End тестирование
Это тестирование полного пользовательского пути. Например, пользователь заходит на сайт, регистрируется, добавляет товар в корзину, оформляет заказ. E2E-тесты имитируют действия реального пользователя в браузере.
Популярные инструменты: Playwright, Cypress, Selenium. Лично я предпочитаю Playwright — быстрый, стабильный, хорошо работает с современными фреймворками.
// Пример E2E-теста для оформления заказа
import { test, expect } from '@playwright/test';
test('оформление заказа работает', async ({ page }) => {
await page.goto('/catalog/');
// Добавляем товар в корзину
await page.click('[data-testid="add-to-cart-123"]');
await expect(page.locator('.cart-counter')).toContainText('1');
// Переходим в корзину
await page.click('[data-testid="cart-link"]');
await expect(page).toHaveURL('/cart/');
// Оформляем заказ
await page.fill('[name="name"]', 'Иван Иванов');
await page.fill('[name="phone"]', '+7 900 123-45-67');
await page.click('[type="submit"]');
// Проверяем успешное оформление
await expect(page.locator('.success-message')).toBeVisible();
});
API-тестирование
Если у вас есть API (а в современных сайтах оно есть почти всегда), его тоже нужно тестировать. API-тесты быстрые, стабильные и покрывают бизнес-логику без UI.
У меня был проект на WordPress с кастомным REST API для мобильного приложения. API-тесты помогли поймать кучу багов ещё до того, как их увидели мобильные разработчики.
// Тест API регистрации пользователя
test('POST /api/register создаёт пользователя', async ({ request }) => {
const response = await request.post('/api/register', {
data: {
email: 'test@example.com',
password: 'password123',
name: 'Test User'
}
});
expect(response.status()).toBe(201);
const user = await response.json();
expect(user.email).toBe('test@example.com');
expect(user.id).toBeDefined();
});
Тесты производительности
Скорость работы сайта критично важна. Я использую автоматические тесты производительности, чтобы отслеживать деградацию скорости после изменений. Особенно полезно для оптимизации Core Web Vitals.
Инструменты: Lighthouse CI, WebPageTest API, K6 для нагрузочного тестирования.
Визуальное тестирование
Автоматическое сравнение скриншотов до и после изменений. Помогает поймать визуальные регрессии — когда вёрстка поехала, но функционально всё работает.
Честно говоря, визуальные тесты капризные. Малейшее изменение шрифта или цвета — и тест падает. Но для критичных страниц (главная, каталог товаров) они полезны.
Инструменты для автотестирования
За годы работы я перепробовал десятки инструментов. Некоторые отлично подходят для простых сайтов, другие — только для сложных enterprise-проектов. Расскажу про те, которыми пользуюсь сам.
Playwright
Мой текущий фаворит для E2E-тестирования. Быстрый, стабильный, поддерживает все современные браузеры. Отлично работает с SPA на React/Vue и серверными приложениями на PHP.
Плюсы:
- Быстрое выполнение тестов
- Автоматическое ожидание элементов
- Встроенные инструменты для дебага
- Поддержка мобильных браузеров
Минусы:
- Относительно новый инструмент (меньше туториалов)
- Требует Node.js
Cypress
Популярная альтернатива Playwright. Хороший DX (developer experience), много документации и примеров. Но работает медленнее и только в Chromium-браузерах.
Cypress отлично подходит для команд, которые только начинают с автотестирования. Простой синтаксис, наглядная отладка.
Selenium
Старожил среди инструментов автотестирования. Поддерживает все языки программирования, все браузеры. Но медленный и капризный в настройке.
Selenium стоит использовать, только если у вас специфичные требования — например, тестирование в старых браузерах или интеграция с существующей Java/C#-инфраструктурой.
PHPUnit для backend-тестирования
Если ваш сайт написан на PHP (Laravel, Bitrix, WordPress), PHPUnit — must-have для unit и интеграционных тестов.
'regular']);
$discount = $calculator->calculate($user, 1000);
$this->assertEquals(50, $discount); // 5% скидка
}
public function testCalculateDiscountForVipUser()
{
$calculator = new DiscountCalculator();
$user = new User(['type' => 'vip']);
$discount = $calculator->calculate($user, 1000);
$this->assertEquals(150, $discount); // 15% скидка
}
}
Jest для JavaScript
Если у вас много фронтенд-логики на JavaScript, Jest покроет unit-тестирование. Особенно полезно для SPA и сложных форм с валидацией.
Lighthouse CI
Автоматическое тестирование производительности. Интегрируется с CI/CD, отслеживает метрики скорости сайта. У одного клиента мы настроили Lighthouse CI — теперь каждый деплой проверяется на скорость автоматически.
Настройка автотестов на практике
Теория — это хорошо, но на практике всегда возникают нюансы. Покажу, как я настраиваю автотестирование на реальных проектах.
Настройка Playwright для сайта на Laravel
Допустим, у нас есть интернет-магазин на Laravel. Хотим автоматизировать тестирование основных пользовательских сценариев.
Сначала устанавливаем Playwright:
npm init playwright@latest
npx playwright install
Создаём базовый конфиг:
// playwright.config.js
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
use: {
baseURL: process.env.BASE_URL || 'http://localhost:8000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 5'] },
},
],
webServer: {
command: 'php artisan serve',
url: 'http://localhost:8000',
reuseExistingServer: !process.env.CI,
},
});
Теперь пишем тест для регистрации пользователя:
// tests/e2e/registration.spec.js
import { test, expect } from '@playwright/test';
test.describe('Регистрация пользователя', () => {
test('успешная регистрация с валидными данными', async ({ page }) => {
await page.goto('/register');
// Заполняем форму
await page.fill('[name="name"]', 'Тест Тестов');
await page.fill('[name="email"]', `test${Date.now()}@example.com`);
await page.fill('[name="password"]', 'SecurePass123');
await page.fill('[name="password_confirmation"]', 'SecurePass123');
// Отправляем форму
await page.click('button[type="submit"]');
// Проверяем редирект на главную
await expect(page).toHaveURL('/dashboard');
// Проверяем, что пользователь авторизован
await expect(page.locator('[data-testid="user-menu"]')).toBeVisible();
});
test('ошибка при невалидном email', async ({ page }) => {
await page.goto('/register');
await page.fill('[name="name"]', 'Тест Тестов');
await page.fill('[name="email"]', 'invalid-email');
await page.fill('[name="password"]', 'SecurePass123');
await page.fill('[name="password_confirmation"]', 'SecurePass123');
await page.click('button[type="submit"]');
// Проверяем, что остались на странице регистрации
await expect(page).toHaveURL('/register');
// Проверяем сообщение об ошибке
await expect(page.locator('.error-message')).toContainText('некорректный email');
});
});
Интеграция с CI/CD
Автотесты бесполезны, если их не запускать автоматически. Я настраиваю их в GitHub Actions или GitLab CI.
Пример конфига для GitHub Actions:
# .github/workflows/tests.yml
name: E2E Tests
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: testing
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
extensions: mbstring, pdo_mysql
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
- name: Setup Laravel
run: |
cp .env.testing .env
php artisan key:generate
php artisan migrate --force
php artisan db:seed --force
- name: Install Playwright
run: |
npm install
npx playwright install chromium
- name: Run E2E tests
run: npx playwright test
- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-results
path: test-results/
Тестирование на разных окружениях
На практике сайт ведёт себя по-разному в development, staging и production. Я настраиваю тесты так, чтобы они работали на всех окружениях.
Использую переменные окружения для разных конфигов:
# .env.testing
APP_ENV=testing
APP_URL=http://localhost:8000
DB_DATABASE=testing
# .env.staging
APP_ENV=staging
APP_URL=https://staging.example.com
DB_DATABASE=staging
# .env.production
APP_ENV=production
APP_URL=https://example.com
DB_DATABASE=production
И адаптирую тесты под окружение:
// utils/config.js
export const config = {
baseURL: process.env.BASE_URL || 'http://localhost:8000',
isProduction: process.env.NODE_ENV === 'production',
timeout: process.env.NODE_ENV === 'production' ? 30000 : 10000,
};
// tests/e2e/checkout.spec.js
import { config } from '../utils/config.js';
test('оформление заказа', async ({ page }) => {
// На продакшене используем тестовые данные
const testEmail = config.isProduction
? 'test+automation@example.com'
: 'test@example.com';
await page.fill('[name="email"]', testEmail);
// остальная логика теста...
});
Тестирование сайтов на Bitrix
Bitrix — особенная CMS со своими нюансами. За годы работы с ней я выработал подходы к тестированию, которые реально работают.
Специфика тестирования Bitrix
Главная проблема Bitrix — сложная структура и множество зависимостей. Компоненты могут использовать кеширование, подключать внешние модули, обращаться к API. Простые unit-тесты здесь не очень эффективны.
Я фокусируюсь на интеграционных и E2E-тестах. Они покрывают реальные пользовательские сценарии с учётом всех особенностей Bitrix.
Настройка тестового окружения
Для Bitrix нужно отдельное тестовое окружение с копией БД. Я создаю отдельный dbconn.php для тестов:
И переключатель в зависимости от окружения:
Тестирование компонентов Bitrix
Для тестирования кастомных компонентов я использую PHPUnit с инициализацией ядра Bitrix:
Add([
'NAME' => 'Тестовый каталог',
'CODE' => 'test_catalog',
'IBLOCK_TYPE_ID' => 'catalog',
'SITE_ID' => 's1',
]);
// Добавляем тестовый товар
$element = new \CIBlockElement();
$elementId = $element->Add([
'IBLOCK_ID' => $iblockId,
'NAME' => 'Тестовый товар',
'ACTIVE' => 'Y',
'PREVIEW_TEXT' => 'Описание товара',
]);
// Тестируем компонент
global $APPLICATION;
ob_start();
$APPLICATION->IncludeComponent(
'custom:catalog.list',
'',
['IBLOCK_ID' => $iblockId]
);
$output = ob_get_clean();
$this->assertStringContainsString('Тестовый товар', $output);
// Очищаем тестовые данные
\CIBlockElement::Delete($elementId);
\CIBlock::Delete($iblockId);
}
}
E2E-тестирование интернет-магазина на Bitrix
Для полноценного тестирования интернет-магазина я использую Playwright с учётом особенностей Bitrix:
// tests/e2e/bitrix-shop.spec.js
import { test, expect } from '@playwright/test';
test.describe('Интернет-магазин Bitrix', () => {
test.beforeEach(async ({ page }) => {
// Bitrix может долго грузиться
page.setDefaultTimeout(30000);
});
test('добавление товара в корзину', async ({ page }) => {
await page.goto('/catalog/');
// Ждём загрузки каталога (Bitrix может подгружать компоненты)
await page.waitForSelector('.catalog-item', { timeout: 10000 });
// Кликаем на первый товар
await page.click('.catalog-item:first-child .btn-buy');
// Ждём обновления корзины (AJAX)
await page.waitForFunction(() => {
const counter = document.querySelector('.basket-counter');
return counter && parseInt(counter.textContent) > 0;
});
// Проверяем, что товар добавился
await expect(page.locator('.basket-counter')).toContainText('1');
});
test('оформление заказа', async ({ page }) => {
// Добавляем товар в корзину
await page.goto('/catalog/');
await page.click('.catalog-item:first-child .btn-buy');
await page.waitForSelector('.basket-counter:has-text("1")');
// Переходим в корзину
await page.click('.basket-link');
await expect(page).toHaveURL(/\/personal\/cart\//);
// Оформляем заказ
await page.click('.btn-order');
await page.fill('[name="ORDER_PROP_1"]', 'Тест Тестович'); // ФИО
await page.fill('[name="ORDER_PROP_2"]', 'test@example.com'); // Email
await page.fill('[name="ORDER_PROP_3"]', '+7 900 123-45-67'); // Телефон
await page.click('.btn-order-submit');
// Проверяем успешное оформление
await expect(page.locator('.order-success')).toBeVisible();
await expect(page.locator('.order-number')).toContainText(/№\s*\d+/);
});
});
Важный нюанс: Bitrix активно использует AJAX и может долго инициализироваться. Поэтому я всегда увеличиваю таймауты и добавляю explicit waits.
Также полезно тестировать кеширование в Bitrix — проверять, что после очистки кеша сайт работает корректно.
Тестирование сайтов на WordPress
WordPress — совершенно другая история. Здесь много готовых плагинов, но каждый может сломаться после обновления. Плюс кастомные темы с собственной логикой.
Unit-тестирование WordPress
WordPress предоставляет собственную тестовую среду на базе PHPUnit. Честно говоря, настройка муторная, но результат того стоит.
# Установка WP test suite
bash bin/install-wp-tests.sh wordpress_test root 'password' localhost latest
Пример теста для кастомного плагина:
assertStringContainsString('
E2E-тестирование WordPress
Для E2E-тестирования WordPress я использую Playwright с учётом особенностей админки:
// tests/e2e/wordpress-admin.spec.js
import { test, expect } from '@playwright/test';
test.describe('Админка WordPress', () => {
test.beforeEach(async ({ page }) => {
// Авторизуемся в админке
await page.goto('/wp-admin/');
await page.fill('#user_login', 'admin');
await page.fill('#user_pass', 'password');
await page.click('#wp-submit');
await expect(page).toHaveURL(/wp-admin\/(?:index\.php)?$/);
});
test('создание нового поста', async ({ page }) => {
// Переходим к созданию поста
await page.click('text=Записи');
await page.click('text=Добавить новую');
// Заполняем пост
await page.fill('[data-testid="post-title"]', 'Тестовый пост');
// Работаем с Gutenberg редактором
await page.click('[data-type="core/paragraph"]');
await page.keyboard.type('Содержимое тестового поста');
// Публикуем
await page.click('text=Опубликовать');
await page.click('text=Опубликовать', { nth: 1 }); // подтверждение
// Проверяем успешную публикацию
await expect(page.locator('text=Запись опубликована')).toBeVisible();
// Проверяем на фронтенде
await page.click('text=Просмотреть запись');
await expect(page.locator('h1')).toContainText('Тестовый пост');
});
test('обновление плагина', async ({ page }) => {
await page.goto('/wp-admin/plugins.php');
// Ищем плагин с обновлением
const updateLink = page.locator('.update-now').first();
if (await updateLink.count() > 0) {
await updateLink.click();
// Ждём завершения обновления
await expect(page.locator('.notice-success')).toBeVisible({ timeout: 30000 });
// Проверяем, что сайт работает
await page.goto('/');
await expect(page.locator('body')).toBeVisible();
}
});
});
Тестирование WooCommerce
Если у вас интернет-магазин на WooCommerce, критично важно тестировать процесс покупки:
// tests/e2e/woocommerce.spec.js
test('покупка товара в WooCommerce', async ({ page }) => {
// Добавляем товар в корзину
await page.goto('/shop/');
await page.click('.product:first-child .add_to_cart_button');
// Ждём добавления (WooCommerce использует AJAX)
await page.waitForSelector('.cart-contents-count:not(:empty)');
// Переходим в корзину
await page.click('.cart-contents');
await expect(page).toHaveURL(/\/cart\//);
// Оформляем заказ
await page.click('.checkout-button');
// Заполняем данные покупателя
await page.fill('#billing_first_name', 'Иван');
await page.fill('#billing_last_name', 'Петров');
await page.fill('#billing_email', 'ivan@example.com');
await page.fill('#billing_phone', '+7 900 123-45-67');
// Выбираем способ оплаты
await page.check('#payment_method_cod'); // наложенный платёж
// Размещаем заказ
await page.click('#place_order');
// Проверяем успешное оформление
await expect(page.locator('.woocommerce-order-received')).toBeVisible();
await expect(page.locator('.order-number')).toContainText(/\d+/);
});
У меня был клиент с WooCommerce, где после обновления плагина сломалась интеграция с платёжной системой. Автотесты помогли поймать это за 5 минут вместо нескольких дней жалоб клиентов.
Мониторинг и алертинг
Автотесты — это не только про разработку. Их можно использовать для постоянного мониторинга работоспособности сайта. Особенно полезно для критичных бизнес-процессов.
Регулярные проверки
Я настраиваю автотесты на запуск каждые 30 минут через cron. Если что-то сломалось — сразу получаю уведомление в Slack.
# Cron для регулярного запуска тестов
*/30 * * * * cd /var/www/site && npm run test:critical > /dev/null 2>&1 || echo "Tests failed" | mail -s "Site tests failed" admin@example.com
Для этого создаю отдельный набор "smoke tests" — быстрые тесты критичного функционала:
// tests/smoke/critical.spec.js
import { test, expect } from '@playwright/test';
test.describe('Критичные проверки', () => {
test('главная страница загружается', async ({ page }) => {
await page.goto('/');
await expect(page.locator('h1')).toBeVisible({ timeout: 5000 });
});
test('форма обратной связи работает', async ({ page }) => {
await page.goto('/contacts/');
await page.fill('[name="name"]', 'Test');
await page.fill('[name="email"]', 'test@example.com');
await page.fill('[name="message"]', 'Test message');
await page.click('[type="submit"]');
await expect(page.locator('.success-message')).toBeVisible();
});
test('каталог товаров отображается', async ({ page }) => {
await page.goto('/catalog/');
await expect(page.locator('.product-item')).toHaveCount({ min: 1 });
});
});
Интеграция с мониторингом
Автотесты можно интегрировать с системами мониторинга типа Zabbix, Prometheus или DataDog. Я отправляю метрики успешности тестов:
// utils/monitoring.js
export async function sendMetrics(testResults) {
const metrics = {
tests_total: testResults.total,
tests_passed: testResults.passed,
tests_failed: testResults.failed,
response_time: testResults.avgResponseTime,
timestamp: Date.now()
};
// Отправляем в InfluxDB или другую TSDB
await fetch('http://monitoring.example.com/api/metrics', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(metrics)
});
}
Уведомления в Slack
Когда тесты падают, важно быстро об этом узнать. Я настраиваю уведомления в Slack:
// utils/notifications.js
export async function notifySlack(testResults) {
if (testResults.failed > 0) {
const message = {
text: `🚨 Тесты упали на ${process.env.SITE_URL}`,
attachments: [{
color: 'danger',
fields: [
{ title: 'Упавшие тесты', value: testResults.failed, short: true },
{ title: 'Всего тестов', value: testResults.total, short: true },
{ title: 'Время', value: new Date().toLocaleString(), short: true }
]
}]
};
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message)
});
}
}
У одного клиента такой мониторинг помог поймать проблему с платёжным шлюзом в 2 часа ночи. Без автотестов узнали бы только утром по жалобам покупателей.
Типичные ошибки и подводные камни
За годы работы с автотестами я наступил на все возможные грабли. Поделюсь самыми болезненными, чтобы вы их избежали.
Хрупкие селекторы
Самая частая проблема — тесты ломаются из-за изменений в вёрстке. Вчера кнопка была `.btn-primary`, сегодня стала `.button-submit` — и все тесты упали.
Плохо:
await page.click('.btn.btn-primary.btn-lg'); // сломается при изменении CSS
await page.click('div > ul > li:nth-child(3) > a'); // сломается при изменении структуры
Хорошо:
await page.click('[data-testid="submit-button"]'); // стабильно
await page.click('text=Отправить заказ'); // понятно и стабильно
Я всегда прошу верстальщиков добавлять data-testid для важных элементов. Это небольшие усилия, которые сэкономят кучу времени.
Зависимость от внешних сервисов
Тесты не должны зависеть от внешних API. Платёжные системы, SMS-сервисы, почтовые провайдеры — всё это может быть недоступно во время тестирования.
Я использую моки для внешних сервисов:
// utils/mocks.js
export async function mockPaymentGateway(page) {
await page.route('**/api/payment/**', route => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
status: 'success',
transaction_id: 'mock_12345',
payment_url: '/payment/success'
})
});
});
}
Слишком медленные тесты
Если тесты выполняются больше 10 минут, их никто не будет запускать. Я оптимизирую производительность тестов:
- Запуск тестов параллельно
- Переиспользование браузерных сессий
- Моки вместо реальных HTTP-запросов
- Отключение изображений и CSS в тестах
// playwright.config.js - оптимизация скорости
use: {
// Отключаем загрузку изображений
launchOptions: {
args: ['--disable-images']
},
// Блокируем ненужные ресурсы
extraHTTPHeaders: {
'Accept-Language': 'en-US'
}
}
Недетерминированные тесты
Тесты должны работать одинаково при каждом запуске. Но иногда они падают случайно из-за race conditions, асинхронности, случайных данных.
Типичные проблемы:
- Использование текущего времени в тестах
- Зависимость от порядка выполнения
- Недостаточные таймауты
- Конкурентное использование одних данных
Решения:
// Плохо - зависит от времени
test('создание события на завтра', async ({ page }) => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
await page.fill('[name="date"]', tomorrow.toISOString().split('T')[0]);
});
// Хорошо - фиксированная дата
test('создание события', async ({ page }) => {
await page.fill('[name="date"]', '2026-12-31');
});
// Плохо - race condition
test('проверка счётчика', async ({ page }) => {
await page.click('.increment-btn');
expect(await page.textContent('.counter')).toBe('1');
});
// Хорошо - ждём изменения
test('проверка счётчика', async ({ page }) => {
await page.click('.increment-btn');
await expect(page.locator('.counter')).toHaveText('1');
});
Избыточное тестирование
Не нужно тестировать всё подряд. 80% багов можно поймать 20% тестов. Я фокусируюсь на критичном функционале:
- Регистрация и авторизация
- Оформление заказов
- Отправка форм
- Интеграции с внешними сервисами
А вот тестировать цвет кнопок или отступы — пустая трата времени.
Помните: исправление ошибок на сайте обходится дороже, чем их предотвращение с помощью тестов. Но писать тесты тоже нужно с умом.
Автоматическое тестирование — это инвестиция в будущее проекта. На начальных этапах кажется, что проще протестировать вручную. Но когда проект растёт, автотесты становятся критично важными для поддержания качества и скорости разработки.
Начните с малого — автоматизируйте тестирование самых важных функций. Постепенно расширяйте покрытие. И помните: лучше 10 стабильных тестов, чем 100 нестабильных.
Хотите повысить качество своего сайта?
Внедрим систему автоматического тестирования, которая выявит ошибки до того, как их увидят пользователи.