All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.pojosontheweb.selenium.Findrs Maven / Gradle / Ivy

The newest version!
package com.pojosontheweb.selenium;

import org.hamcrest.BaseMatcher;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
import org.openqa.selenium.WebElement;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * Groups useful predicates and functions.
 */
public class Findrs {

    /**
     * Map a web element before composing it with the given matcher.
     *
     * @param describe Describe the mapping
     * @param fun      Map web element for matcher
     * @param matcher  Compose with this matcher
     * @return New composed matcher
     */
    public static  Matcher mapped(String describe, Function fun, Matcher matcher) {
        return new BaseMatcher<>() {

            @Override
            public boolean matches(Object item) {
                if (item instanceof WebElement w) {
                    return matcher.matches(fun.apply(w));
                }
                return false;
            }

            @Override
            public void describeTo(Description description) {
                description.appendText(String.format("mapped(%s,", describe)).appendDescriptionOf(matcher)
                        .appendText(")");
            }

            @Override
            public void describeMismatch(Object item, Description description) {
                if (item instanceof WebElement w) {
                    description.appendText("was ").appendValue(fun.apply(w));
                } else {
                    description.appendText("was null");
                }
            }
        };
    }

    /**
     * Map a list of web element before composing it with the given matcher.
     *
     * @param describe Describe the mapping
     * @param fun      Map a web element list item for matcher
     * @param matcher  Compose with this matcher
     * @return New composed matcher for list findr
     */
    public static  Matcher> mappedList(String describe, Function fun,
            Matcher> matcher) {
        return new BaseMatcher<>() {

            @Override
            public boolean matches(Object item) {
                if (item instanceof List ws) {
                    return matcher.matches(mapped(ws));
                }
                return false;
            }

            private List mapped(List ws) {
                return ws.stream().filter(WebElement.class::isInstance).map(WebElement.class::cast)
                        .map(fun)
                        .toList();
            }

            @Override
            public void describeTo(Description description) {
                description.appendText(String.format("mappedList(%s,", describe)).appendDescriptionOf(matcher)
                        .appendText(")");
            }

            @Override
            public void describeMismatch(Object item, Description description) {
                if (item instanceof List ws) {
                    description.appendText("was ").appendValueList("[", ",", "]", mapped(ws));
                } else {
                    description.appendText("was ?");
                }
            }
        };
    }

    /**
     * A regex matcher.
     *
     * @param regex The pattern to match
     * @return New regex matcher
     */
    public static Matcher matchesPattern(String regex) {
        return new BaseMatcher<>() {

            @Override
            public boolean matches(Object item) {
                if (item instanceof String s) {
                    return s.matches(regex);
                }
                return false;
            }

            @Override
            public void describeTo(Description description) {
                description.appendText(String.format("/%s/", regex));
            }
        };
    }

    private static Predicate matchAttribute(String attrName, Matcher matcher) {
        return matcherPredicate(
                mapped(String.format("getAttribute(%s)", attrName), w -> w.getAttribute(attrName), matcher));
    }

    private static Predicate matchText(Matcher matcher) {
        return matcherPredicate(mapped("getText", WebElement::getText, matcher));
    }

    /**
     * Create and return a new Predicate that matches an element's attribute value
     *
     * @param attrName      the name of the attribute
     * @param expectedValue the expected value of the attribute
     * @return a new Predicate
     */
    public static Predicate attrEquals(final String attrName, final String expectedValue) {
        return matchAttribute(attrName, CoreMatchers.equalTo(expectedValue));
    }

    /**
     * Create and return a new Predicate that checks for an attribute start
     *
     * @param attrName           the name of the attribute
     * @param expectedStartsWith the expected start of the attribute
     * @return a new Predicate
     */
    public static Predicate attrStartsWith(final String attrName, final String expectedStartsWith) {
        return matchAttribute(attrName, CoreMatchers.startsWith(expectedStartsWith));
    }

    /**
     * Create and return a new Predicate that checks for an attribute end
     *
     * @param attrName         the name of the attribute
     * @param expectedEndsWith the expected start of the attribute
     * @return a new Predicate
     */
    public static Predicate attrEndsWith(final String attrName, final String expectedEndsWith) {
        return matchAttribute(attrName, CoreMatchers.endsWith(expectedEndsWith));
    }

