Selenium'da iframelerle Çalışmak
Neden iframe?
Section titled “Neden iframe?”Bir sayfada başka bir HTML belgesini gömmek için kullanılan <iframe>, içerdiği DOM’u ana sayfadan yalıtır. Bu yüzden:
driver.findElement(...)çağrıları, varsayılan olarak ana sayfanın DOM’unda arama yapar.iframeiçindeki elementlere erişmek için önce çerçeveye geçiş yapılmalıdır.
Temel API
Section titled “Temel API”driver.switchTo().frame(int index)driver.switchTo().frame(String nameOrId)driver.switchTo().frame(WebElement iframeElement)driver.switchTo().defaultContent()– En dıştaki (ana) sayfaya dön.driver.switchTo().parentFrame()– Bir üst çerçeveye dön.
İpucu: Çerçeveye geçmeden önce
iframegörünür olmayabilir; explicit wait ile beklemek testleri kararlı hale getirir.
Örnek: İndeks ile iframe’e Geçiş
Section titled “Örnek: İndeks ile iframe’e Geçiş”WebDriver driver = new ChromeDriver();driver.get("https://example.com/page-with-iframes");
// 0. iframe'e geçdriver.switchTo().frame(0);
// Artık bulucular bu iframe'in DOM'unda çalışırWebElement editor = driver.findElement(By.id("richTextEditor"));editor.sendKeys("Merhaba iframe!");
// Ana sayfaya geri döndriver.switchTo().defaultContent();Örnek: name / id ile Geçiş
Section titled “Örnek: name / id ile Geçiş”driver.switchTo().frame("payment-frame"); // <iframe id="payment-frame" ...>driver.findElement(By.name("cardNumber")).sendKeys("4111 1111 1111 1111");driver.switchTo().defaultContent();Örnek: WebElement ile Geçiş (Tercih Edilen)
Section titled “Örnek: WebElement ile Geçiş (Tercih Edilen)”id/name dinamikse en güvenlisi WebElement referansıdır.
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));WebElement iframe = wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("iframe[src*='editor']")));
driver.switchTo().frame(iframe);driver.findElement(By.cssSelector("[role='textbox']")).sendKeys("Iframe içinden selam!");driver.switchTo().defaultContent();İç İçe (Nested) iframe’ler
Section titled “İç İçe (Nested) iframe’ler”// dış iframedriver.switchTo().frame("outer-frame");
// iç iframedriver.switchTo().frame("inner-frame");
driver.findElement(By.id("inside")).click();
// bir üst iframedriver.switchTo().parentFrame();
// ana sayfadriver.switchTo().defaultContent();iframe Bulma ve Bekletme Stratejileri
Section titled “iframe Bulma ve Bekletme Stratejileri”- Explicit Wait kullanın:
presenceOfElementLocated→ DOM’a eklendi mi?
frameToBeAvailableAndSwitchToIt→ Hem eklensin hem otomatik switch yapsın.
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.cssSelector("iframe[data-test='checkout']")));- Görünürlük/aktivasyon kontrolü:
Bazı iframeler lazy-load olur. GerekirsescrollIntoView()veyaActionsile görünür yapın.
WebElement iframe = driver.findElement(By.cssSelector("iframe.lazy"));((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", iframe);driver.switchTo().frame(iframe);- Dinamik kaynak (
src) eşleme:
iframe[src*='segment']gibi kısmi eşleme dayanıklıdır.
StaleElementReferenceException ve İpuçları
Section titled “StaleElementReferenceException ve İpuçları”iframeyeniden yüklendiğinde öncekiWebElementreferansları bayatlar.- Çözüm:
switchTo().defaultContent()→ iframe’i yeniden bulun → tekrarswitchTo().frame(...).
try { driver.findElement(By.id("submit")).click();} catch (StaleElementReferenceException e) { driver.switchTo().defaultContent(); WebElement freshFrame = driver.findElement(By.cssSelector("iframe[src*='form']")); driver.switchTo().frame(freshFrame); driver.findElement(By.id("submit")).click();}Sayı veya Kimlik Değişiyorsa: Dayanıklı Yardımcı
Section titled “Sayı veya Kimlik Değişiyorsa: Dayanıklı Yardımcı”public class FrameUtils { private WebDriver driver; private WebDriverWait wait;
public FrameUtils(WebDriver driver, Duration timeout) { this.driver = driver; this.wait = new WebDriverWait(driver, timeout); }
public void switchToFrame(By iframeLocator) { wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(iframeLocator)); }
public void switchToMain() { driver.switchTo().defaultContent(); }
public void doInFrame(By iframeLocator, Consumer<WebDriver> action) { switchToFrame(iframeLocator); try { action.accept(driver); } finally { switchToMain(); } }}Kullanım:
FrameUtils frames = new FrameUtils(driver, Duration.ofSeconds(10));
frames.doInFrame(By.cssSelector("iframe[src*='editor']"), d -> { d.findElement(By.id("title")).sendKeys("Başlık"); d.findElement(By.id("content")).sendKeys("Iframe içi içerik");});Page Object Model (POM) ile iframe
Section titled “Page Object Model (POM) ile iframe”public class EditorFrame { private WebDriver driver; private By iframe = By.cssSelector("iframe#editor-frame"); private By title = By.id("title"); private By content = By.id("content");
public EditorFrame(WebDriver driver) { this.driver = driver; }
public EditorFrame typeTitle(String text) { driver.findElement(title).clear(); driver.findElement(title).sendKeys(text); return this; }
public EditorFrame typeContent(String text) { driver.findElement(content).sendKeys(text); return this; }
public static EditorFrame in(WebDriver driver) { new WebDriverWait(driver, Duration.ofSeconds(10)) .until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.cssSelector("iframe#editor-frame"))); return new EditorFrame(driver); }}Test:
@Testpublic void editArticle() { driver.get("https://app.example.com/articles/new");
EditorFrame editor = EditorFrame.in(driver) .typeTitle("Iframe Rehberi") .typeContent("Merhaba!");
driver.switchTo().defaultContent(); driver.findElement(By.id("save")).click();}Üçüncü Parti iframe’ler (Örn. Ödeme, reCAPTCHA)
Section titled “Üçüncü Parti iframe’ler (Örn. Ödeme, reCAPTCHA)”- Genelde farklı alan adından gelir.
- Alan adı kısıtları JS ile erişimini engeller; Selenium ile switch normal çalışır.
- Çerçeve genelde çok parçalıdır (kart numarası, CVV, tarih ayrı iframeler):
- Her alan için ayrı iframe’e geç → değer gir →
defaultContent()→ diğerine geç.
- Her alan için ayrı iframe’e geç → değer gir →
// Kart numarasıdriver.switchTo().frame(driver.findElement(By.cssSelector("iframe[name='card-number']")));driver.findElement(By.name("cardnumber")).sendKeys("4111111111111111");driver.switchTo().defaultContent();
// Son kullanmadriver.switchTo().frame(driver.findElement(By.cssSelector("iframe[name='exp-date']")));driver.findElement(By.name("exp-date")).sendKeys("12/30");driver.switchTo().defaultContent();iframe mi, shadow DOM mu?
Section titled “iframe mi, shadow DOM mu?”iframe:page -> switchTo().frame(...)gerekir; tarayıcı adres çubuğu değişmez.shadow DOM:framedeğil;getShadowRoot()/JS ile gölge köke erişilir.
EğerswitchTo().frame(...)işe yaramıyorsa, öğe muhtemelen shadow root içindedir.
TestNG ile Örnek Akış
Section titled “TestNG ile Örnek Akış”public class IframeTests { private WebDriver driver; private WebDriverWait wait;
@BeforeClass public void setup() { driver = new ChromeDriver(); wait = new WebDriverWait(driver, Duration.ofSeconds(10)); }
@AfterClass public void teardown() { if (driver != null) driver.quit(); }
@Test public void canTypeInsideEditorIframe() { driver.get("https://the-internet.herokuapp.com/iframe");
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("mce_0_ifr"))); WebElement body = wait.until(ExpectedConditions.elementToBeClickable(By.id("tinymce"))); body.clear(); body.sendKeys("Hello from inside an iframe!");
driver.switchTo().defaultContent(); Assert.assertTrue(driver.getTitle().contains("The Internet")); }}Stabilite İçin Kontrol Listesi
Section titled “Stabilite İçin Kontrol Listesi”-
iframe’e geçmeden önce mevcudiyet şartını bekleyin (frameToBeAvailableAndSwitchToIt). -
defaultContent()/parentFrame()ile kontekst yönetimini net yapın. - Dinamik
src/idiçin sağlam locator tasarlayın (src*=). - İç içe yapılarda her adımda doğru seviyede olduğunuzu doğrulayın.
- Üçüncü parti iframelerde her alan için ayrı geçiş yapın.
-
StaleElementReferenceExceptionyakalayın, çerçeveyi yeniden bulun. - POM + yardımcı sınıflarla tekrar kullanım sağlayın.
Sık Karşılaşılan Hatalar ve Çözümler
Section titled “Sık Karşılaşılan Hatalar ve Çözümler”NoSuchElementException: Çerçeveye geçilmedi. →switchTo().frame(...)ekleyin.NoSuchFrameException: Yanlış locator/indeks. →presenceOfElementLocatedile doğrulayın, indeks yerineWebElementkullanın.- Klavye girilmiyor:
iframeiçindeki alandisabled/kapalı olabilir. → Görünürlük veelementToBeClickablebekleyin. - Performans sorunu: Aşırı
defaultContent()/frame()döngüsü. →doInFrame(...)gibi yardımcılarla kapsülleyin.
Küçük Yardımcı: Güvenli Text Girme
Section titled “Küçük Yardımcı: Güvenli Text Girme”public static void typeInFrame(WebDriver driver, By frameLocator, By inputLocator, String text) { WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(frameLocator)); try { WebElement input = wait.until(ExpectedConditions.elementToBeClickable(inputLocator)); input.clear(); input.sendKeys(text); } finally { driver.switchTo().defaultContent(); }}Kullanım:
typeInFrame(driver, By.cssSelector("iframe#bio"), By.id("bioText"), "MDX ile iframe dokümanı!");iframe→ ayrı DOM → switch zorunlu.- En sağlam yöntem:
WebElementileframee geçiş + explicit wait. - İç içe ve üçüncü parti iframelerde adım adım ve her alan için ayrı geçiş mantığını izleyin.
- POM ve yardımcı sınıflarla yeniden kullanılabilir bir çatı kurun.
Sorun yaşadığınız bir sayfa/iframe yapısı varsa, locator’larınızı paylaşın; örneğe göre uyarlayabilirim.