İçeriğe geç

Selenium'da iframelerle Çalışmak


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.
  • iframe içindeki elementlere erişmek için önce çerçeveye geçiş yapılmalıdır.

  • 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 iframe görünür olmayabilir; explicit wait ile beklemek testleri kararlı hale getirir.


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ışır
WebElement editor = driver.findElement(By.id("richTextEditor"));
editor.sendKeys("Merhaba iframe!");
// Ana sayfaya geri dön
driver.switchTo().defaultContent();

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();

// dış iframe
driver.switchTo().frame("outer-frame");
// iç iframe
driver.switchTo().frame("inner-frame");
driver.findElement(By.id("inside")).click();
// bir üst iframe
driver.switchTo().parentFrame();
// ana sayfa
driver.switchTo().defaultContent();

  1. 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']")));
  1. Görünürlük/aktivasyon kontrolü:
    Bazı iframeler lazy-load olur. Gerekirse scrollIntoView() veya Actions ile 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);
  1. 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ı”
  • iframe yeniden yüklendiğinde önceki WebElement referansları bayatlar.
  • Çözüm: switchTo().defaultContent() → iframe’i yeniden bulun → tekrar switchTo().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");
});

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:

@Test
public 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ç.
// Kart numarası
driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[name='card-number']")));
driver.findElement(By.name("cardnumber")).sendKeys("4111111111111111");
driver.switchTo().defaultContent();
// Son kullanma
driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[name='exp-date']")));
driver.findElement(By.name("exp-date")).sendKeys("12/30");
driver.switchTo().defaultContent();

  • iframe: page -> switchTo().frame(...) gerekir; tarayıcı adres çubuğu değişmez.
  • shadow DOM: frame değil; getShadowRoot()/JS ile gölge köke erişilir.
    Eğer switchTo().frame(...) işe yaramıyorsa, öğe muhtemelen shadow root içindedir.

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"));
}
}

  • iframe’e geçmeden önce mevcudiyet şartını bekleyin (frameToBeAvailableAndSwitchToIt).
  • defaultContent() / parentFrame() ile kontekst yönetimini net yapın.
  • Dinamik src/id iç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.
  • StaleElementReferenceException yakalayı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. → presenceOfElementLocated ile doğrulayın, indeks yerine WebElement kullanın.
  • Klavye girilmiyor: iframe içindeki alan disabled/kapalı olabilir. → Görünürlük ve elementToBeClickable bekleyin.
  • Performans sorunu: Aşırı defaultContent()/frame() döngüsü. → doInFrame(...) gibi yardımcılarla kapsülleyin.

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: WebElement ile framee 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.