Sim, dá para automatizar os testes que passam por CAPTCHA: a API da CaptchaAI resolve o desafio e devolve o token que o Pytest ou o Selenium injetam no formulário. O CAPTCHA costuma ser o primeiro teste a quebrar quando a suíte de QA cresce — alguém resolve à mão, ou o CI trava esperando uma interação que nunca chega. Isso vale tanto para o pipeline de regressão que roda a cada deploy quanto para a suíte de ponta a ponta que só executa à noite.
Por que times de QA travam em fluxos com CAPTCHA
| Cenário | Por que a CaptchaAI ajuda |
|---|---|
| Teste de regressão | Funciona após o deploy |
| Teste de ponta a ponta | Jornada completa do usuário |
| Teste de carga | CAPTCHA da produção em escala |
| Teste entre navegadores | Renderiza igual em Chrome, Firefox e Edge |
| Teste de acessibilidade | Fluxos para leitor de tela |
Exemplo: um time de QA em São Paulo valida centenas de formulários por noite antes da Black Friday. Rodar isso à mão travaria a suíte a cada release; com a API integrada ao Pytest, o fluxo roda sozinho contra o ambiente de staging, sempre com CPFs e e-mails fictícios — o cuidado básico que a LGPD exige para qualquer dado de teste. Na manhã seguinte, o relatório do CI já mostra quais formulários quebraram, sem ninguém ter clicado em um único CAPTCHA durante a madrugada.
Como manter o custo dos testes de CAPTCHA sob controle
Resolver CAPTCHA de verdade tem custo por thread, não é ilimitado — e esse custo cresce rápido se a suíte inteira disparar CAPTCHA a cada push. As práticas abaixo mantêm o gasto previsível sem abrir mão de cobertura real:
| Estratégia | Benefício |
|---|---|
| Rodar contra staging | Desafio mais simples |
| Testes com CAPTCHA por agendamento, não a cada push | Reduz consumo da API |
| Cachear resultados de testes instáveis | Evita resolver à toa |
| Flag de ambiente para pular CAPTCHA localmente | Ciclo de dev mais rápido |
| Job de CI dedicado para testes com CAPTCHA | Controla custo por pipeline |
Perguntas frequentes
Quanto custa manter a suíte de QA resolvendo CAPTCHA todos os dias?
A CaptchaAI cobra por thread, não por solução — então rodar a suíte inteira todo dia não multiplica o custo por execução. O BASIC (US$ 15/mês, 5 threads) já cobre a maioria das suítes de QA; com mais paralelismo no CI, suba para o ADVANCE (US$ 90/mês, 50 threads).
Faz sentido resolver CAPTCHA de verdade em testes unitários?
Não. Testes unitários devem rodar em milissegundos e sem rede — simule a resposta do CAPTCHA nesse nível, como qualquer outra dependência externa. Resolva o desafio de verdade só na integração e no E2E, onde o objetivo é validar o fluxo completo contra staging.
hCaptcha funciona com a CaptchaAI nos testes de QA?
Ainda não. hCaptcha e FunCaptcha não são suportados hoje — simule esse fluxo nos testes até que o suporte seja lançado.
Preciso me preocupar com a LGPD nos logs desses testes?
Sim. Trate dados de teste como se fossem reais: use staging, e-mails e CPFs fictícios nos formulários, e evite gravar payloads completos — headers, cookies, tokens — nos logs do CI.
Os testes com CAPTCHA ficam instáveis (flaky) no pipeline?
Podem ficar, principalmente quando o timeout configurado é curto demais para o tempo real de resolução. Dê folga ao timeout — o helper deste guia usa 120 s — e trate erros de rede do provedor com uma retentativa antes de marcar o teste como quebrado.
Integração com Pytest: resolvendo CAPTCHA antes do teste rodar
O helper abaixo envia a tarefa e consulta o token; qualquer teste que precise de reCAPTCHA resolvido importa a fixture captcha_helper. A fixture tem escopo de sessão, então a chave de API é lida uma única vez e reaproveitada por toda a suíte.
import pytest
import requests
import time
class CaptchaTestHelper:
"""Helper for solving CAPTCHAs in test environments."""
def __init__(self, api_key):
self.api_key = api_key
def solve_recaptcha(self, sitekey, pageurl, timeout=120):
"""Solve reCAPTCHA and return token."""
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1,
}, timeout=30)
result = resp.json()
assert result.get("status") == 1, f"Submit failed: {result}"
task_id = result["request"]
deadline = time.time() + timeout
time.sleep(10)
while time.time() < deadline:
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key, "action": "get",
"id": task_id, "json": 1,
}, timeout=15)
data = resp.json()
if data.get("status") == 1:
return data["request"]
if data["request"] != "CAPCHA_NOT_READY":
raise RuntimeError(f"Solve error: {data['request']}")
time.sleep(5)
raise TimeoutError("CAPTCHA solve timeout")
@pytest.fixture(scope="session")
def captcha_helper():
"""Provide CaptchaAI helper for test session."""
import os
api_key = os.environ.get("CAPTCHAAI_API_KEY")
if not api_key:
pytest.skip("CAPTCHAAI_API_KEY not set")
return CaptchaTestHelper(api_key)
class TestLoginFlow:
"""Test login flow behind reCAPTCHA."""
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
LOGIN_URL = "https://staging.staging.example.com/qa-login"
def test_login_with_valid_credentials(self, captcha_helper):
"""Verify login succeeds with valid creds and solved CAPTCHA."""
token = captcha_helper.solve_recaptcha(self.SITEKEY, self.LOGIN_URL)
assert token and len(token) > 100
resp = requests.post(self.LOGIN_URL, data={
"username": "test_user",
"password": "test_pass",
"g-recaptcha-response": token,
})
assert resp.status_code == 200
assert "Welcome" in resp.text
def test_login_with_invalid_credentials(self, captcha_helper):
"""Verify login fails gracefully with bad creds but valid CAPTCHA."""
token = captcha_helper.solve_recaptcha(self.SITEKEY, self.LOGIN_URL)
resp = requests.post(self.LOGIN_URL, data={
"username": "wrong_user",
"password": "wrong_pass",
"g-recaptcha-response": token,
})
assert resp.status_code in (200, 401)
assert "Invalid" in resp.text or "error" in resp.text.lower()
def test_login_without_captcha_fails(self):
"""Verify login rejects submissions without CAPTCHA."""
resp = requests.post(self.LOGIN_URL, data={
"username": "test_user",
"password": "test_pass",
})
assert resp.status_code in (400, 403, 422)
Testes E2E no Selenium com CAPTCHA resolvido automaticamente
O mesmo helper serve para testes de ponta a ponta: o Selenium extrai a sitekey da página, pede o token e injeta o valor no campo. Se o widget expuser um callback JavaScript, o teste também dispara essa função manualmente antes de enviar o formulário.
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
@pytest.fixture
def browser():
"""Create browser for testing."""
options = webdriver.ChromeOptions()
options.add_argument("--window-size=1920,1080")
driver = webdriver.Chrome(options=options)
yield driver
driver.quit()
class TestRegistrationFlow:
"""Test registration form with CAPTCHA."""
REG_URL = "https://staging.example.com/register"
def test_registration_form_submits(self, browser, captcha_helper):
"""Full registration flow with CAPTCHA solving."""
browser.get(self.REG_URL)
# Fill form
browser.find_element(By.ID, "email").send_keys("test@example.com")
browser.find_element(By.ID, "password").send_keys("SecurePass123!")
browser.find_element(By.ID, "confirm_password").send_keys("SecurePass123!")
# Extract sitekey from page
captcha_div = browser.find_element(By.CSS_SELECTOR, ".g-recaptcha")
sitekey = captcha_div.get_attribute("data-sitekey")
# Solve via API
token = captcha_helper.solve_recaptcha(sitekey, browser.current_url)
# Inject token
browser.execute_script("""
document.querySelector('[name="g-recaptcha-response"]').value = arguments[0];
""", token)
# Trigger callback if needed
callback = captcha_div.get_attribute("data-callback")
if callback:
browser.execute_script(f"window['{callback}'](arguments[0]);", token)
# Submit
browser.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
# Verify success
WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".success-message"))
)
def test_captcha_renders_on_page(self, browser):
"""Verify CAPTCHA widget loads on registration page."""
browser.get(self.REG_URL)
captcha = WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".g-recaptcha, iframe[src*='recaptcha']"))
)
assert captcha.is_displayed()
Isolando os testes de CAPTCHA com markers do Pytest
Marque os testes com CAPTCHA real para rodá-los à parte — assim o pipeline rápido, que roda a cada push, não paga o custo nem o tempo de resolver CAPTCHA a cada commit:
# conftest.py
import os
# Mark tests that need CAPTCHA solving
def pytest_configure(config):
config.addinivalue_line(
"markers", "captcha: tests requiring CAPTCHA solving (may be slow)"
)
# pytest.ini or pyproject.toml
"""
[tool.pytest.ini_options]
markers = [
"captcha: tests requiring CAPTCHA solving (may be slow)",
]
"""
Rode só os testes que envolvem CAPTCHA:
pytest -m captcha -v
Rode o pipeline sem eles quando quiser feedback rápido:
pytest -m "not captcha" -v
Guias relacionados
Automatize seu pipeline de controle de qualidade — adicione a CaptchaAI aos seus testes.