API SMS OTP: test đăng nhập OTP bằng Selenium và Python
Đội ngũ AxioAPI · Đăng ngày
Bước OTP thường là lý do bài test đăng nhập chập chờn: SMS đến trễ hoặc không đến đúng số. API SMS OTP loại bỏ phần đoán mò bằng cách cho test một số công khai và trả mã ngay khi tin nhắn đến, nên script Selenium không cần vòng lặp chờ riêng.
Trước khi bắt đầu
- Chỉ dùng trên staging. Số là công khai và dùng chung, ai cũng thấy tin nhắn.
- Một số dịch vụ chặn số công khai, nên không nhận được SMS không phải lúc nào cũng do ứng dụng của bạn lỗi.
- Lưu key vào AXIOAPI_KEY và cài selenium, requests.
Bài test
Bài test lấy một số US bằng GET /api/v1/sms/numbers, ghi lại thời điểm, nhập số vào form đăng nhập rồi gọi POST /api/v1/verify/wait với số đó và mốc thời gian. Tham số since giúp bỏ qua tin nhắn cũ.
import os
import time
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
API = "https://axioapi.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['AXIOAPI_KEY']}", "Accept": "application/json"}
def pick_number(country="US"):
res = requests.get(f"{API}/sms/numbers", headers=HEADERS, params={"country": country, "limit": 1}, timeout=60)
res.raise_for_status()
return res.json()["data"]["items"][0]["number"]
def wait_for_code(number, since):
res = requests.post(f"{API}/verify/wait", headers=HEADERS, timeout=120, json={"number": number, "since": since})
res.raise_for_status()
items = res.json()["data"].get("items") or []
return items[0]["code"] if items else None
def test_otp_login():
number = pick_number()
since = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
driver = webdriver.Chrome()
try:
driver.get("https://staging.example.com/login")
driver.find_element(By.NAME, "phone").send_keys(number)
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
code = wait_for_code(number, since)
assert code, "no OTP arrived before the timeout"
driver.find_element(By.NAME, "otp").send_keys(code)
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
assert "/dashboard" in driver.current_url
finally:
driver.quit()
Cách hoạt động
- Lệnh chờ trả về data.items, mỗi mục có người gửi, nội dung đầy đủ và mã đã tách.
- Mã 4 đến 8 chữ số được tách sẵn nên test không cần biểu thức chính quy.
- Nếu hết thời gian chờ mà chưa có tin nhắn, lệnh trả về không có mục nào. Hãy chọn số khác và thử lại cả luồng.
Giữ ổn định trong CI
- Luôn truyền since cho mỗi lần chạy để không dùng lại mã của lần trước.
- Thử số khác nếu dịch vụ đang test từ chối số đầu tiên.
- Không bao giờ dùng số công khai cho tài khoản bạn cần giữ.
Khi nào dùng API SMS thay thế
Nếu muốn xem mọi tin nhắn một số đã nhận, dùng GET /api/v1/sms/numbers/{number}/messages và tự đọc nội dung. API OTP là đường ngắn hơn khi bạn chỉ cần mã.