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

ru.mk.pump.web.elements.internal.AbstractElement Maven / Gradle / Ivy

package ru.mk.pump.web.elements.internal;

import com.google.common.collect.Maps;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import ru.mk.pump.commons.utils.Strings;
import ru.mk.pump.commons.utils.WaitResult;
import ru.mk.pump.web.browsers.Browser;
import ru.mk.pump.web.elements.api.listeners.ActionListener;
import ru.mk.pump.web.elements.api.listeners.StateListener;
import ru.mk.pump.web.elements.enums.StateType;
import ru.mk.pump.web.elements.internal.interfaces.Action;
import ru.mk.pump.web.elements.internal.interfaces.InternalElement;
import ru.mk.pump.web.page.api.Page;
import ru.mk.pump.web.utils.Xpath;

@SuppressWarnings({"WeakerAccess", "unused", "UnusedReturnValue", "unchecked"})
abstract class AbstractElement implements InternalElement {

    /*turn off for more speed*/
    public static boolean JS_WAIT = false;

    private final By avatarBy;

    private final ElementWaiter waiter;

    @Getter
    private final Browser browser;

    private final InternalElement parentElement;

    @Getter
    private final ActionExecutor actionExecutor;

    @Getter
    private final StateResolver stateResolver;

    @Getter
    private final Finder finder;

    private final Consumer> TEAR_DOWN = stateWaitResult -> getFinder().getLast()
        .ifPresent(waitResult -> stateWaitResult.withCause(waitResult.getCause()));

    @Getter
    private final ActionsStore actionsStore;

    @Setter(AccessLevel.PROTECTED)
    protected boolean xpathAutoFix = true;

    private String elementName;

    @Getter
    private String elementDescription = "nonArg (recommend to add)";

    private final Page page;

    private int listIndex = -1;

    //region CONSTRUCTORS
    public AbstractElement(By avatarBy, Page page) {
        this(avatarBy, null, null, page);
    }

    public AbstractElement(By avatarBy, InternalElement parentElement) {
        this(avatarBy, parentElement, null, null);
    }

    public AbstractElement(By avatarBy, Browser browser) {
        this(avatarBy, null, browser, null);
    }

    private AbstractElement(@NonNull By avatarBy, @Nullable InternalElement parentElement, @Nullable Browser browser, @Nullable Page page) {
        this.avatarBy = xpathAutoFix ? Xpath.fixIfXpath(avatarBy) : avatarBy;
        this.parentElement = parentElement;
        if (parentElement != null) {
            this.page = parentElement.getPage();
            this.browser = parentElement.getBrowser();
        } else {
            this.page = page;
            if (page != null) {
                this.browser = page.getBrowser();
            } else {
                this.browser = browser;
            }
        }
        this.waiter = newDelegateWaiter();
        this.finder = newDelegateFinder();
        this.stateResolver = newDelegateStateResolver();
        this.actionsStore = new ActionsStore(this, newDelegateActionFactory());
        this.actionExecutor = newDelegateActionExecutor(stateResolver);
        this.elementName = getBy().toString();
    }

    //endregion

    //region delegates
    protected ElementWaiter newDelegateWaiter() {
        return ElementWaiter.newWaiterS();
    }

    protected Finder newDelegateFinder() {
        return new Finder(this);
    }

    protected ActionFactory newDelegateActionFactory() {
        return new ActionFactory(this);
    }

    protected StateResolver newDelegateStateResolver() {
        return new StateResolver(this);
    }

    protected ActionExecutor newDelegateActionExecutor(StateResolver stateResolver) {
        return new ActionExecutor().withStateResolver(stateResolver);
    }

    public AbstractElement addActionListener(List actionListener) {
        actionListener.forEach(actionExecutor::addListener);
        return this;
    }

    public AbstractElement addStateListener(List stateListener) {
        stateListener.forEach(stateResolver::addListener);
        return this;
    }
    //endregion

    public CHILD setName(String elementName) {
        if (!Strings.isEmpty(elementName)) {
            this.elementName = elementName;
        }
        return (CHILD) this;
    }

    public CHILD setDescription(String elementDescription) {
        if (!Strings.isEmpty(elementDescription)) {
            this.elementDescription = elementDescription;
        }
        return (CHILD) this;
    }

    @Override
    public String getName() {
        return elementName;
    }

    @Override
    public By getBy() {
        return avatarBy;
    }

    @Override
    public String fullByAsString() {
        //TODO::Сделать конкатинацию By от всех родителей и заменить везде, где логируется By
        return Strings.toString(getBy());
    }

    @Override
    public Page getPage() {
        return page;
    }

    @Override
    public Optional getParent() {
        return Optional.ofNullable(parentElement);
    }

    @Override
    public ElementWaiter getWaiter() {
        return waiter;
    }

    @Override
    public boolean isList() {
        return listIndex != -1;
    }

    @Override
    public int getIndex() {
        return listIndex;
    }

    @Override
    public InternalElement setIndex(int index) {
        if (!isList()) {
            getFinder().setFindStrategy(new ListElementStrategy(this));
        }
        listIndex = index;
        return this;
    }

    @Override
    public Action getClickAction() {
        return actionsStore.clickAction();
    }

