package com.github.andreptb.fitnesse.selenium;
import com.github.andreptb.fitnesse.util.FitnesseMarkup;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.openqa.selenium.support.ui.Select;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
/**
* Utility class designed to wrap infrastructure code necessary to operate with selenium {@link Select} API.
*/
public class SelectWebElementHelper {
/**
* HTML input value attribute constant
*/
private static final String INPUT_VALUE_ATTRIBUTE = "value";
/**
* Utility to process FitNesse markup so can be used by Selenium WebDriver
*/
private FitnesseMarkup fitnesseMarkup = new FitnesseMarkup();
/**
* enum mapping option locator identifier.
*/
private enum OptionSelectorType {
/**
* Label selector, will look for the text of the option element
*/
label((select, value) -> select.selectByVisibleText(value), select -> select.getFirstSelectedOption().getText()),
/**
* Value selector, will look for the value attribute of the option element
*/
value((select, value) -> select.selectByValue(value), select -> select.getFirstSelectedOption().getAttribute(SelectWebElementHelper.INPUT_VALUE_ATTRIBUTE)),
/**
* Value selector, will look for the index of the desired option element
*/
index((select, value) -> select.selectByIndex(NumberUtils.toInt(value)), select -> select.getOptions().indexOf(select.getFirstSelectedOption()));
/**
* Function that selects a value in a {@link Select} element
*/
private BiConsumer<Select, String> selector;
/**
* Function that retrieves a value from a {@link Select} element
*/
private Function<Select, Object> retriever;
OptionSelectorType(BiConsumer<Select, String> selector, Function<Select, Object> retriever) {
this.selector = selector;
this.retriever = retriever;
}
}
/**
* Selects a option of a select element.
*
* @param driverHelper API that will be used for selenium task execution
* @param optionLocator expected to be [type]=value, see {@link OptionSelectorType} for possible types.
* @param locator an element locator
* @return result Boolean result indication of assertion/operation
*/
public boolean select(WebDriverHelper driverHelper, String optionLocator, String locator) {
Pair<String, String> optionTypeAndLocatorWithExpectedValue = this.fitnesseMarkup.swapValueToCheck(optionLocator, locator);
Pair<OptionSelectorType, String> parsedOptionLocator = parseOptionLocator(optionTypeAndLocatorWithExpectedValue.getKey());
return driverHelper.doWhenAvailable(optionTypeAndLocatorWithExpectedValue.getValue(), (driver, parsedLocator) -> {
parsedOptionLocator.getKey().selector.accept(new Select(driver.findElement(parsedLocator.getBy())), parsedOptionLocator.getValue());
});
}
/**
* Retrieves information from the current selected value in a select element.
*
* @param driverHelper API that will be used for selenium task execution
* @param optionLocator see {@link OptionSelectorType} for possible types.
* @param locator an element locator
* @return the information from the current selected element
*/
public String selected(WebDriverHelper driverHelper, String optionLocator, String locator) {
Pair<String, String> optionTypeAndLocatorWithExpectedValue = this.fitnesseMarkup.swapValueToCheck(optionLocator, locator);
OptionSelectorType optionRetriever = parseOptionLocator(optionTypeAndLocatorWithExpectedValue.getKey()).getKey();
return driverHelper.getWhenAvailable(optionTypeAndLocatorWithExpectedValue.getValue(), (driver, parsedLocator) -> this.fitnesseMarkup.clean(optionRetriever.retriever.apply(new Select(driver.findElement(parsedLocator.getBy())))));
}
private Pair<OptionSelectorType, String> parseOptionLocator(String optionLocator) {
Pair<String, String> keyValue = this.fitnesseMarkup.cleanAndParseKeyValue(optionLocator, FitnesseMarkup.KEY_VALUE_SEPARATOR);
// if no type is informed value will be parsed as prefix
String prefix = keyValue.getKey();
String value = StringUtils.defaultIfBlank(keyValue.getValue(), prefix);
return Pair.of(Optional.ofNullable(EnumUtils.getEnum(OptionSelectorType.class, prefix)).orElse(OptionSelectorType.label), value);
}
}