Selenium ve Playwright ile E-posta Doğrulama Kodu Testi
Selenium ya da Playwright ile e-posta doğrulama adımını test etmek için testin, uygulamanızın gönderdiği kodu okuyabileceği gerçek bir gelen kutusuna ihtiyacı vardır. OTPGmail API'siyle test önce bir @gmail.com adresi kiralar, adresi forma yazar, kodu API'den bekler ve kod gelmezse siparişi iptal ederek tutarı geri alır.
Bu rehber, kendi uygulamasının ya da sahibi olduğu test ortamının kayıt akışını otomatikleştiren QA mühendisleri ve geliştiriciler içindir. Ham API çağrılarının ayrıntısı Python ile e-posta onay kodu alma rehberinde; burada çerçevelere özgü kısımlara odaklanıyoruz.
Ne zaman gerçek bir gelen kutusu gerekir?
Birim testlerde ve yerel geliştirmede e-postayı kendi sunucunuzda yakalayan bir araç daha hızlıdır ve her çalıştırmada ücret gerektirmez. Gerçek bir gelen kutusu şu durumlarda anlam kazanır:
- Test ortamınız e-postayı gerçek gönderim altyapınızdan, gerçek bir Gmail ya da iCloud adresine göndermek zorundaysa.
- Kodların Gmail'e gerçekten ulaşıp ulaşmadığını sürüm öncesinde kontrol etmek istiyorsanız.
- Kayıt formunuz geçici posta servislerinin alan adlarını reddediyorsa ve testin sıradan bir kullanıcı gibi davranması gerekiyorsa.
Kendi uygulamanız OTPGmail'in hizmet listesinde olmadığı için kod olarak ot (“Herhangi bir site”, uygulamada “Any service”) kullanılır; fiyatı listedeki hizmetlerden yüksektir. Bu seçeneğin Gmail versiyonu adres başına bir kod alır; aynı testte kayıt ve giriş için iki kod gerekiyorsa her biri için ayrı sipariş planlayın. Gmail ve iCloud seçeneklerinin farkları Herhangi bir site sayfasında.
Akış ve kullanacağınız alanlar
POST /v1/ordersgövdesi{"service": "ot"}; her yeni sipariş için yeni birIdempotency-Key(UUID). Yanıt bir dizidir:data[0].orderIdvedata[0].email.emaildeğerini kayıt formuna yazın ve uygulamanızın kodu göndermesini tetikleyin.GET /v1/orders/{orderId}çağrısını 3–5 saniyede bir yapın.statusdeğeriwaiting_codeiken bekleyin;completedolduğunda en yeni kodotp[otp.length - 1].codealanındadır.statusdeğericancelledise kodcodeDeadlineAtzamanına kadar gelmemiş, sipariş kendiliğinden iade edilmiştir (en fazla 25 dakika).- Test kod gelmeden biterse
POST /v1/orders/{orderId}/cancelçağırın: ilk koddan önce iptal %100 iade edilir.
otp[].code genellikle kısa bir kod ya da bir bağlantıdır. Sistem kodu ayıklayamazsa e-postanın tamamı (HTML ya da metin) aynı alana gelir; değer 80 karakterden uzunsa, satır sonu ya da HTML içeriyorsa kodu kendi biçiminize göre içinden çıkarın.
Playwright (TypeScript): expect.poll ile kod beklemek
Playwright'ın request fikstürü API çağrılarını tarayıcı dışında yapar; anahtar test sürecinde kalır. Örnek, ortam değişkeninde OTPGMAIL_API_KEY ve yapılandırmada baseURL olduğunu varsayar.
// tests/kayit.spec.ts
import { test, expect, type APIRequestContext } from '@playwright/test';
import { randomUUID } from 'node:crypto';
const HOST = 'otpgmail.net';
const API = `https://${HOST}/v1`;
const auth = { Authorization: `Bearer ${process.env.OTPGMAIL_API_KEY}` };
async function rentInbox(request: APIRequestContext) {
const res = await request.post(`${API}/orders`, {
headers: { ...auth, 'Idempotency-Key': randomUUID() },
data: { service: 'ot' },
timeout: 15_000,
});
const body = await res.json();
if (!body.success) throw new Error(body.error.code); // NO_MAILS_AVAILABLE, INSUFFICIENT_BALANCE...
return body.data[0] as { orderId: string; email: string };
}
function extractCode(raw: string): string {
if (raw.length <= 80 && !raw.includes('\n') && !raw.includes('<')) return raw;
return raw.match(/\b\d{6}\b/)?.[0] ?? raw; // tam e-posta geldiyse: kendi kod biçiminiz
}
test('e-posta doğrulama kodlu kayıt', async ({ page, request }) => {
test.setTimeout(6 * 60_000);
const inbox = await rentInbox(request);
let order: { status: string; otp: { code: string }[] } | undefined;
try {
await page.goto('/kayit');
await page.getByLabel('E-posta').fill(inbox.email);
await page.getByRole('button', { name: 'Kod gönder' }).click();
await expect.poll(async () => {
const r = await request.get(`${API}/orders/${inbox.orderId}`, { headers: auth });
order = (await r.json()).data;
return order?.status;
}, { message: 'doğrulama kodu bekleniyor', intervals: [4_000], timeout: 5 * 60_000 })
.not.toBe('waiting_code');
expect(order?.status).toBe('completed');
const code = extractCode(order!.otp[order!.otp.length - 1].code);
await page.getByLabel('Doğrulama kodu').fill(code);
await page.getByRole('button', { name: 'Doğrula' }).click();
await expect(page.getByText('Hesabınız doğrulandı')).toBeVisible();
} finally {
if (order?.status !== 'completed') {
await request.post(`${API}/orders/${inbox.orderId}/cancel`, { headers: auth }); // iade
}
}
});
Playwright'ın varsayılan test süresi yavaş bir e-postadan kısadır; bu yüzden test süreyi kendisi uzatır. Etiketler ve metinler (“Kod gönder”, “Hesabınız doğrulandı”) sizin uygulamanıza aittir; kendi seçicilerinizle değiştirin.
Selenium e-posta doğrulama testi (Python): WebDriverWait ile API
WebDriverWait.until yalnızca sayfa öğelerini değil, sürücüyü alan herhangi bir fonksiyonu bekleyebilir. poll_frequency=4 ile API her dört saniyede bir sorgulanır; temizliği pytest fikstürü yapar.
# test_kayit.py
import os, uuid, requests, pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
HOST = "otpgmail.net"
API = f"https://{HOST}/v1"
AUTH = {"Authorization": f"Bearer {os.environ['OTPGMAIL_API_KEY']}"}
@pytest.fixture
def driver():
d = webdriver.Chrome()
yield d
d.quit()
@pytest.fixture
def inbox():
r = requests.post(f"{API}/orders", json={"service": "ot"},
headers={**AUTH, "Idempotency-Key": str(uuid.uuid4())}, timeout=15)
body = r.json()
if not body["success"]:
pytest.skip(body["error"]["code"]) # ör. NO_MAILS_AVAILABLE: ücret kesilmez
order = body["data"][0]
yield order
# temizlik: ilk koddan önce iptal %100 iade; kod geldiyse API iptali reddeder
requests.post(f"{API}/orders/{order['orderId']}/cancel", headers=AUTH, timeout=15)
def latest_code(order_id):
o = requests.get(f"{API}/orders/{order_id}", headers=AUTH, timeout=15).json()["data"]
if o["status"] == "cancelled":
raise AssertionError("kod gelmedi, sipariş iade edildi")
return o["otp"][-1]["code"] if o["otp"] else False
def test_kayit(driver, inbox):
driver.get("https://staging.ornek.com.tr/kayit")
driver.find_element(By.NAME, "email").send_keys(inbox["email"])
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
code = WebDriverWait(driver, timeout=300, poll_frequency=4).until(
lambda d: latest_code(inbox["orderId"]))
driver.find_element(By.NAME, "code").send_keys(code)
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
latest_code kod yokken False döndürür; WebDriverWait bu sırada beklemeye devam eder, sipariş iptal olduysa hata testi hemen durdurur. Python'da requests kullanın: standart urllib kütüphanesinin varsayılan kullanıcı aracısı API'nin önündeki CDN tarafından reddedilebilir.
Türkçe yerel ayarda gizli hata: büyük “I”
Türkçe yerel ayarda büyük “I” harfinin küçüğü “ı”dır. E-posta adresini küçük harfe çevirirken yerel ayara bağlı bir fonksiyon kullanan bir sunucu, “INFO@…” adresini “ınfo@…” yapar ve kod hiç gönderilmez ya da yanlış yere gider. Java'da varsayılan yerel ayarla çalışan toLowerCase(), C#'ta ToLower() ve JavaScript'te toLocaleLowerCase('tr-TR') bu davranışa açıktır; toLowerCase(Locale.ROOT), ToLowerInvariant() ve JavaScript'in düz toLowerCase() fonksiyonu ise yerel ayardan bağımsızdır.
Bu hatayı yalnızca gerçek teslimat yakalar. Gmail adreslerinde büyük-küçük harf fark etmediği için kiraladığınız adresi forma inbox.email.toUpperCase() olarak yazan ikinci bir test ekleyin; Playwright yapılandırmasında locale: 'tr-TR' kullanın ve sunucuyu Türkçe yerel ayarla çalıştırın. Kod geliyorsa normalleştirme doğrudur.
CI'da sınırlar, paralel testler ve temizlik
- Her test kendi siparişi. Paralel çalışan testler asla aynı adresi paylaşmamalı; sipariş numarasını test günlüğüne yazın.
- Hız sınırı. API anahtarı başına varsayılan sınırlar ve hesabınıza özel değerler API belgelerinde görünür. Sınır aşılırsa HTTP 429 ve
RATE_LIMITEDdöner;Retry-Afterbaşlığındaki saniye kadar bekleyin. Sorgulamayı 3–5 saniyeden sık yapmak yalnızca aynı veriyi getirir. - Kirala-iptal döngüsü kurmayın. Hesap son 60 dakikada kodsuz çok sayıda sipariş iptal ettiyse yeni kiralama da geçici olarak
RATE_LIMITEDalır. - Bekleyen sipariş sayısı. Aynı anda kod bekleyen sipariş sayısı hesap başına sınırlıdır (
WAITING_LIMIT_REACHED); testi biten ama hâlâ kod bekleyen siparişleri iptal edin. - Yeniden deneme. Sipariş çağrısı yoğun anlarda birkaç saniye sürebilir; istemci zaman aşımını yaklaşık 15 saniye tutun ve zaman aşımından sonra aynı isteği aynı
Idempotency-Keyile gönderin. - Ücret. Kod gelmeyen sipariş bekleme süresi sonunda kendiliğinden %100 iade edilir; ilk kod geldikten sonra iptal ve iade yoktur. Kurallar iade ve garanti politikasında.
Sınırlar
Kiralık gelen kutusu yalnızca e-posta almak içindir: e-posta gönderemezsiniz, gelen kutusuna giriş yapamazsınız ve adres kalıcı değildir. Bu test düzenini kendi uygulamanızın ya da test etme izniniz olan bir ortamın kayıt akışı için kullanın; başkalarının platformlarında betikle hesap açmak için değil. Akışın genel resmi OTPGmail nasıl çalışır sayfasında.
Sıkça sorulan sorular
Kod gelmezse ücret öder miyim?
Hayır. Kod codeDeadlineAt zamanına kadar gelmezse sipariş kendiliğinden iptal olur ve tutarın %100'ü bakiyenize döner; testiniz daha erken bitiyorsa iptal çağrısıyla aynı iadeyi hemen alırsınız.
Kiralık adresin gelen kutusunu IMAP ile okuyabilir miyim?
Hayır. Kiralamada şifre ve IMAP erişimi yoktur; kod yalnızca API'de ve sipariş sayfasında görünür. Testiniz IMAP'e bağlıysa okuma adımını API çağrısıyla değiştirin.
iCloud adresi mi, Gmail mi kullanmalıyım?
Kayıt formunuzu sıradan kullanıcılar gibi test etmek için ikisi de gerçek adreslerdir. Fiyat ve kod kuralı seçeneğe göre değişir; ikisini ayrı testlerde denemek, kodlarınızın iki posta sağlayıcısına da ulaştığını gösterir.
Bir test ortamı için anahtarı nereden alırım?
Giriş yaptıktan sonra API belgeleri sayfasındaki “API anahtarınız” kutusundan ya da “Hesabım” sayfasından. Anahtarı CI gizli değişkeninde tutun; yeni anahtar oluşturduğunuzda eskisi hemen çalışmaz hale gelir.
