1. They all have these two instance fields, Where and Locator;
2. They all call locator.locate(where) before taking other actions.
To use one word to describe this activity of the locator, it is "locating"
Thus this class Locating is introduced into Selenium Capsules framework,
public class Locating<Where extends Searchable<Where>, What> { protected final Where where; protected final Locator<Where, What> locator; /** * Constructor of the Locating. * * @param where where * @param locator locator */ public Locating(Where where, Locator<Where, What> locator) { this.where = where; this.locator = locator; } public What locate() { return locator.locate(where); } }
And now Input is
public class Input<Where extends Searchable<Where>> extends Locating<Where, Element> { public static final Logger log = getLogger(Input.class); /** * Constructor of the input field. * * @param where where * @param selector selector */ public Input(Where where, Supplier<By> selector) { super(where, Locators.<Where>tryElement(selector)); } /** * the value of input field, for example, "good" will be return * <p> * String value = page.get(() -> By.name("status")) * <p> * <input name="status" value="good"/> * * @return the value of the input */ public String getValue() { final Retry retry = new Retry(5, 1, SECONDS); try { retry.attempt(() -> { log.info("{}", retry); Element element = locate(); return VALUE.locate(element); }); } catch (Exception e) { log.info("Failed to read text", e); } return null; } /** * set the value of input field, for example, * <p> * after, * page.set(() -> By.name("status"), "good"); * <p> * it will be, * <input name="status" value="good"/> * * @param value the value to set */ public void put(final Object value) { String string = value.toString(); final Retry retry = new Retry(5, 1, SECONDS); try { retry.attempt(() -> { log.info("{}", retry); Element element = locate(); element.clear(); element.sendKeys(string); if (VALUE.and(new IsStringEqual(string)).test(element)) { retry.off(); } return null; }); } catch (Exception e) { log.info("Failed to set text {}", string); } } /** * Test the autocomplete function for the input by given value, click the element * on the suggestion list which matches value parameter. * <p> * Please refer "http://seleniumcapsules.blogspot.com/2014/05/by-xpath.html" * * @param value value * @param locator locator */ public void autocomplete(Object value, Locator<Where, Element> locator) { Element element = locate(); element.clear(); Element suggestion; for (char c : value.toString().toCharArray()) { element.sendKeys(String.valueOf(c)); suggestion = locator.locate(where); if (suggestion != null) { suggestion.click(); return; } } suggestion = where.until(locator); if (suggestion != null) { suggestion.click(); } } }
Checkbox became,
public class Checkbox<Where extends Searchable<Where>> extends Locating<Where, Element> { /** * Constructor of the checkbox. * * @param where the place the checkbox can be found * @param selector the selector that leads to the checkbox */ public Checkbox(final Where where, Supplier<By> selector) { super(where, element(selector)); } /** * Change the checkbox according to the value parameter * * @param value true or false */ public void setValue(boolean value) { Element checkbox = locate(); if (checkbox != null && checkbox.isSelected() != value) { checkbox.click(); } } /** * @return whether the checkbox is checked or not */ public boolean isChecked() { return CHECKED.and(TRUE).test(locate()); } }
Radio became,
public class RadioButton<Where extends Searchable<Where>> extends Locating<Where, Stream&tl;Element>> { /** * Constructor this radio button. * * @param where where * @param selector selector */ public RadioButton(Where where, Supplier<By> selector) { super(where, elements(selector)); } /** * @param value value to set */ public void setValue(Object value) { new FirstMatch<>(DISPLAYED.and(VALUE.and(new IsStringEqual(value)))) .and(CLICK_IF_NOT_NULL) .locate(locate()); } /** * @return the value of the select radio */ public String getValue() { return new FirstMatch<>(DISPLAYED.and(CHECKED.and(TRUE))) .and(VALUE) .locate(locate()); } }
There no longer have these two instance fields,
protected final Locator
And
radioButtonGroup .and(new FirstMatch<>(DISPLAYED.and(CHECKED.and(TRUE)))) .and(VALUE) .locate(where);
new FirstMatch<>(DISPLAYED.and(CHECKED.and(TRUE))) .and(VALUE) .locate(radioButtonGroup.locate(where));
VALUE.locate( new FirstMatch<>(DISPLAYED.and(CHECKED.and(TRUE))).locate( radioButtonGroup.locate(where)));
They all are equivalent to this sequential form,
Stream<Element> radios = radioButtonGroup.locate(where); Element radio = new FirstMatch<>(DISPLAYED.and(CHECKED.and(TRUE))).locate(radios); String value = VALUE.locate(radio);
which is exactly same to this raw form, without Selenium Capsules, you can see a lot of Selenium powder.
String value = null; List<WebElement> radios = webDriver.findElements(By.name("customFieldDS.customfield_ROW0_value")); for (WebElement radio : radios) { if (radio.getAttribute("checked").equals("true")) { value = radio.getAttribute("value")); } }