इस पेज पर
OTP ऑटोमेशन को क्यों तोड़ता है
टेस्ट क्लिक कर सकता है, टाइप कर सकता है और assert कर सकता है, लेकिन फ़ोन नहीं पढ़ सकता। आम जुगाड़ों में हर एक कुछ न कुछ खो देता है:
- स्टेजिंग में 2FA बंद करना मतलब यूज़र्स जिस साइन-इन रास्ते से सच में जाते हैं, वह कभी टेस्ट ही नहीं होता।
- फ़िक्स्ड टेस्ट कोड सिर्फ़ उन्हीं सिस्टम में चलते हैं जो आपके कंट्रोल में हैं, और डिलीवरी की समस्याएँ छिपा देते हैं।
- फ़ोन लेकर बैठा कोई व्यक्ति रात भर चलने वाले रन के लिए स्केल नहीं करता, और रात 3 बजे कभी मौजूद नहीं होता।
तरीका: असली नंबर, API से पढ़ा गया
अपनी SIM किसी Android फ़ोन में लगाएँ (या Shortcuts ऑटोमेशन के साथ iPhone इस्तेमाल करें), BusySMS इंस्टॉल करें और नंबर सत्यापित करें। अपना टेस्ट खाता उसी नंबर पर रजिस्टर करें। टेस्ट में SMS ट्रिगर करें, BusySMS API से आने वाला अगला कोड माँगें, और उसे टाइप करें। कोड असली है, डिलीवरी का रास्ता असली है, और किसी को फ़ोन पर नज़र नहीं रखनी पड़ती।
- पुराने कोड नहीं। इंतज़ार करने वाला अनुरोध सिर्फ़ वही कोड लौटाता है जो उसके शुरू होने के बाद आया, इसलिए टेस्ट कभी पिछले रन का कोड सबमिट नहीं करता।
- एक अनुरोध।
GET /api/v1/codes?timeoutMs=60000लॉन्ग-पोल करता है, इसलिए कोई पोलिंग लूप नहीं लिखना पड़ता। - फ़िल्टर।
phone,serviceऔरdeviceIdपैरलल टेस्ट को एक-दूसरे के कोड लेने से रोकते हैं।
एक बार का सेटअप
- 1
फ़ोन नामांकित करें
टेस्ट SIM वाले फ़ोन पर Google Play से BusySMS इंस्टॉल करें, साइन इन करें और नंबर सत्यापित करें। पूरा विवरण Android SMS gateway गाइड में है।
- 2
टेस्ट खाता उसी नंबर पर रजिस्टर करें
जिस प्रोडक्ट को आप टेस्ट कर रहे हैं, उसमें यही नंबर डालें, ठीक वैसे ही जैसे कोई यूज़र डालता।
- 3
API कुंजी बनाएँ
डैशबोर्ड → REST API → कुंजी बनाएँ। उसे तुरंत कॉपी करें: वह सिर्फ़ एक बार दिखती है।
- 4
उसे CI सीक्रेट के रूप में रखें
टेस्ट रनर को यह
BUSYSMS_API_KEYके रूप में दें। इसे कभी कमिट न करें, और टेस्ट हो रहे ब्राउज़र को कभी न भेजें।
एक छोटा हेल्पर
नीचे के सभी उदाहरण एक ही विचार पर चलते हैं: इंतज़ार शुरू करें, SMS ट्रिगर करें, कोड लें। इंतज़ार को एक हेल्पर में रखें, TypeScript या Python में:
const API = "https://busysms.net/api/v1/codes";
export async function waitForSmsCode(
opts: { phone?: string; service?: string; timeoutMs?: number } = {},
): Promise<string> {
const params = new URLSearchParams({ timeoutMs: String(opts.timeoutMs ?? 60_000) });
if (opts.phone) params.set("phone", opts.phone);
if (opts.service) params.set("service", opts.service);
const res = await fetch(`${API}?${params}`, {
headers: { Authorization: `Bearer ${process.env.BUSYSMS_API_KEY}` },
});
if (!res.ok) throw new Error(`BusySMS ${res.status}: ${await res.text()}`);
const { code } = (await res.json()) as { code: string | null };
if (!code) throw new Error("No new SMS code arrived in time");
return code;
}import os
import requests
API = "https://busysms.net/api/v1/codes"
def wait_for_sms_code(phone=None, service=None, timeout_ms=60_000):
params = {"timeoutMs": timeout_ms}
if phone:
params["phone"] = phone
if service:
params["service"] = service
r = requests.get(
API,
params=params,
headers={"Authorization": f"Bearer {os.environ['BUSYSMS_API_KEY']}"},
timeout=timeout_ms / 1000 + 15,
)
r.raise_for_status()
code = r.json()["code"]
if not code:
raise TimeoutError("No new SMS code arrived in time")
return codeकोड भेजें पर क्लिक करने से पहले इंतज़ार शुरू करें। इससे वह रेस खत्म होती है जिसमें तेज़ SMS आपके इंतज़ार शुरू करने से पहले ही आ जाता है। अनुरोध से लगभग एक सेकंड पहले तक आया कोड अब भी नया माना जाता है, लेकिन उससे पुराना नहीं।
Playwright
import { test, expect } from "@playwright/test";
import { waitForSmsCode } from "./busysms";
test("signs in with SMS two-factor", async ({ page }) => {
test.setTimeout(120_000); // the default 30 s is shorter than an SMS wait
await page.goto("https://staging.example.com/login");
await page.getByLabel("Phone number").fill("+44 7700 900123");
// Start waiting BEFORE the SMS is sent, then trigger it.
const code = waitForSmsCode({ phone: "447700900123" });
await page.getByRole("button", { name: "Send code" }).click();
await page.getByLabel("Verification code").fill(await code);
await page.getByRole("button", { name: "Verify" }).click();
await expect(page).toHaveURL(/dashboard/);
});Selenium (Python)
Selenium की कॉल ब्लॉक करती हैं, इसलिए इंतज़ार को एक वर्कर थ्रेड पर चलाएँ, SMS ट्रिगर करें, फिर नतीजा लें:
from concurrent.futures import ThreadPoolExecutor
from selenium import webdriver
from selenium.webdriver.common.by import By
from busysms import wait_for_sms_code
driver = webdriver.Chrome()
driver.get("https://staging.example.com/login")
driver.find_element(By.NAME, "phone").send_keys("+44 7700 900123")
with ThreadPoolExecutor(max_workers=1) as pool:
# Start waiting first, then trigger the SMS.
pending = pool.submit(wait_for_sms_code, phone="447700900123")
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
code = pending.result()
driver.find_element(By.NAME, "otp").send_keys(code)
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()Cypress
Cypress कमांड ब्राउज़र में चलती हैं, इसलिए कुंजी को उससे दूर रखें: cypress.config.ts में एक Node task से API कॉल करें और नतीजा टेस्ट में इस्तेमाल करें।
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
setupNodeEvents(on) {
on("task", {
// Runs in Node, so the API key never reaches the browser.
async waitForSmsCode({ phone }: { phone: string }) {
const params = new URLSearchParams({ phone, timeoutMs: "60000" });
const res = await fetch(`https://busysms.net/api/v1/codes?${params}`, {
headers: { Authorization: `Bearer ${process.env.BUSYSMS_API_KEY}` },
});
if (!res.ok) throw new Error(`BusySMS ${res.status}`);
const { code } = await res.json();
return code; // null if nothing new arrived
},
});
},
},
});it("signs in with SMS two-factor", () => {
cy.visit("https://staging.example.com/login");
cy.get("input[name=phone]").type("+44 7700 900123");
cy.contains("button", "Send code").click();
cy.task("waitForSmsCode", { phone: "447700900123" }, { timeout: 90_000 }).then((code) => {
expect(code, "SMS code").to.be.a("string");
cy.get("input[name=otp]").type(String(code));
});
cy.contains("button", "Verify").click();
});Cypress कमांड क्रम से चलाता है, इसलिए यहाँ इंतज़ार क्लिक के ठीक बाद शुरू होता है। SMS डिलीवरी शायद ही इतनी तेज़ होती है, और अनुरोध से एक सेकंड पहले तक आया कोड भी गिना जाता है।
पैरलल रन और अटकती डिलीवरी
- हर पैरलल वर्कर के लिए एक नंबर सबसे आसान नियम है। अगर वर्कर को नंबर साझा करना ही पड़े, तो
serviceसे फ़िल्टर करें और एक ही सर्विस में साइन-इन एक-एक करके चलाएँ। - एक इंतज़ार की सीमा 90 सेकंड है। अगर SMS आने में ज़्यादा समय लग सकता है, तो टाइमआउट बढ़ाने के बजाय इंतज़ार एक बार दोबारा करें।
- जब टेस्ट को
nullमिले, तो प्रोडक्ट को दोष देने से पहले फ़ोन जाँचें:GET /api/v1/numberscanReceiveऔरreasonबताता है, जैसेgateway_offयाphone_unreachable। - अगर इंतज़ार शुरू होते समय कुछ भी कैप्चर नहीं हो रहा, तो BusySMS फ़ोन पर नोटिफ़िकेशन भेजकर गेटवे फिर से चालू करने को कहता है। उस पर किसी को टैप करना होगा।
- कैप्चर हुए मैसेज 7 दिन तक रखे जाते हैं, जो कल रात के फ़ेल हुए रन को डीबग करने के लिए काफ़ी है।
सामान्य स्क्रिप्ट और CI जॉब
यहाँ कुछ भी किसी टेस्ट फ़्रेमवर्क से बँधा नहीं है। CI जॉब का एक shell स्टेप curl और jq से यही कर सकता है: इंतज़ार बैकग्राउंड में शुरू करें, SMS ट्रिगर करें, फिर नतीजा पढ़ें।
# Start waiting in the background, then trigger the SMS
curl -s -H "Authorization: Bearer $BUSYSMS_API_KEY" \
"https://busysms.net/api/v1/codes?phone=447700900123&timeoutMs=60000" > code.json &
WAIT_PID=$!
./trigger-login.sh # whatever makes the service send the SMS
wait "$WAIT_PID"
CODE=$(jq -r .code code.json)
[ "$CODE" != "null" ] || { echo "No SMS code arrived" >&2; exit 1; }
echo "Got code $CODE"कोई कोड न आने पर jq null प्रिंट करता है, इसलिए जाँच फ़ॉर्म में null शब्द टाइप करने के बजाय जॉब को फ़ेल कर देती है।
इसे अपने ही खातों पर इस्तेमाल करें
यह इसलिए काम करता है क्योंकि कोड आपके अपने नंबर पर भेजा जाता है। इसे उन्हीं खातों के लिए इस्तेमाल करें जो आपके कंट्रोल में हैं: आपके प्रोडक्ट के टेस्ट यूज़र, आपके अपने एडमिन लॉगिन, आपका स्टेजिंग एनवायरनमेंट। टेस्ट रनर की जगह AI एजेंट से ब्राउज़र चला रहे हैं? उसके लिए MCP गाइड देखें।
BusySMS आपके अपने नंबरों पर भेजे गए कोड पढ़ता है। यह किसी और की सत्यापन प्रक्रिया से बचने का तरीका नहीं है, और थोक में खाते बनाने के लिए नहीं बना है।
सवाल-जवाब
अक्सर पूछे जाने वाले सवाल
Selenium में OTP सत्यापन कैसे ऑटोमेट करें?
एक वर्कर थ्रेड पर GET /api/v1/codes?timeoutMs=60000 शुरू करें, SMS ट्रिगर करें, फिर लौटा हुआ कोड फ़ील्ड में टाइप करें। ऊपर का Python उदाहरण ठीक यही करता है।
क्या असली फ़ोन के बिना OTP ऑटोमेट कर सकते हैं?
BusySMS के साथ नहीं। कोड असली फ़ोन में लगी आपकी SIM से आते हैं; एमुलेटर गेटवे के रूप में समर्थित नहीं हैं।
क्या कोई टेस्ट कभी पुराना कोड उठा लेगा?
नहीं। timeoutMs शून्य से ज़्यादा हो तो API सिर्फ़ वे कोड लौटाता है जो अनुरोध शुरू होने के बाद आए, और कोई न आए तो null लौटाता है।
CI में चलाने की लागत क्या है?
7 दिन के मुफ़्त ट्रायल के बाद $5 प्रति सत्यापित नंबर प्रति माह। कीमत प्रति नंबर है, प्रति टेस्ट रन या प्रति कोड नहीं।
क्या यह ईमेल कोड या ऑथेंटिकेटर ऐप के साथ काम करता है?
नहीं। BusySMS आपके अपने नंबरों पर SMS से भेजे गए कोड पढ़ता है। ईमेल कोड और ऑथेंटिकेटर-ऐप कोड SMS नहीं हैं, इसलिए वे इसके दायरे से बाहर हैं।
क्या मेरी पूरी टीम एक टेस्ट नंबर इस्तेमाल कर सकती है?
हाँ। नंबर को 5 और BusySMS यूज़र्स तक के साथ साझा करें; स्वीकार करने के बाद उनकी अपनी API कुंजियों को भी उसके नए कोड मिलते हैं।
ब्लॉग
ब्लॉग से और लेख
सभी लेखआगे पढ़ें
संबंधित गाइड
सभी गाइडSMS गेटवे API
रिसीव-साइड API रेफ़रेंस: ऑथेंटिकेशन, एंडपॉइंट, रिस्पॉन्स का ढाँचा, एरर, और curl, Node.js व Python कोड।
गाइड पढ़ेंAI एजेंट के लिए SMS कोड
Claude, Codex या किसी भी MCP क्लाइंट को BusySMS MCP सर्वर से SMS सत्यापन कोड का इंतज़ार करने दें।
गाइड पढ़ेंAndroid SMS गेटवे
अपने Android फ़ोन को गेटवे बनाएँ और उसके सत्यापन कोड API, MCP, डैशबोर्ड या Chrome से पढ़ें।
गाइड पढ़ेंअपने ही नंबर पर आज़माएँ
ऐप इंस्टॉल करें, अपना नंबर सत्यापित करें और आज ही अपना पहला कोड पढ़ें। हर खाता 7 दिन के मुफ़्त ट्रायल से शुरू होता है; उसके बाद $5 प्रति सत्यापित नंबर प्रति माह, और आप कभी भी रद्द कर सकते हैं।
BusySMS के बारे में और