    /**
     * Create and return a new Predicate that checks for the presence of a css class
     * on a an element.
     *
     * @param className the expected css class
     * @return a new Predicate
     */
    public static Predicate hasClass(final String className) {
        return matcherPredicate(mapped("class", w -> Arrays.asList(w.getAttribute("class").split("\\s")),
                CoreMatchers.hasItem(className)));
    }

    /**
     * Create and return a new Predicate that checks for an element's
     * inner text.
     *
     * @param expected the expected inner text
     * @return a new Predicate
     */
    public static Predicate textEquals(final String expected) {
        return matchText(CoreMatchers.equalTo(expected));
    }

    /**
     * Create and return a new Predicate checking that an element's
     * inner text starts with passed text.
     *
     * @param expectedStartsWith the expected start of text
     * @return a new Predicate
     */
    public static Predicate textStartsWith(final String expectedStartsWith) {
        return matchText(CoreMatchers.startsWith(expectedStartsWith));
    }

    /**
     * Create and return a new Predicate checking that an element's
     * inner text contains passed text.
     *
     * @param expectedContains the expected contained text
     * @return a new Predicate
     */
    public static Predicate textContains(final String expectedContains) {
        return matchText(CoreMatchers.containsString(expectedContains));
    }

    /**
     * Create and return a new Predicate checking that an element's
     * inner text ends with passed text.
     *
     * @param expectedEndsWith the expected start of text
     * @return a new Predicate
     */
    public static Predicate textEndsWith(final String expectedEndsWith) {
        return matchText(CoreMatchers.endsWith(expectedEndsWith));
    }

    /**
     * Create and return a new Predicate that checks if the element is enabled.
     *
     * @return a new Predicate
     */
    public static Predicate isEnabled() {
        return matcherPredicate(mapped("isEnabled", WebElement::isEnabled, CoreMatchers.equalTo(true)));
    }

    /**
     * Create and return a new Predicate that checks if the element is displayed.
     *
     * @return a new Predicate
     */
    public static Predicate isDisplayed() {
        return matcherPredicate(mapped("isDisplayed", WebElement::isDisplayed, CoreMatchers.equalTo(true)));
    }

    /**
     * Create and return a new Predicate that checks if the element's text matches
     * passed regexp.
     *
     * @return a new Predicate
     */
    public static Predicate textMatches(final String regexp) {
        return matchText(matchesPattern(regexp));
    }

    /**
     * Create and return a new Predicate that checks for a css value on the element.
     *
     * @param propName      the css prop name
     * @param expectedValue the expected css value
     * @return a new Predicate
     */
    public static Predicate cssValue(final String propName, final String expectedValue) {
        return matcherPredicate(mapped(String.format("getCssValue(%s)", propName), w -> w.getCssValue(propName),
                CoreMatchers.equalTo(expectedValue)));
    }

    /**
     * Create and return a new Predicate that inverses passed predicate.
     *
     * @param in the predicate to inverse
     * @return a new Predicate
     */
    public static Predicate not(final Predicate in) {
        return new Predicate<>() {
            @Override
            public boolean test(WebElement input) {
                return !in.test(input);
            }

            @Override
            public String toString() {
                return "not " + in.toString();
            }
        };
    }

    public static Function click() {
        return new Function<>() {
            @Override
            public Boolean apply(WebElement webElement) {
                try {
                    webElement.click();
                } catch (Exception e) {
                    // click threw : try again !
                    return false;
                }
                return true;
            }

            @Override
            public String toString() {
                return "click()";
            }
        };
    }

    public static Function clear() {
        return new Function<>() {
            @Override
            public Boolean apply(WebElement webElement) {
                try {
                    webElement.clear();
                } catch (Exception e) {
                    return false;
                }
                return true;
            }

            @Override
            public String toString() {
                return "clear()";
            }
        };
    }

    public static Function sendKeys(final CharSequence... keys) {
        return new Function<>() {
            @Override
            public Boolean apply(WebElement webElement) {
                try {
                    webElement.sendKeys(keys);
                } catch (Exception e) {
                    // sendKeys throws, try again !
                    return false;
                }
                return true;
            }

            @Override
            public String toString() {
                return "sendKeys(" + Arrays.toString(keys) + ")";
            }
        };
    }

    // for testing
    static  Predicate matcherPredicate(Matcher matcher) {
        return new MatcherPredicate<>(matcher);
    }

    record MatcherPredicate(Matcher matcher) implements Predicate {

        public boolean test(T w) {
            return matcher.matches(w);
        }

        @Override
        public String toString() {
            return StringDescription.toString(matcher);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy