Капча в e2e-тестах: как держать CI зелёным
Ваша форма регистрации защищена PopularCaptcha. Ваш end-to-end набор тестов должен регистрироваться. Теперь CI красный, и соблазнительное решение — отключить капчу в тестовой сборке — означает, что тестируемый поток не совпадает с тем, что получают ваши пользователи.
Есть несколько выходов. Они различаются по тому, насколько полно они воспроизводят реальный поток, поэтому выбирайте тот, который соответствует вопросу, на который отвечает ваш тест. Вот варианты от самого дешёвого к самому реалистичному.
Scarnox решает PopularCaptcha сегодня. Другие типы капч скоро появятся, поэтому вариант с решением ниже — только для PopularCaptcha.
1. Тестовые ключи для юнит- и локальных тестов
Многие провайдеры капчи публикуют тестовые ключи, которые всегда проходят. Используйте их, когда контролируете окружение и нужно только, чтобы форма отрисовалась и отправилась. Тестовые ключи не проверяют реальную верификацию и не помогают, когда вы тестируете развёрнутое окружение с настоящими ключами.
2. Обход для собственного staging
Некоторые команды добавляют секретный заголовок, который бэкенд принимает вместо токена капчи. Это быстро и бесплатно, но это путь в коде, который существует только для тестов, и одна ошибка конфигурации отделяет его от продакшна. Если вы его используете, закройте его проверкой окружения, сделайте секрет длинным и случайным и проверьте, что на продакшне он отклоняется.
3. Замокать вызов верификации
Заглушите серверный запрос верификации в интеграционных тестах. Это хорошо для проверки логики бэкенда, например того, что происходит при неудачной верификации. Но это ничего не говорит о том, отправляет ли фронтенд токен правильно, поэтому сочетайте этот вариант с одним из других.
4. Решайте капчу по-настоящему в staging и smoke-тестах
Когда нужно доказать, что реальный поток работает от начала до конца — с реальными ключами, настоящим виджетом и настоящей верификацией, — получите токен из API решения капчи внутри теста. Это единственный вариант, который ловит поломку интеграции виджета.
Вспомогательная функция для Playwright выглядит так:
// Вспомогательная функция для теста Playwright
export async function solveCaptcha(page) {
const sitekey = await page.getAttribute("[data-sitekey]", "data-sitekey");
const r = await fetch("https://api.scarnox.com/api/tasks/create", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SCARNOX_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
captcha_type: "PopularCaptchaTaskProxyless",
site_key: sitekey,
site_url: page.url(),
}),
});
const { errorId, solution, errorCode, errorDescription } = await r.json();
if (errorId !== 0) throw new Error(`${errorCode}: ${errorDescription}`);
await page.evaluate((t) => {
document.querySelectorAll('[name="h-captcha-response"],[name="g-recaptcha-response"]')
.forEach((el) => { el.value = t; });
}, solution.token);
}
Вызывайте её прямо перед отправкой формы в тесте, а не в начале теста. Токены истекают примерно через две минуты, и медленный шаг раньше в тесте может съесть это окно.
Держите количество решений на минимуме
Набор, который регистрируется при каждом запуске, может сделать за неделю много решений. Держите их число небольшим:
- Запускайте реальное решение только в staging и в smoke-тесте. Остальные варианты используйте на каждом коммите.
- Запускайте реальное решение один раз на пайплайн, а не один раз на файл с тестами.
- Ограничьте число решений на запуск в своей вспомогательной функции. Тест, который упал из-за достигнутого лимита, — понятный сигнал пересмотреть набор.
- Неудачные решения не списываются, поэтому нестабильный шаг стоит времени, а не денег. Но набор, который слепо повторяет попытки, всё равно тратит минуты раннера.
Правила повторов внутри функции возьмите из обработки ошибок и backoff.
Храните ключ вне репозитория
Сохраните ключ как секрет CI, например с именем SCARNOX_KEY, и никогда не кладите его в код тестов или фикстуры. Если он утёк, перевыпустите его в панели управления. Старый ключ перестанет работать сразу, поэтому утёкший ключ нельзя долго использовать для запуска решений.
Для CI используйте отдельный ключ. Если один пайплайн работает неправильно, вы сможете сменить ключ, не трогая остальное.
Попробуйте на собственном staging
Создайте аккаунт и начните с пробного баланса, карта не нужна. Подключите вспомогательную функцию сначала к одному smoke-тесту, убедитесь, что регистрация проходит чисто, и только потом добавляйте её в остальной набор. Сколько стоят решения при большом объёме, см. в актуальных тарифах.
Что проверять после отправки
Решённая капча подтверждает только то, что шаг с виджетом сработал. После отправки проверьте то, что важно пользователю: загрузилась следующая страница, появилось сообщение об успехе и аккаунт или заказ существует в вашей базе данных. Тест, который останавливается на «ошибок в форме нет», может пройти, хотя регистрация на бэкенде тихо падает.
Держите проверки ближе к бизнес-результату. Проверьте URL, видимое сообщение и одну запись, которую создал тест. Удалите эту запись в конце запуска, чтобы следующий запуск начинался из известного состояния.
Запуск smoke-теста по расписанию
Запускайте smoke-тест с реальным решением по расписанию, например раз в сутки на staging, а не на каждом pull request. Запуски по расписанию ловят изменения, которые сайт выкатил за ночь, например новую версию виджета или смененный sitekey, и не тратят решения на каждый коммит. Оповещайте команду, когда запуск по расписанию падает, а набор на каждый коммит держите на более быстрых вариантах.