code: // Licensed to the Software Freedom Conservancy (SFC) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The SFC licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  
  package org.openqa.selenium;
  
  import static org.assertj.core.api.Assertions.assertThat;
  import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
  import static org.openqa.selenium.support.ui.ExpectedConditions.frameToBeAvailableAndSwitchToIt;
  import static org.openqa.selenium.support.ui.ExpectedConditions.not;
  import static org.openqa.selenium.support.ui.ExpectedConditions.presenceOfElementLocated;
  import static org.openqa.selenium.support.ui.ExpectedConditions.textToBe;
  import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
  import static org.openqa.selenium.testing.drivers.Browser.CHROME;
  import static org.openqa.selenium.testing.drivers.Browser.EDGE;
  import static org.openqa.selenium.testing.drivers.Browser.HTMLUNIT;
  import static org.openqa.selenium.testing.drivers.Browser.IE;
  import static org.openqa.selenium.testing.drivers.Browser.SAFARI;
  
  import java.util.Random;
  import org.junit.jupiter.api.AfterEach;
  import org.junit.jupiter.api.Test;
  import org.junit.jupiter.api.Timeout;
  import org.openqa.selenium.testing.Ignore;
  import org.openqa.selenium.testing.JupiterTestBase;
  import org.openqa.selenium.testing.NotYetImplemented;
  
  class FrameSwitchingTest extends JupiterTestBase {
  
    private Random random;
  
    @AfterEach
    public void tearDown() {
      try {
        driver.switchTo().defaultContent();
      } catch (Exception e) {
        // May happen if the driver went away.
      }
    }
  
    // ----------------------------------------------------------------------------------------------
    //
    // Tests that WebDriver doesn't do anything fishy when it navigates to a page with frames.
    //
    // ----------------------------------------------------------------------------------------------
    @Test
    void testShouldAlwaysFocusOnTheTopMostFrameAfterANavigationEvent() {
      driver.get(pages.framesetPage);
      driver.findElement(By.tagName("frameset")); // Test passes if this does not throw.
    }
  
    @Test
    void testShouldNotAutomaticallySwitchFocusToAnIFrameWhenAPageContainingThemIsLoaded() {
      driver.get(pages.iframePage);
      driver.findElement(By.id("iframe_page_heading"));
    }
  
    @Test
    @Timeout(10)
    public void testShouldOpenPageWithBrokenFrameset() {
      driver.get(appServer.whereIs("framesetPage3.html"));
  
      WebElement frame1 = driver.findElement(By.id("first"));
      driver.switchTo().frame(frame1);
  
      driver.switchTo().defaultContent();
  
      WebElement frame2 = driver.findElement(By.id("second"));
  
      try {
        driver.switchTo().frame(frame2);
      } catch (WebDriverException e) {
        // IE9 can not switch to this broken frame - it has no window.
      }
    }
  
    // ----------------------------------------------------------------------------------------------
    //
    // Tests that WebDriver can switch to frames as expected.
    //
    // ----------------------------------------------------------------------------------------------
    @Test
    void testShouldBeAbleToSwitchToAFrameByItsIndex() {
      driver.get(pages.framesetPage);
      driver.switchTo().frame(1);
  
      assertThat(driver.findElement(By.id("pageNumber")).getText()).isEqualTo("2");
    }
  
    @Test
    void testShouldBeAbleToSwitchToAnIframeByItsIndex() {
      driver.get(pages.iframePage);
      driver.switchTo().frame(0);
  
      assertThat(driver.findElement(By.name("id-name1")).getAttribute("value")).isEqualTo("name");
    }
  
    @Test
    void testShouldBeAbleToSwitchToAFrameByItsName() {
      driver.get(pages.framesetPage);
      driver.switchTo().frame("fourth");
  
      assertThat(driver.findElement(By.tagName("frame")).getAttribute("name")).isEqualTo("child1");
    }
  
    @Test
    void testShouldBeAbleToSwitchToAnIframeByItsName() {
      driver.get(pages.iframePage);
      driver.switchTo().frame("iframe1-name");
  
      assertThat(driver.findElement(By.name("id-name1")).getAttribute("value")).isEqualTo("name");
    }
  
    @Test
    void testShouldBeAbleToSwitchToAFrameByItsID() {
      driver.get(pages.framesetPage);
      driver.switchTo().frame("fifth");
      assertThat(driver.findElement(By.name("windowOne")).getText()).isEqualTo("Open new window");
    }
  
    @Test
    void testShouldBeAbleToSwitchToAnIframeByItsID() {
      driver.get(pages.iframePage);
      driver.switchTo().frame("iframe1");
  
      assertThat(driver.findElement(By.name("id-name1")).getAttribute("value")).isEqualTo("name");
    }
  
    @Test
    void testShouldBeAbleToSwitchToFrameWithNameContainingDot() {
      driver.get(pages.framesetPage);
      driver.switchTo().frame("sixth.iframe1");
      assertThat(driver.findElement(By.tagName("body")).getText()).contains("Page number 3");
    }
  
    @Test
    void testShouldBeAbleToSwitchToAFrameUsingAPreviouslyLocatedWebElement() {
      driver.get(pages.framesetPage);
      WebElement frame = driver.findElement(By.tagName("frame"));
      driver.switchTo().frame(frame);
  
      assertThat(driver.findElement(By.id("pageNumber")).getText()).isEqualTo("1");
    }
  
    @Test
    void testShouldBeAbleToSwitchToAnIFrameUsingAPreviouslyLocatedWebElement() {
      driver.get(pages.iframePage);
      WebElement frame = driver.findElement(By.tagName("iframe"));
      driver.switchTo().frame(frame);
  
      WebElement element = driver.findElement(By.name("id-name1"));
      assertThat(element.getAttribute("value")).isEqualTo("name");
    }
  
    @Test
    void testShouldEnsureElementIsAFrameBeforeSwitching() {
      driver.get(pages.framesetPage);
      WebElement frame = driver.findElement(By.tagName("frameset"));
  
      assertThatExceptionOfType(NoSuchFrameException.class)
          .isThrownBy(() -> driver.switchTo().frame(frame));
    }
  
    @Test
    void testFrameSearchesShouldBeRelativeToTheCurrentlySelectedFrame() {
      driver.get(pages.framesetPage);
  
      driver.switchTo().frame("second");
      assertThat(driver.findElement(By.id("pageNumber")).getText()).isEqualTo("2");
  
      assertThatExceptionOfType(NoSuchFrameException.class)
          .isThrownBy(() -> driver.switchTo().frame("third"));
  
      driver.switchTo().defaultContent();
      driver.switchTo().frame("third");
  
      assertThatExceptionOfType(NoSuchFrameException.class)
          .isThrownBy(() -> driver.switchTo().frame("second"));
  
      driver.switchTo().defaultContent();
      driver.switchTo().frame("second");
      assertThat(driver.findElement(By.id("pageNumber")).getText()).isEqualTo("2");
    }
  
    @Test
    void testShouldSelectChildFramesByChainedCalls() {
      driver.get(pages.framesetPage);
  
      driver.switchTo().frame("fourth").switchTo().frame("child2");
      assertThat(driver.findElement(By.id("pageNumber")).getText()).isEqualTo("11");
    }
  
    @Test
    void testShouldThrowFrameNotFoundExceptionLookingUpSubFramesWithSuperFrameNames() {
      driver.get(pages.framesetPage);
      driver.switchTo().frame("fourth");
  
      assertThatExceptionOfType(NoSuchFrameException.class)
          .isThrownBy(() -> driver.switchTo().frame("second"));
    }
  
    @Test
    void testShouldThrowAnExceptionWhenAFrameCannotBeFound() {
      driver.get(pages.xhtmlTestPage);
  
      assertThatExceptionOfType(NoSuchFrameException.class)
          .isThrownBy(() -> driver.switchTo().frame("Nothing here"));
    }
  
    @Test
    void testShouldThrowAnExceptionWhenAFrameCannotBeFoundByIndex() {
      driver.get(pages.xhtmlTestPage);
  
      assertThatExceptionOfType(NoSuchFrameException.class)
          .isThrownBy(() -> driver.switchTo().frame(27));
    }
  
    @Test
    void testShouldBeAbleToSwitchToParentFrame() {
      driver.get(pages.framesetPage);
  
      driver.switchTo().frame("fourth").switchTo().parentFrame().switchTo().frame("first");
      assertThat(driver.findElement(By.id("pageNumber")).getText()).isEqualTo("1");
    }
  
    @Test
    @NotYetImplemented(SAFARI)
    public void testShouldBeAbleToSwitchToParentFrameFromASecondLevelFrame() {
      driver.get(pages.framesetPage);
  
      driver
          .switchTo()
          .frame("fourth")
          .switchTo()
          .frame("child1")
          .switchTo()
          .parentFrame()
          .switchTo()
          .frame("child2");
      assertThat(driver.findElement(By.id("pageNumber")).getText()).isEqualTo("11");
    }
  
    @Test
    void testSwitchingToParentFrameFromDefaultContextIsNoOp() {
      driver.get(pages.xhtmlTestPage);
      driver.switchTo().parentFrame();
      assertThat(driver.getTitle()).isEqualTo("XHTML Test Page");
    }
  
    @Test
    void testShouldBeAbleToSwitchToParentFromAnIframe() {
      driver.get(pages.iframePage);
      driver.switchTo().frame(0);
  
      driver.switchTo().parentFrame();
      driver.findElement(By.id("iframe_page_heading"));
    }
  
    // ----------------------------------------------------------------------------------------------
    //
    // General frame handling behavior tests
    //
    // ----------------------------------------------------------------------------------------------
  
    @Test
    void testShouldContinueToReferToTheSameFrameOnceItHasBeenSelected() {
      driver.get(pages.framesetPage);
  
      driver.switchTo().frame(2);
      WebElement checkbox = driver.findElement(By.xpath("//input[@name='checky']"));
      checkbox.click();
      checkbox.submit();
  
      wait.until(textToBe(By.xpath("//p"), "Success!"));
    }
  
    @Test
    @NotYetImplemented(SAFARI)
    public void testShouldFocusOnTheReplacementWhenAFrameFollowsALinkToA_TopTargetedPage() {
      driver.get(pages.framesetPage);
  
      driver.switchTo().frame(0);
      driver.findElement(By.linkText("top")).click();
  
      String expectedTitle = "XHTML Test Page";
  
      wait.until(titleIs(expectedTitle));
    }
  
    @Test
    void testShouldAllowAUserToSwitchFromAnIframeBackToTheMainContentOfThePage() {
      driver.get(pages.iframePage);
      driver.switchTo().frame(0);
  
      driver.switchTo().defaultContent();
      driver.findElement(By.id("iframe_page_heading"));
    }
  
    @Test
    void testShouldAllowTheUserToSwitchToAnIFrameAndRemainFocusedOnIt() {
      driver.get(pages.iframePage);
      driver.switchTo().frame(0);
  
      driver.findElement(By.id("submitButton")).click();
  
      assertThat(getTextOfGreetingElement()).isEqualTo("Success!");
    }
  
    public String getTextOfGreetingElement() {
      return wait.until(presenceOfElementLocated(By.id("greeting"))).getText();
    }
  
    @Test
    void testShouldBeAbleToClickInAFrame() {
      driver.get(pages.framesetPage);
      driver.switchTo().frame("third");
  
      // This should replace frame "third" ...
      driver.findElement(By.id("submitButton")).click();
      // driver should still be focused on frame "third" ...
      assertThat(getTextOfGreetingElement()).isEqualTo("Success!");
      // Make sure it was really frame "third" which was replaced ...
      driver.switchTo().defaultContent().switchTo().frame("third");
      assertThat(getTextOfGreetingElement()).isEqualTo("Success!");
    }
  
    @Test
    void testShouldBeAbleToClickInAFrameThatRewritesTopWindowLocation() {
      driver.get(appServer.whereIs("click_tests/issue5237.html"));
      driver.switchTo().frame("search");
      driver.findElement(By.id("submit")).click();
      driver.switchTo().defaultContent();
      wait.until(titleIs("Target page for issue 5237"));
    }
  
    @Test
    void testShouldBeAbleToClickInASubFrame() {
      driver.get(pages.framesetPage);
      driver.switchTo().frame("sixth").switchTo().frame("iframe1");
  
      // This should replace frame "iframe1" inside frame "sixth" ...
      driver.findElement(By.id("submitButton")).click();
      // driver should still be focused on frame "iframe1" inside frame "sixth" ...
      assertThat(getTextOfGreetingElement()).isEqualTo("Success!");
      // Make sure it was really frame "iframe1" inside frame "sixth" which was replaced ...
      driver.switchTo().defaultContent().switchTo().frame("sixth").switchTo().frame("iframe1");
      assertThat(driver.findElement(By.id("greeting")).getText()).isEqualTo("Success!");
    }
  
    @Test
    void testShouldBeAbleToFindElementsInIframesByXPath() {
      driver.get(pages.iframePage);
  
      driver.switchTo().frame("iframe1");
  
      WebElement element = driver.findElement(By.xpath("//*[@id = 'changeme']"));
  
      assertThat(element).isNotNull();
    }
  
    @Test
    void testGetCurrentUrlReturnsTopLevelBrowsingContextUrl() {
      driver.get(pages.framesetPage);
      assertThat(driver.getCurrentUrl()).isEqualTo(pages.framesetPage);
  
      driver.switchTo().frame("second");
      assertThat(driver.getCurrentUrl()).isEqualTo(pages.framesetPage);
    }
  
    @Test
    void testGetCurrentUrlReturnsTopLevelBrowsingContextUrlForIframes() {
      driver.get(pages.iframePage);
      assertThat(driver.getCurrentUrl()).isEqualTo(pages.iframePage);
  
      driver.switchTo().frame("iframe1");
      assertThat(driver.getCurrentUrl()).isEqualTo(pages.iframePage);
    }
  
    @Test
    @Ignore(SAFARI)
    public void testShouldBeAbleToSwitchToTheTopIfTheFrameIsDeletedFromUnderUs() {
      driver.get(appServer.whereIs("frame_switching_tests/deletingFrame.html"));
  
      driver.switchTo().frame("iframe1");
  
      WebElement killIframe = driver.findElement(By.id("killIframe"));
      killIframe.click();
      driver.switchTo().defaultContent();
  
      assertFrameNotPresent("iframe1");
  
      WebElement addIFrame = driver.findElement(By.id("addBackFrame"));
      addIFrame.click();
      wait.until(presenceOfElementLocated(By.id("iframe1")));
  
      driver.switchTo().frame("iframe1");
  
      wait.until(presenceOfElementLocated(By.id("success")));
    }
  
    @Test
    @Ignore(SAFARI)
    public void testShouldBeAbleToSwitchToTheTopIfTheFrameIsDeletedFromUnderUsWithFrameIndex() {
      driver.get(appServer.whereIs("frame_switching_tests/deletingFrame.html"));
      int iframe = 0;
      wait.until(frameToBeAvailableAndSwitchToIt(iframe));
      // we should be in the frame now
      WebElement killIframe = driver.findElement(By.id("killIframe"));
      killIframe.click();
  
      driver.switchTo().defaultContent();
  
      WebElement addIFrame = driver.findElement(By.id("addBackFrame"));
      addIFrame.click();
      wait.until(frameToBeAvailableAndSwitchToIt(iframe));
  
      wait.until(presenceOfElementLocated(By.id("success")));
    }
  
    @Test
    @Ignore(SAFARI)
    public void testShouldBeAbleToSwitchToTheTopIfTheFrameIsDeletedFromUnderUsWithWebElement() {
      driver.get(appServer.whereIs("frame_switching_tests/deletingFrame.html"));
      WebElement iframe = driver.findElement(By.id("iframe1"));
      wait.until(frameToBeAvailableAndSwitchToIt(iframe));
      // we should be in the frame now
      WebElement killIframe = driver.findElement(By.id("killIframe"));
      killIframe.click();
  
      driver.switchTo().defaultContent();
  
      WebElement addIFrame = driver.findElement(By.id("addBackFrame"));
      addIFrame.click();
  
      iframe = driver.findElement(By.id("iframe1"));
      wait.until(frameToBeAvailableAndSwitchToIt(iframe));
      wait.until(presenceOfElementLocated(By.id("success")));
    }
  
    @Test
    @NotYetImplemented(value = CHROME, reason = "Throws NoSuchElementException")
    @NotYetImplemented(value = EDGE, reason = "Throws NoSuchElementException")
    @Ignore(IE)
    @NotYetImplemented(HTMLUNIT)
    @Ignore(SAFARI)
    public void testShouldNotBeAbleToDoAnythingTheFrameIsDeletedFromUnderUs() {
      driver.get(appServer.whereIs("frame_switching_tests/deletingFrame.html"));
  
      driver.switchTo().frame("iframe1");
      driver.findElement(By.id("killIframe")).click();
  
      assertThatExceptionOfType(NoSuchWindowException.class)
          .isThrownBy(() -> driver.findElement(By.id("killIframe")));
    }
  
    @Test
    void testShouldReturnWindowTitleInAFrameset() {
      driver.get(pages.framesetPage);
      driver.switchTo().frame("third");
      assertThat(driver.getTitle()).isEqualTo("Unique title");
    }
  
    @Test
    void testJavaScriptShouldExecuteInTheContextOfTheCurrentFrame() {
      JavascriptExecutor executor = (JavascriptExecutor) driver;
  
      driver.get(pages.framesetPage);
      assertThat((Boolean) executor.executeScript("return window == window.top")).isTrue();
      driver.switchTo().frame("third");
      assertThat((Boolean) executor.executeScript("return window != window.top")).isTrue();
    }
  
    @Test
    void testShouldNotSwitchMagicallyToTheTopWindow() {
      String baseUrl = appServer.whereIs("frame_switching_tests/");
      driver.get(baseUrl + "bug4876.html");
      driver.switchTo().frame(0);
      wait.until(presenceOfElementLocated(By.id("inputText")));
  
      for (int i = 0; i < 20; i++) {
        try {
          WebElement input = wait.until(presenceOfElementLocated(By.id("inputText")));
          WebElement submit = wait.until(presenceOfElementLocated(By.id("submitButton")));
          input.clear();
          random = new Random();
          input.sendKeys("rand" + random.nextInt());
          submit.click();
        } finally {
          String url =
              (String) ((JavascriptExecutor) driver).executeScript("return window.location.href");
          // IE6 and Chrome add "?"-symbol to the end of the URL
          if (url.endsWith("?")) {
            url = url.substring(0, url.length() - 1);
          }
          assertThat(url).isEqualTo(baseUrl + "bug4876_iframe.html");
        }
      }
    }
  
    @Test
    void testGetShouldSwitchToDefaultContext() {
      driver.get(pages.iframePage);
      driver.switchTo().frame(driver.findElement(By.id("iframe1")));
      driver.findElement(By.id("cheese")); // Found on formPage.html but not on iframes.html.
  
      driver.get(pages.iframePage); // This must effectively switchTo().defaultContent(), too.
      driver.findElement(By.id("iframe1"));
    }
  
    private void assertFrameNotPresent(String locator) {
      driver.switchTo().defaultContent();
      wait.until(not(frameToBeAvailableAndSwitchToIt(locator)));
      driver.switchTo().defaultContent();
    }
  }
  