package com.github.andreptb.fitnesse.selenium;
import java.util.function.BiFunction;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.openqa.selenium.Alert;
import org.openqa.selenium.NoAlertPresentException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import com.github.andreptb.fitnesse.selenium.SeleniumLocatorParser.ByFocus;
import com.github.andreptb.fitnesse.selenium.SeleniumLocatorParser.WebElementSelector;
import com.github.andreptb.fitnesse.util.FitnesseMarkup;
/**
* Utility class to handle browser native dialogs, such as confirm and alert.
*/
public class BrowserDialogHelper {
/**
* Utility to process FitNesse markup so can be used by Selenium WebDriver
*/
private FitnesseMarkup fitnesseMarkup = new FitnesseMarkup();
/**
* Enum holding all possible identifiers used to manipulate browser dialog
*/
private enum DialogIdentifier {
dialog,
alert,
confirm,
cancel;
}
/**
* Will try to click a browser dialog button in the following conditions:
* <ul>
* <li>If locator is any of: 'dialog', 'alert', 'dialog=confirm' or 'dialog=cancel'. If there is no alert present {@link NoAlertPresentException} will be thrown</li>
* <li>If locator is {@link ByFocus} and there is an alert present. If dialog contains 'confirm' and 'cancel' buttons, 'confirm' will be clicked</li>
* </ul>
*
* @param driver instance of {@link WebDriver} to manipulate dialog
* @param parsedLocator instance of {@link WebElementSelector} containing locator context
* @return true if dialog was clicked.
* @throws NoAlertPresentException if locator prefix is 'dialog' or 'alert' and there is no alert present
*/
public boolean click(WebDriver driver, WebElementSelector parsedLocator) {
return BooleanUtils.isTrue(doIfAvailable(driver, parsedLocator, (alert, value) -> {
DialogIdentifier action = StringUtils.isBlank(value) ? DialogIdentifier.confirm : DialogIdentifier.valueOf(value);
if (action == DialogIdentifier.confirm) {
alert.accept();
} else if (action == DialogIdentifier.cancel) {
alert.dismiss();
}
return true;
}));
}
public String text(WebDriver driver, WebElementSelector parsedLocator) {
return doIfAvailable(driver, parsedLocator, (alert, action) -> alert.getText());
}
public boolean present(WebDriver driver, WebElementSelector parsedLocator) {
return BooleanUtils.isTrue(doIfAvailable(driver, parsedLocator, (alert, action) -> true));
}
private <T> T doIfAvailable(WebDriver driver, WebElementSelector parsedLocator, BiFunction<Alert, String, T> callback) {
Pair<String, String> prefixAndLocator = this.fitnesseMarkup.cleanAndParseKeyValue(parsedLocator.getOriginalSelector(), FitnesseMarkup.KEY_VALUE_SEPARATOR);
DialogIdentifier selectorType = EnumUtils.getEnum(DialogIdentifier.class, prefixAndLocator.getKey());
if (selectorType != null) {
return callback.apply(driver.switchTo().alert(), prefixAndLocator.getValue());
}
if (!ClassUtils.isAssignable(parsedLocator.getBy().getClass(), ByFocus.class)) {
return null;
}
Alert alert = ExpectedConditions.alertIsPresent().apply(driver);
if (alert == null) {
return null;
}
return callback.apply(alert, prefixAndLocator.getValue());
}
}