Tạo quy trình thử nghiệm sẵn sàng cho CI để giải CAPTCHA trong các thử nghiệm toàn diện, nhờ đó bộ thử nghiệm tự động của bạn không bao giờ chặn các thử thách CAPTCHA.
Cấu trúc dự án
tests/
├── conftest.py # Shared fixtures
├── helpers/
│ ├── captcha.py # CaptchaAI integration
│ └── browser.py # Selenium helpers
├── test_login.py # Login flow tests
├── test_checkout.py # Checkout flow tests
└── pytest.ini # Config
Người trợ giúp kiểm tra CaptchaAI
# tests/helpers/captcha.py
import requests
import time
import os
class CaptchaTestHelper:
"""Solve CAPTCHAs during automated tests."""
def __init__(self):
self.api_key = os.environ.get("CAPTCHAAI_API_KEY")
if not self.api_key:
raise EnvironmentError("CAPTCHAAI_API_KEY required for CAPTCHA tests")
def solve_recaptcha(self, sitekey, pageurl):
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()
if result.get("status") != 1:
raise RuntimeError(f"Submit failed: {result.get('request')}")
task_id = result["request"]
time.sleep(15)
for _ in range(24):
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(data["request"])
time.sleep(5)
raise TimeoutError("CAPTCHA solve timeout in test")
def inject_token(self, driver, token):
"""Inject solved token into Selenium browser."""
driver.execute_script(
'document.getElementById("g-recaptcha-response").value = arguments[0];',
token,
)
# Trigger callback if available
driver.execute_script("""
if (typeof ___grecaptcha_cfg !== 'undefined') {
var clients = ___grecaptcha_cfg.clients;
for (var key in clients) {
var client = clients[key];
for (var prop in client) {
var val = client[prop];
if (val && typeof val === 'object') {
for (var inner in val) {
if (typeof val[inner] === 'function') {
val[inner](arguments[0]);
return;
}
}
}
}
}
}
""", token)
Lịch thi đấu Pytest
# tests/conftest.py
import pytest
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from helpers.captcha import CaptchaTestHelper
@pytest.fixture(scope="session")
def captcha_solver():
return CaptchaTestHelper()
@pytest.fixture(scope="function")
def browser():
options = Options()
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(options=options)
driver.implicitly_wait(10)
yield driver
driver.quit()
@pytest.fixture(scope="session")
def base_url():
return "https://staging.example.com"
Kiểm tra đăng nhập bằng CAPTCHA
# tests/test_login.py
import pytest
from selenium.webdriver.common.by import By
class TestLogin:
def test_valid_login_with_captcha(self, browser, captcha_solver, base_url):
"""Test that login succeeds when CAPTCHA is solved correctly."""
browser.get(f"{base_url}/login")
# Fill form
browser.find_element(By.ID, "email").send_keys("test@example.com")
browser.find_element(By.ID, "password").send_keys("testpassword123")
# Solve CAPTCHA
sitekey = browser.find_element(
By.CLASS_NAME, "g-recaptcha"
).get_attribute("data-sitekey")
token = captcha_solver.solve_recaptcha(sitekey, browser.current_url)
captcha_solver.inject_token(browser, token)
# Submit
browser.find_element(By.ID, "login-btn").click()
# Assert redirect to dashboard
assert "/dashboard" in browser.current_url
assert browser.find_element(By.CLASS_NAME, "welcome-message")
def test_invalid_credentials_with_captcha(self, browser, captcha_solver, base_url):
"""Test that wrong credentials show error even with valid CAPTCHA."""
browser.get(f"{base_url}/login")
browser.find_element(By.ID, "email").send_keys("wrong@example.com")
browser.find_element(By.ID, "password").send_keys("wrongpass")
sitekey = browser.find_element(
By.CLASS_NAME, "g-recaptcha"
).get_attribute("data-sitekey")
token = captcha_solver.solve_recaptcha(sitekey, browser.current_url)
captcha_solver.inject_token(browser, token)
browser.find_element(By.ID, "login-btn").click()
error = browser.find_element(By.CLASS_NAME, "error-message")
assert "Invalid" in error.text
Kiểm tra thanh toán
# tests/test_checkout.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class TestCheckout:
def test_checkout_flow_with_captcha(self, browser, captcha_solver, base_url):
"""Full checkout flow: add item, fill form, solve CAPTCHA, confirm."""
# Add item to cart
browser.get(f"{base_url}/products/test-item")
browser.find_element(By.ID, "add-to-cart").click()
# Go to checkout
browser.get(f"{base_url}/checkout")
# Fill shipping
browser.find_element(By.ID, "address").send_keys("123 Test St")
browser.find_element(By.ID, "city").send_keys("Test City")
browser.find_element(By.ID, "zip").send_keys("12345")
# Solve CAPTCHA on checkout page
captcha_el = browser.find_element(By.CLASS_NAME, "g-recaptcha")
sitekey = captcha_el.get_attribute("data-sitekey")
token = captcha_solver.solve_recaptcha(sitekey, browser.current_url)
captcha_solver.inject_token(browser, token)
# Submit order
browser.find_element(By.ID, "place-order").click()
# Wait for confirmation
wait = WebDriverWait(browser, 15)
confirmation = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "order-confirmation"))
)
assert "Thank you" in confirmation.text
Cấu hình Pytest
# tests/pytest.ini
[pytest]
markers =
captcha: tests requiring CAPTCHA solving (cost per run)
addopts = -v --tb=short
Quy trình làm việc hành động của GitHub
# .github/workflows/e2e-tests.yml
name: E2E Tests
on:
push:
branches: [main]
schedule:
- cron: "0 6 * * 1" # Weekly Monday 6 AM
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install pytest selenium requests
- name: Install Chrome
uses: browser-actions/setup-chrome@latest
- name: Run E2E tests
env:
CAPTCHAAI_API_KEY: ${{ secrets.CAPTCHAAI_API_KEY }}
run: pytest tests/ -m captcha -v
Khắc phục sự cố
| Vấn đề | Nguyên nhân | Cách xử lý |
|---|---|---|
| Việc tiêm mã thông báo không thành công | Không tìm thấy vùng văn bản | Kiểm tra ID phần tử hoặc sử dụng querySelector('[name="g-recaptcha-response"]') |
| Các bài kiểm tra đạt cục bộ, thất bại trong CI | Phiên bản Chrome khác | Ghim phiên bản Chrome trong thiết lập CI |
| CAPTCHA không xuất hiện trong dàn dựng | Phân tầng vô hiệu hóa CAPTCHA | Bật CAPTCHA trong cấu hình env dàn dựng |
| Hết thời gian chờ giải quyết | Mạng chậm trong CI | Tăng thời gian chờ thăm dò lên 180 giây |
Câu hỏi thường gặp
Chi phí chạy thử nghiệm CAPTCHA là bao nhiêu?
Mỗi giải quyết là một vài xu. Việc chạy bộ 10 bài kiểm tra hàng ngày có chi phí dưới $10/month.. Chỉ sử dụng điểm đánh dấu pytest để chạy kiểm tra CAPTCHA khi cần.
Tôi có thể mô phỏng CAPTCHA trong bài kiểm tra đơn vị không?
Vâng. Mô phỏng phương pháp CaptchaTestHelper.solve_recaptcha trong các bài kiểm tra đơn vị và chỉ sử dụng các giải pháp thực tế cho các bài kiểm tra tích hợp E2E.
Làm cách nào để bỏ qua các bài kiểm tra CAPTCHA cục bộ?
Sử dụng pytest -m "not captcha" để bỏ qua các bài kiểm tra được đánh dấu bằng trang trí @pytest.mark.captcha.
Hướng dẫn liên quan
- Giải CAPTCHA để kiểm tra QA
- CAPTCHA trong thử nghiệm CI/CD
Đừng bao giờ để CAPTCHA chặn bài kiểm tra của bạn —bắt đầu với CaptchaAI.