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.WaitingConditions.newWindowIsOpened;
  import static org.openqa.selenium.support.ui.ExpectedConditions.alertIsPresent;
  import static org.openqa.selenium.support.ui.ExpectedConditions.presenceOfElementLocated;
  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.FIREFOX;
  import static org.openqa.selenium.testing.drivers.Browser.HTMLUNIT;
  import static org.openqa.selenium.testing.drivers.Browser.SAFARI;
  
  import java.util.Set;
  import org.junit.jupiter.api.AfterEach;
  import org.junit.jupiter.api.Test;
  import org.openqa.selenium.environment.webserver.Page;
  import org.openqa.selenium.support.ui.ExpectedCondition;
  import org.openqa.selenium.testing.Ignore;
  import org.openqa.selenium.testing.JupiterTestBase;
  import org.openqa.selenium.testing.NoDriverAfterTest;
  import org.openqa.selenium.testing.SwitchToTopAfterTest;
  
  class AlertsTest extends JupiterTestBase {
  
    private static ExpectedCondition<Boolean> textInElementLocated(
        final By locator, final String text) {
      return driver -> text.equals(driver.findElement(locator).getText());
    }
  
    private static ExpectedCondition<WebDriver> ableToSwitchToWindow(final String name) {
      return driver -> driver.switchTo().window(name);
    }
  
    @AfterEach
    public void closeAlertIfPresent() {
      try {
        driver.switchTo().alert().dismiss();
      } catch (WebDriverException ignore) {
      }
    }
  
    private String alertPage(String alertText) {
      return appServer.create(
          new Page()
              .withTitle("Testing Alerts")
              .withBody(
                  "<a href='#' id='alert' onclick='alert(\"" + alertText + "\");'>click me</a>"));
    }
  
    private String promptPage(String defaultText) {
      return appServer.create(
          new Page()
              .withTitle("Testing Prompt")
              .withScripts(
                  "function setInnerText(id, value) {",
                  "  document.getElementById(id).innerHTML = '<p>' + value + '</p>';",
                  "}",
                  defaultText == null
                      ? "function displayPrompt() { setInnerText('text', prompt('Enter something'));"
                          + " }"
                      : "function displayPrompt() { setInnerText('text', prompt('Enter something', '"
                          + defaultText
                          + "')); }")
              .withBody(
                  "<a href='#' id='prompt' onclick='displayPrompt();'>click me</a>",
                  "<div id='text'>acceptor</div>"));
    }
  
    @Test
    void testShouldBeAbleToOverrideTheWindowAlertMethod() {
      driver.get(alertPage("cheese"));
  
      ((JavascriptExecutor) driver)
          .executeScript(
              "window.alert = function(msg) { document.getElementById('text').innerHTML = msg; }");
      driver.findElement(By.id("alert")).click();
  
      // If we can perform any action, we're good to go
      assertThat(driver.getTitle()).isEqualTo("Testing Alerts");
    }
  
    @Test
    void testShouldAllowUsersToAcceptAnAlertManually() {
      driver.get(alertPage("cheese"));
  
      driver.findElement(By.id("alert")).click();
      Alert alert = wait.until(alertIsPresent());
      alert.accept();
  
      // If we can perform any action, we're good to go
      assertThat(driver.getTitle()).isEqualTo("Testing Alerts");
    }
  
    @Test
    void testShouldThrowIllegalArgumentExceptionWhenKeysNull() {
      driver.get(alertPage("cheese"));
  
      driver.findElement(By.id("alert")).click();
      Alert alert = wait.until(alertIsPresent());
  
      assertThatExceptionOfType(IllegalArgumentException.class)
          .isThrownBy(() -> alert.sendKeys(null));
    }
  
    @Test
    void testShouldAllowUsersToAcceptAnAlertWithNoTextManually() {
      driver.get(alertPage(""));
  
      driver.findElement(By.id("alert")).click();
      Alert alert = wait.until(alertIsPresent());
      alert.accept();
  
      // If we can perform any action, we're good to go
      assertThat(driver.getTitle()).isEqualTo("Testing Alerts");
    }
  
    @Test
    void testShouldAllowUsersToDismissAnAlertManually() {
      driver.get(alertPage("cheese"));
  
      driver.findElement(By.id("alert")).click();
      Alert alert = wait.until(alertIsPresent());
      alert.dismiss();
  
      // If we can perform any action, we're good to go
      assertThat(driver.getTitle()).isEqualTo("Testing Alerts");
    }
  
    @Test
    void testShouldAllowAUserToAcceptAPrompt() {
      driver.get(promptPage(null));
  
      driver.findElement(By.id("prompt")).click();
      Alert alert = wait.until(alertIsPresent());
      alert.accept();
  
      // If we can perform any action, we're good to go
      assertThat(driver.getTitle()).isEqualTo("Testing Prompt");
    }
  
    @Test
    void testShouldAllowAUserToDismissAPrompt() {
      driver.get(promptPage(null));
  
      driver.findElement(By.id("prompt")).click();
      Alert alert = wait.until(alertIsPresent());
      alert.dismiss();
  
      // If we can perform any action, we're good to go
      assertThat(driver.getTitle()).isEqualTo("Testing Prompt");
    }
  
    @Test
    void testShouldAllowAUserToSetTheValueOfAPrompt() {
      driver.get(promptPage(null));
  
      driver.findElement(By.id("prompt")).click();
      Alert alert = wait.until(alertIsPresent());
      alert.sendKeys("cheese");
      alert.accept();
  
      wait.until(textInElementLocated(By.id("text"), "cheese"));
    }
  
    @Test
    void testSettingTheValueOfAnAlertThrows() {
      driver.get(alertPage("cheese"));
  
      driver.findElement(By.id("alert")).click();
  
      Alert alert = wait.until(alertIsPresent());
      assertThatExceptionOfType(ElementNotInteractableException.class)
          .isThrownBy(() -> alert.sendKeys("cheese"));
    }
  
    @Test
    void testShouldAllowTheUserToGetTheTextOfAnAlert() {
      driver.get(alertPage("cheese"));
  
      driver.findElement(By.id("alert")).click();
      Alert alert = wait.until(alertIsPresent());
      String value = alert.getText();
      alert.accept();
  
      assertThat(value).isEqualTo("cheese");
    }
  
    @Test
    void testShouldAllowTheUserToGetTheTextOfAPrompt() {
      driver.get(promptPage(null));
  
      driver.findElement(By.id("prompt")).click();
      Alert alert = wait.until(alertIsPresent());
      String value = alert.getText();
      alert.accept();
  
      assertThat(value).isEqualTo("Enter something");
    }
  
    @Test
    void testAlertShouldNotAllowAdditionalCommandsIfDismissed() {
      driver.get(alertPage("cheese"));
  
      driver.findElement(By.id("alert")).click();
      Alert alert = wait.until(alertIsPresent());
      alert.accept();
  
      assertThatExceptionOfType(NoAlertPresentException.class).isThrownBy(alert::getText);
    }
  
    @SwitchToTopAfterTest
    @Test
    void testShouldAllowUsersToAcceptAnAlertInAFrame() {
      String iframe =
          appServer.create(
              new Page()
                  .withBody(
                      "<a href='#' id='alertInFrame' onclick='alert(\"framed cheese\");'>click"
                          + " me</a>"));
      driver.get(
          appServer.create(
              new Page()
                  .withTitle("Testing Alerts")
                  .withBody(
                      String.format("<iframe src='%s' name='iframeWithAlert'></iframe>", iframe))));
  
      driver.switchTo().frame("iframeWithAlert");
      driver.findElement(By.id("alertInFrame")).click();
      Alert alert = wait.until(alertIsPresent());
      alert.accept();
  
      // If we can perform any action, we're good to go
      assertThat(driver.getTitle()).isEqualTo("Testing Alerts");
    }
  
    @SwitchToTopAfterTest
    @Test
    void testShouldAllowUsersToAcceptAnAlertInANestedFrame() {
      String iframe =
          appServer.create(
              new Page()
                  .withBody(
                      "<a href='#' id='alertInFrame' onclick='alert(\"framed cheese\");'>click"
                          + " me</a>"));
      String iframe2 =
          appServer.create(
              new Page()
                  .withBody(
                      String.format("<iframe src='%s' name='iframeWithAlert'></iframe>", iframe)));
      driver.get(
          appServer.create(
              new Page()
                  .withTitle("Testing Alerts")
                  .withBody(
                      String.format("<iframe src='%s' name='iframeWithIframe'></iframe>", iframe2))));
  
      driver.switchTo().frame("iframeWithIframe").switchTo().frame("iframeWithAlert");
  
      driver.findElement(By.id("alertInFrame")).click();
      Alert alert = wait.until(alertIsPresent());
      alert.accept();
  
      // If we can perform any action, we're good to go
      assertThat(driver.getTitle()).isEqualTo("Testing Alerts");
    }
  
    @Test
    void testSwitchingToMissingAlertThrows() {
      driver.get(alertPage("cheese"));
  
      assertThatExceptionOfType(NoAlertPresentException.class)
          .isThrownBy(() -> driver.switchTo().alert());
    }
  
    @Test
    void testSwitchingToMissingAlertInAClosedWindowThrows() {
      String blank = appServer.create(new Page());
      driver.get(
          appServer.create(
              new Page()
                  .withBody(
                      String.format(
                          "<a id='open-new-window' href='%s' target='newwindow'>open new window</a>",
                          blank))));
  
      String mainWindow = driver.getWindowHandle();
      try {
        driver.findElement(By.id("open-new-window")).click();
        wait.until(ableToSwitchToWindow("newwindow"));
        driver.close();
  
        assertThatExceptionOfType(NoSuchWindowException.class)
            .isThrownBy(() -> driver.switchTo().alert());
  
      } finally {
        driver.switchTo().window(mainWindow);
      }
    }
  
    @Test
    void testPromptShouldUseDefaultValueIfNoKeysSent() {
      driver.get(promptPage("This is a default value"));
  
      wait.until(presenceOfElementLocated(By.id("prompt"))).click();
      Alert alert = wait.until(alertIsPresent());
      alert.accept();
  
      wait.until(textInElementLocated(By.id("text"), "This is a default value"));
    }
  
    @Test
    void testPromptShouldHaveNullValueIfDismissed() {
      driver.get(promptPage("This is a default value"));
  
      driver.findElement(By.id("prompt")).click();
      Alert alert = wait.until(alertIsPresent());
      alert.dismiss();
  
      wait.until(textInElementLocated(By.id("text"), "null"));
    }
  
    @Test
    void testHandlesTwoAlertsFromOneInteraction() {
      driver.get(
          appServer.create(
              new Page()
                  .withScripts(
                      "function setInnerText(id, value) {",
                      "  document.getElementById(id).innerHTML = '<p>' + value + '</p>';",
                      "}",
                      "function displayTwoPrompts() {",
                      "  setInnerText('text1', prompt('First'));",
                      "  setInnerText('text2', prompt('Second'));",
                      "}")
                  .withBody(
                      "<a href='#' id='double-prompt' onclick='displayTwoPrompts();'>click me</a>",
                      "<div id='text1'></div>",
                      "<div id='text2'></div>")));
  
      wait.until(presenceOfElementLocated(By.id("double-prompt"))).click();
      Alert alert1 = wait.until(alertIsPresent());
      alert1.sendKeys("brie");
      alert1.accept();
  
      Alert alert2 = wait.until(alertIsPresent());
      alert2.sendKeys("cheddar");
      alert2.accept();
  
      wait.until(textInElementLocated(By.id("text1"), "brie"));
      wait.until(textInElementLocated(By.id("text2"), "cheddar"));
    }
  
    @Test
    void testShouldHandleAlertOnPageLoad() {
      String pageWithOnLoad =
          appServer.create(
              new Page()
                  .withOnLoad("javascript:alert(\"onload\")")
                  .withBody("<p>Page with onload event handler</p>"));
      driver.get(
          appServer.create(
              new Page()
                  .withBody(
                      String.format("<a id='link' href='%s'>open new page</a>", pageWithOnLoad))));
  
      driver.findElement(By.id("link")).click();
      Alert alert = wait.until(alertIsPresent());
      String value = alert.getText();
      alert.accept();
  
      assertThat(value).isEqualTo("onload");
      wait.until(textInElementLocated(By.tagName("p"), "Page with onload event handler"));
    }
  
    @Test
    void testShouldHandleAlertOnPageLoadUsingGet() {
      driver.get(
          appServer.create(
              new Page()
                  .withOnLoad("javascript:alert(\"onload\")")
                  .withBody("<p>Page with onload event handler</p>")));
  
      Alert alert = wait.until(alertIsPresent());
      String value = alert.getText();
      alert.accept();
  
      assertThat(value).isEqualTo("onload");
      wait.until(textInElementLocated(By.tagName("p"), "Page with onload event handler"));
    }
  
    @Test
    @Ignore(value = CHROME, reason = "Hangs")
    @Ignore(value = EDGE, reason = "Hangs")
    @Ignore(SAFARI)
    @NoDriverAfterTest
    public void testShouldNotHandleAlertInAnotherWindow() {
      String pageWithOnLoad =
          appServer.create(
              new Page()
                  .withOnLoad("javascript:alert(\"onload\")")
                  .withBody("<p>Page with onload event handler</p>"));
      driver.get(
          appServer.create(
              new Page()
                  .withBody(
                      String.format(
                          "<a id='open-new-window' href='%s' target='newwindow'>open new window</a>",
                          pageWithOnLoad))));
  
      Set<String> currentWindowHandles = driver.getWindowHandles();
      driver.findElement(By.id("open-new-window")).click();
      wait.until(newWindowIsOpened(currentWindowHandles));
  
      assertThatExceptionOfType(TimeoutException.class)
          .isThrownBy(() -> wait.until(alertIsPresent()));
    }
  
    @Test
    @Ignore(value = HTMLUNIT, reason = "https://github.com/SeleniumHQ/htmlunit-driver/issues/57")
    @Ignore(
        value = FIREFOX,
        reason = "Per spec, an error data dictionary with text value is optional")
    public void testIncludesAlertTextInUnhandledAlertException() {
      driver.get(alertPage("cheese"));
  
      driver.findElement(By.id("alert")).click();
      wait.until(alertIsPresent());
  
      assertThatExceptionOfType(UnhandledAlertException.class)
          .isThrownBy(driver::getTitle)
          .withMessageContaining("cheese")
          .satisfies(ex -> assertThat(ex.getAlertText()).isEqualTo("cheese"));
    }
  
    @NoDriverAfterTest
    @Test
    void testCanQuitWhenAnAlertIsPresent() {
      driver.get(alertPage("cheese"));
  
      driver.findElement(By.id("alert")).click();
      wait.until(alertIsPresent());
  
      driver.quit();
    }
  
    @Test
    void shouldHandleAlertOnFormSubmit() {
      driver.get(
          appServer.create(
              new Page()
                  .withTitle("Testing Alerts")
                  .withBody(
                      "<form id='theForm' action='javascript:alert(\"Tasty cheese\");'>",
                      "<input id='unused' type='submit' value='Submit'>",
                      "</form>")));
  
      driver.findElement(By.id("theForm")).submit();
      Alert alert = wait.until(alertIsPresent());
      String value = alert.getText();
      alert.accept();
  
      assertThat(value).isEqualTo("Tasty cheese");
      assertThat(driver.getTitle()).isEqualTo("Testing Alerts");
    }
  }
  