Friday, October 19, 2012

clickable interface (300 mcg)

Clickable is a simple interface with only one method click. It is a common interface for Url, Link and Button classes.

public interface Clickable {

    void click();

}
public class Clickables<Where extends Searchable<Where>> implements Clickable {

    private static final Logger log = getLogger(Clickables.class);
    private final Where where;
    private final Locator<Where, Element> locator;

    public Clickables(Where where, Locator<Where, Element> locator) {
        this.locator = locator;
        this.where = where;
    }

    @Override
    public void click() {
        Element apply = locator.locate(where);
        log.info("clicking [" + apply + "]");
        where.save();
        apply.click();
        where.save();
    }

    @Override
    public String toString() {
        return locator.toString();
    }
}
public class Link<Where extends Searchable<Where>> extends Clickables<Where> {

    public Link(Where where, Locator<Where, Element> locator) {
        super(where, locator);
    }
}

    /**
     * Find the link using the selector.
     *
     * @param selector selector
     * @return the link using the selector.
     */
    @SuppressWarnings("unchecked")
    default public Clickable link(Supplier<By> selector) {
        return new Link<>((Where) this, element(selector));
    }

    public static <Where extends Searchable<Where>> Locators<Where, Element> element(Supplier<By> selector) {
        return new ElementLocator<>(selector);
    }
public class ElementLocator<Where extends Searchable<Where>>
        extends Locators<Where, Element> {

    public ElementLocator(Supplier<By> selector) {
        super((Where where) -> where.untilFound(selector));
    }
}

this example show how to use click(), and until()

        manningPage.link(Java).click();
        Element element = manningPage.until(new ElementLocator<>(ActiveMQ_In_Action));
        element.click();
        manningPage.until(IS_COPYRIGHTED);

What benefit do we get from this Link class? There are couple of benefits, one advantage is to add some logging and screenshot generating logic before and after the clicking event, those screenshots can be used for problem solving purpose in case test fails, we can use the generated screenshots as a analysis input to figure out what went wrong during last time. For example, finding an element will fail if there is a server error and the application return an error page instead of the expected page. Without the screenshot, we wouldn't be sure why we can't find the element.

So the click method can be rewritten like this,

Besides Link, Submit input and some button can also submit http request to refresh pages, so these can be encapsulated into Submit, Button classes.


After Java 8 came out, the wait logic can be further simplified into an interface with default methods.
public interface ExplcitWait<T> {

    default public <T1> T1 until(Function<T, T1> predicate) {
        return until(30, SECONDS, predicate);
    }

    default public void until(Predicate<T> predicate) {
        until(30, SECONDS, predicate);
    }

    default public <T1> T1 until(int duration, TimeUnit timeUnit, Function<T, T1> function) {
        return getFluentWait(duration, timeUnit).until((T it) -> function.apply(it));
    }

    default public void until(int duration, TimeUnit timeUnit, Predicate<T> predicate) {
        getFluentWait(duration, timeUnit).until((T it) -> predicate.test(it));
    }

    default public FluentWait<T> getFluentWait(int duration, TimeUnit timeUnit) {
        return new FluentWait<>((T) this).withTimeout(duration, timeUnit).pollingEvery(50, MILLISECONDS).ignoring(Exception.class);
    }
}

An useful application of Clickable interface is to collect all the menu items into a Stream of Clickable and for each item inside the stream, click them one by one to implement the menu testing,

No comments:

Post a Comment