Use Cases

Solução CAPTCHA para controle de qualidade e testes autorizados

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.

Os comentários estão desativados para este artigo.