    @Override
    public Action getTextAction() {
        return actionsStore.textAction();
    }

    @Override
    public Action getClearAction() {
        return actionsStore.clear();
    }

    @Override
    public Action getFocusAction() {
        return actionsStore.focusAction();
    }

    @Override
    public Action getInputAction(CharSequence... keys) {
        return actionsStore.inputAction(keys);
    }

    public String getTagName() {
        return actionExecutor
            .execute(actionsStore.tagName());
    }

    public String getAttribute(String name) {
        return actionExecutor
            .execute(actionsStore.attribute(name));
    }

    public State jsReady() {
        final String js = "return document.readyState";
        return State.of(StateType.OTHER, () -> "complete".equals(Strings.toString(getBrowser().actions().executeScript(js))), TEAR_DOWN)
            .withName("JS is completed");
    }

    @Override
    public State notExists() {
        getFinder().clearCache();
        return State.of(StateType.EXISTS.not(), () -> !getFinder().findFast().isSuccess(), TEAR_DOWN).withName("Not Exists in DOM")
            .withName("Not Exists Or Not Displayed");
    }

    @Override
    public SetState notDisplayed() {
        return (SetState) SetState.of(StateType.DISPLAYED.not(), notExists(), State.of(StateType.SELENIUM_DISPLAYED.not(), webElement ->
            !webElement.isSuccess() || !webElement.getResult().isDisplayed(), getFinder()).withTearDown(TEAR_DOWN)).withName("Not Exists Or Not Displayed");
    }

    @Override
    public SetState notEnabled() {
        return (SetState) SetState.of(StateType.ENABLED.not(), notExists(), State.of(StateType.SELENIUM_ENABLED.not(), webElement ->
            !webElement.isSuccess() || !webElement.getResult().isEnabled(), getFinder()).withTearDown(TEAR_DOWN)).withName("Not Exists Or Not Enabled");
    }

    @Override
    public SetState exists() {
        getFinder().clearCache();
        if (JS_WAIT) {
            return (SetState) SetState.of(StateType.EXISTS, jsReady(),
                State.of(StateType.SELENIUM_EXISTS, () -> getFinder().findFast().isSuccess(), TEAR_DOWN)).withTearDown(TEAR_DOWN).withName("Exists in DOM");
        } else {
            return (SetState) SetState.of(StateType.EXISTS,
                State.of(StateType.SELENIUM_EXISTS, () -> getFinder().findFast().isSuccess(), TEAR_DOWN)).withTearDown(TEAR_DOWN).withName("Exists in DOM");
        }
    }

    @Override
    public SetState displayed() {
        return (SetState) SetState.of(StateType.DISPLAYED, exists(), State.of(StateType.SELENIUM_DISPLAYED, () -> {
            final WaitResult res = getFinder().find();
            return res.isSuccess() && res.getResult().isDisplayed();
        }, TEAR_DOWN)).withName("Exists And Displayed");
    }


    @Override
    public SetState enabled() {
        return (SetState) SetState.of(StateType.ENABLED, exists(),
            State.of(StateType.SELENIUM_ENABLED, (webElement) -> webElement.isSuccess() && webElement.getResult().isEnabled(), getFinder())
                .withTearDown(TEAR_DOWN)).withName("Exists And Enabled");
    }

    @Override
    public SetState ready() {
        return (SetState) SetState.of(StateType.READY, displayed(), enabled()).withName("Ready to interact");
    }

    @Override
    public SetState clearState() {
        return (SetState) SetState.of(StateType.OTHER, exists(), State.of(StateType.OTHER, () -> {
            final WaitResult res = getFinder().findFast();
            return res.isSuccess() && Strings.isEmpty(getBrowser().actions().getText(res.getResult()));
        }, TEAR_DOWN)).withName("Text of the element became an nonArg");
    }


    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("PumpElement(");
        sb.append("type=").append(getClass().getSimpleName());
        sb.append(", avatarBy=").append(avatarBy);
        if (page == null) {
            sb.append(", browser=").append(browser.getConfig().getType());
        }
        if (parentElement != null) {
            sb.append(", parentElement=").append(parentElement.getClass().getSimpleName()).append(":").append(parentElement.getBy());
        }
        sb.append(", elementName='").append(elementName).append('\'');
        sb.append(", elementDescription='").append(elementDescription).append('\'');
        if (page != null) {
            sb.append(", page=").append(page);
        }
        if (isList()) {
            sb.append(", listIndex=").append(listIndex);
        }
        sb.append(')');
        return sb.toString();
    }

    @Override
    public Map getInfo() {
        final LinkedHashMap result = Maps.newLinkedHashMap();
        result.put("type", getClass().getSimpleName());
        if (isList()) {
            result.put("list index", String.valueOf(getIndex()));
        } else {
            result.put("list element", "no");
        }
        result.put("name", getName());
        result.put("description", getElementDescription());
        result.put("by", getBy().toString());
        if (parentElement != null) {
            result.put("parentElement", Strings.space(parentElement.getName()));
        } else {
            result.put("parentElement", "no");
        }
        if (page != null) {
            result.put("page", Strings.space(page.getName(), page.getUrl()));
        } else {
            result.put("page", "no");
        }
        result.put("browser", getBrowser().getId());
        return result;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy