Form login atau registrasi yang dilindungi reCAPTCHA sering membuat test suite end-to-end berhenti total — bukan karena aplikasinya rusak, tapi karena skrip pengujian tidak bisa mengklik CAPTCHA seperti manusia. CaptchaAI menutup celah itu: task pengujian mengirim sitekey ke API, menerima token dalam hitungan detik, lalu alur pengujian lanjut seperti biasa tanpa ada interaksi CAPTCHA manual di tengah pipeline. Yang penting digarisbawahi di awal: ini bukan soal menembus proteksi CAPTCHA milik orang lain, melainkan environment staging atau QA yang memang Anda kelola dan berhak uji sendiri.
Alur kerjanya konsisten di semua bahasa dan framework pengujian:
- Kirim sitekey dan URL halaman ke
in.php - Simpan
task_idyang dikembalikan - Polling
res.phpsampai status solve selesai - Pakai token hasil solve untuk melanjutkan submit form
Catatan kepatuhan: jalankan pola ini hanya di environment staging atau akun uji milik tim sendiri, dengan data dummy — bukan data pribadi pengguna nyata. Ini sejalan dengan semangat UU Pelindungan Data Pribadi (UU 27/2022).
Kapan Pipeline QA Butuh Solve CAPTCHA Otomatis
CAPTCHA biasanya baru "terasa" ketika sebuah suite pengujian tiba-tiba merah tanpa sebab yang jelas di kode aplikasi itu sendiri.
| Skenario | Alasan CaptchaAI Membantu |
|---|---|
| Pengujian regresi | Memastikan form tetap berfungsi setelah setiap deployment |
| Pengujian end-to-end | Menguji user journey secara utuh, dari isi form sampai halaman sukses |
| Load testing | Mensimulasikan flow CAPTCHA yang realistis dalam volume besar |
| Pengujian lintas browser | Memvalidasi rendering CAPTCHA di berbagai browser sekaligus |
| Pengujian aksesibilitas | Menguji alur alternatif untuk pengguna penyandang disabilitas |
| Pengujian kondisi jaringan lambat | Mensimulasikan retry dan timeout CAPTCHA pada koneksi mobile 3G/4G |
Baris terakhir relevan untuk tim yang men-deploy ke region Asia Tenggara — misalnya runner CI di AWS ap-southeast-1 (Singapura) atau GCP asia-southeast2 (Jakarta) — karena latensi jaringan mobile membuat parameter timeout dan retry jauh lebih penting dibanding lingkungan desktop-only.
Sebelum masuk ke kode, pertanyaan yang biasanya muncul duluan dari tim QA adalah soal biaya, jadi mari bahas itu dulu.
Berapa Biaya Solve CAPTCHA untuk Tim QA
CaptchaAI tidak mengenakan biaya per solve — Anda membayar per thread yang aktif, dan setiap thread mencakup solve tanpa batas selama periode billing. Ini penting dipahami tim QA karena artinya biaya pengujian CAPTCHA tidak naik linear mengikuti jumlah test case; yang menentukan adalah berapa banyak solve yang perlu berjalan bersamaan.
Sebagai contoh, tim QA kecil yang menjalankan sekitar 50 tes berbasis reCAPTCHA v2 per hari kerja biasanya cukup memakai paket BASIC ($15/bulan, 5 thread). reCAPTCHA v2 umumnya selesai di bawah 60 detik, jadi lima thread paralel sanggup menuntaskan seluruh batch tanpa antrean panjang — dan karena solve per thread tidak dibatasi jumlahnya, tidak ada biaya tambahan tiap kali sebuah test dijalankan ulang. Tim dengan matriks CI yang lebih besar (banyak browser dan environment paralel) baru perlu naik ke STANDARD ($30/bulan, 15 thread) atau ADVANCE ($90/bulan, 50 thread) — bukan karena volume solve-nya, tapi karena jumlah thread yang berjalan bersamaan bertambah.
Beberapa kebiasaan berikut membantu menjaga biaya thread tetap efisien:
- Jalankan di environment staging — tantangan CAPTCHA di sana biasanya lebih ringan dibanding production.
- Jadwalkan tes CAPTCHA berkala, bukan di setiap push, supaya thread tidak terpakai untuk commit kecil yang tidak menyentuh form.
- Cache hasil untuk test yang tidak stabil (flaky) agar tidak solve ulang tanpa perlu.
- Pakai environment flag untuk skip CAPTCHA saat development lokal, supaya developer tidak menunggu solve saat masih iterasi cepat.
- Kelompokkan tes CAPTCHA dalam CI job khusus supaya kontrol thread lebih mudah dipantau per pipeline.
Dengan model biaya itu di kepala, berikut implementasinya — dimulai dari helper pytest yang dipakai ulang di semua test class.
Integrasi dengan Pytest: Helper CAPTCHA yang Reusable
Pola paling praktis adalah membungkus logika kirim-dan-polling CaptchaAI dalam satu helper class, lalu memakainya lewat fixture pytest supaya setiap test class tinggal memanggilnya tanpa menulis ulang boilerplate HTTP. Helper di bawah ini mengirim sitekey ke in.php, menyimpan task_id, lalu polling res.php sampai token siap atau timeout tercapai.
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)
Perhatikan bahwa CAPTCHAAI_API_KEY diambil dari environment variable, bukan ditulis langsung di kode. Sitekey di atas ditempatkan sebagai konstanta di kelas test hanya untuk kejelasan; pada pola Selenium berikutnya, sitekey justru diambil langsung dari halaman.
Uji End-to-End dengan Selenium
Untuk pengujian yang benar-benar menjalankan browser (bukan cuma memanggil API backend), sitekey biasanya diambil langsung dari atribut data-sitekey di halaman — bukan di-hardcode — supaya test tetap valid walau widget CAPTCHA berubah posisi atau konfigurasinya diperbarui tim frontend. Kalau widget memakai callback JavaScript untuk mengaktifkan tombol submit, token hasil solve harus dilewatkan lewat callback yang sama, bukan cuma diisi ke field tersembunyi.
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()
Menyiapkan CAPTCHA di Pipeline CI/CD
Karena solve CAPTCHA butuh waktu dan biaya thread, praktik yang wajar adalah memisahkan test yang menyertakan CAPTCHA dari test suite utama lewat marker pytest, sehingga tim bisa memilih kapan menjalankannya penuh dan kapan cukup skip dulu untuk pipeline yang lebih cepat.
# 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)",
]
"""
Jalankan hanya tes CAPTCHA:
pytest -m captcha -v
Jalankan tanpa tes CAPTCHA (pipeline cepat):
pytest -m "not captcha" -v
Karena CaptchaAI berbasis HTTP murni, pola marker ini juga bisa diadaptasi ke framework testing lain di luar Python — Jest, Mocha, JUnit, atau NUnit tinggal memanggil endpoint in.php/res.php yang sama. Untuk konfigurasi lengkap job CI yang menjalankan test bertag CAPTCHA secara terjadwal, baca panduan GitHub Actions untuk CI/CD testing CAPTCHA.
Pertanyaan Umum
Apakah solve CAPTCHA otomatis untuk QA aman dari sisi kepatuhan data?
Selama pengujian dijalankan di environment staging atau akun uji milik tim sendiri, ini adalah praktik QA yang wajar. Yang perlu dihindari adalah menyentuh data pribadi pengguna nyata di production.
Berapa biaya menjalankan tes CAPTCHA dengan CaptchaAI?
Tidak ada biaya per solve — yang dibayar adalah thread aktif per bulan, dan setiap thread mencakup solve tanpa batas. Untuk kebutuhan QA skala kecil sampai menengah, paket BASIC ($15/bulan, 5 thread) atau STANDARD ($30/bulan, 15 thread) biasanya sudah mencukupi.
Haruskah CAPTCHA di-solve di unit test?
Tidak. Mock respons CAPTCHA di unit test agar tetap cepat dan deterministik. Solve CAPTCHA nyata sebaiknya hanya dijalankan di pengujian integrasi dan end-to-end yang benar-benar menyentuh environment staging.
Berapa sering sebaiknya test suite yang menyertakan CAPTCHA dijalankan?
Untuk kebanyakan tim, cukup dijadwalkan (misalnya beberapa kali sehari atau sebelum rilis) daripada dijalankan di setiap push. Reservasi thread untuk test CAPTCHA di job CI terpisah supaya pipeline utama tetap cepat.
Apa yang terjadi jika solve CAPTCHA gagal di tengah pipeline CI/CD?
Helper di atas melempar RuntimeError atau TimeoutError sehingga test langsung gagal dengan pesan yang jelas, bukan macet menunggu tanpa batas. Praktik yang baik adalah menandai test tersebut retry sekali sebelum benar-benar dianggap gagal, supaya gangguan jaringan sesaat tidak memblokir seluruh pipeline.
Bacaan lanjutan: panduan etika solve CAPTCHA untuk automasi membahas batasan penggunaan yang wajar di luar konteks QA.
Otomatiskan pipeline QA Anda — hubungkan CaptchaAI ke test suite Anda.