Jalankan pengujian menyeluruh terhadap halaman yang dilindungi CAPTCHA di saluran CI/CD Anda — tidak diperlukan intervensi manual.
Masalahnya
Pipeline CI/CD berjalan secara otomatis. CAPTCHA memerlukan interaksi manusia. Tanpa layanan penyelesaian, pengujian end-to-end Anda akan gagal setiap kali mencapai CAPTCHA.
Solusi: Gunakan API CaptchaAI di rangkaian pengujian Anda. Kunci API disimpan sebagai secret CI, dan pengujian memecahkan CAPTCHA secara otomatis selama eksekusi pipeline.
Arsitektur
┌──────────────┐ ┌──────────────┐ ┌────────────┐ ┌──────────────┐
│ Git Push │────▶│ CI Runner │────▶│ E2E Tests │────▶│ Test Report │
│ │ │ (headless │ │ + CAPTCHA │ │ │
│ │ │ Chrome) │ │ solving │ │ │
└──────────────┘ └──────────────┘ └────────────┘ └──────────────┘
│
▼
┌────────────┐
│ CaptchaAI │
│ API │
└────────────┘
Pembantu Tes
import os
import time
import requests
class CICaptchaSolver:
"""CAPTCHA solver designed for CI environments."""
BASE = "https://ocr.captchaai.com"
def __init__(self):
self.api_key = os.environ.get("CAPTCHAAI_API_KEY")
if not self.api_key:
raise EnvironmentError("CAPTCHAAI_API_KEY not set")
def solve(self, params, initial_wait=10, timeout=120):
params["key"] = self.api_key
params["json"] = 1
resp = requests.post(f"{self.BASE}/in.php", data=params).json()
if resp["status"] != 1:
raise Exception(f"CAPTCHA submit failed: {resp['request']}")
task_id = resp["request"]
time.sleep(initial_wait)
deadline = time.time() + timeout
while time.time() < deadline:
result = requests.get(
f"{self.BASE}/res.php",
params={"key": self.api_key, "action": "get", "id": task_id, "json": 1},
).json()
if result["request"] == "CAPCHA_NOT_READY":
time.sleep(5)
continue
if result["status"] == 1:
return result["request"]
raise Exception(f"CAPTCHA solve failed: {result['request']}")
raise TimeoutError("CAPTCHA solve timed out in CI")
def solve_recaptcha(self, sitekey, pageurl):
return self.solve({
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
})
def solve_turnstile(self, sitekey, pageurl):
return self.solve({
"method": "turnstile",
"sitekey": sitekey,
"pageurl": pageurl,
})
Integrasi paling sederhana
konflik.py
import pytest
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
@pytest.fixture(scope="session")
def captcha_solver():
return CICaptchaSolver()
@pytest.fixture(scope="function")
def browser():
options = Options()
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-gpu")
driver = webdriver.Chrome(options=options)
driver.set_window_size(1920, 1080)
yield driver
driver.quit()
Berkas Uji
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class TestLoginFlow:
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
LOGIN_URL = "https://staging.staging.example.com/qa-login"
def test_login_with_captcha(self, browser, captcha_solver):
browser.get(self.LOGIN_URL)
# Fill credentials
browser.find_element(By.ID, "username").send_keys("testuser")
browser.find_element(By.ID, "password").send_keys("testpass123")
# Solve CAPTCHA
token = captcha_solver.solve_recaptcha(self.SITEKEY, self.LOGIN_URL)
browser.execute_script(
f'document.querySelector("[name=g-recaptcha-response]").value = "{token}";'
)
# Submit
browser.find_element(By.ID, "login-btn").click()
time.sleep(3)
# Verify login success
assert "dashboard" in browser.current_url.lower()
def test_login_wrong_password(self, browser, captcha_solver):
browser.get(self.LOGIN_URL)
browser.find_element(By.ID, "username").send_keys("testuser")
browser.find_element(By.ID, "password").send_keys("wrongpass")
token = captcha_solver.solve_recaptcha(self.SITEKEY, self.LOGIN_URL)
browser.execute_script(
f'document.querySelector("[name=g-recaptcha-response]").value = "{token}";'
)
browser.find_element(By.ID, "login-btn").click()
time.sleep(3)
error = browser.find_element(By.CSS_SELECTOR, ".error-message")
assert error.is_displayed()
class TestContactForm:
SITEKEY = "0x4AAAA..."
FORM_URL = "https://staging.example.com/contact"
def test_contact_form_submission(self, browser, captcha_solver):
browser.get(self.FORM_URL)
browser.find_element(By.ID, "name").send_keys("CI Test")
browser.find_element(By.ID, "email").send_keys("ci@test.com")
browser.find_element(By.ID, "message").send_keys("Automated CI test")
token = captcha_solver.solve_turnstile(self.SITEKEY, self.FORM_URL)
browser.execute_script(
f'document.querySelector("[name=cf-turnstile-response]").value = "{token}";'
)
browser.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".success-message"))
)
Alur Kerja Tindakan GitHub
name: E2E Tests with CAPTCHA
on:
push:
branches: [main, staging]
pull_request:
branches: [main]
jobs:
e2e-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Chrome
uses: browser-actions/setup-chrome@v1
with:
chrome-version: stable
- name: Install ChromeDriver
uses: nanasess/setup-chromedriver@v2
- name: Install dependencies
run: |
pip install selenium requests pytest pytest-html
- name: Run E2E tests
env:
CAPTCHAAI_API_KEY: ${{ secrets.CAPTCHAAI_API_KEY }}
run: |
pytest tests/e2e/ -v --html=report.html --self-contained-html
- name: Upload test report
uses: actions/upload-artifact@v4
if: always()
with:
name: e2e-report
path: report.html
Konfigurasi GitLab CI
e2e_tests:
stage: test
image: python:3.11
services:
- selenium/standalone-chrome:latest
variables:
SELENIUM_REMOTE_URL: "http://selenium__standalone-chrome:4444/wd/hub"
script:
- pip install selenium requests pytest
- pytest tests/e2e/ -v
artifacts:
when: always
reports:
junit: report.xml
Pipa Jenkins
pipeline {
agent any
environment {
CAPTCHAAI_API_KEY = credentials('captchaai-api-key')
}
stages {
stage('Setup') {
steps {
sh 'pip install selenium requests pytest'
}
}
stage('E2E Tests') {
steps {
sh 'pytest tests/e2e/ -v --junitxml=results.xml'
}
}
}
post {
always {
junit 'results.xml'
}
}
}
Manajemen Biaya di CI
Hanya Selesaikan Saat Dibutuhkan
import os
def should_run_captcha_tests():
"""Skip CAPTCHA tests in certain environments."""
if os.environ.get("SKIP_CAPTCHA_TESTS"):
return False
if not os.environ.get("CAPTCHAAI_API_KEY"):
return False
return True
# In test
import pytest
@pytest.mark.skipif(
not should_run_captcha_tests(),
reason="CAPTCHA tests disabled or API key not set"
)
class TestWithCaptcha:
def test_login(self, browser, captcha_solver):
pass
Pemeriksaan Saldo Sebelum Test Suite
@pytest.fixture(scope="session", autouse=True)
def check_captcha_balance(captcha_solver):
import requests
resp = requests.get(
f"{captcha_solver.BASE}/res.php",
params={"key": captcha_solver.api_key, "action": "getbalance"},
)
balance = float(resp.text)
if balance < 0.50:
pytest.skip(f"CaptchaAI balance too low: ${balance:.2f}")
Pemecahan Masalah
| Masalah | Penyebab | Solusi |
|---|---|---|
CAPTCHAAI_API_KEY not set |
Secret tidak dikonfigurasi | Tambahkan kunci ke secret CI |
| Chrome crash di CI | Flag --no-sandbox tidak ada |
Tambahkan flag headless Chrome |
| Test lulus lokal, gagal di CI | Versi browser berbeda | Pin versi Chrome di CI |
| Timeout CAPTCHA | Jaringan CI lambat | Naikkan parameter timeout |
| Test terlalu mahal | Terlalu banyak penyelesaian CAPTCHA per run | Gunakan SKIP_CAPTCHA_TESTS untuk PR build |
Pertanyaan Umum
Haruskah setiap CI run menyelesaikan CAPTCHA?
Tidak. Jalankan pengujian CAPTCHA saat digabung ke main atau terjadwal (setiap malam). Lewati setiap PR untuk mengurangi biaya. Gunakan flag SKIP_CAPTCHA_TESTS.
Bagaimana cara menyimpan kunci API dengan aman di CI?
Gunakan manajemen secret platform CI Anda: GitHub Secrets, GitLab CI Variables, atau Jenkins Credentials. Jangan pernah hardcode kunci API.
Bisakah saya menjalankan pengujian CAPTCHA secara paralel?
Ya. Setiap pengujian mendapatkan penyelesaian CAPTCHA sendiri, dan CaptchaAI menangani request concurrent. Gunakan pytest-xdist untuk eksekusi pengujian paralel.
Panduan Terkait
- Pengujian Alur Pendaftaran
- Membangun Pipeline Pengujian Otomatis dengan CaptchaAI
Tambahkan penyelesaian CAPTCHA ke CI Anda — mulai dengan CaptchaAI.