FluentLenium/FluentLenium

View on GitHub
fluentlenium-core/src/main/java/io/fluentlenium/core/FluentDriver.java

Summary

Maintainability
C
1 day
Test Coverage
package io.fluentlenium.core;

import io.appium.java_client.AppiumDriver;
import io.fluentlenium.configuration.Configuration;
import io.fluentlenium.core.action.KeyboardActions;
import io.fluentlenium.core.action.MouseActions;
import io.fluentlenium.core.action.WindowAction;
import io.fluentlenium.core.alert.Alert;
import io.fluentlenium.core.alert.AlertImpl;
import io.fluentlenium.core.components.ComponentsManager;
import io.fluentlenium.core.css.CssControl;
import io.fluentlenium.core.css.CssControlImpl;
import io.fluentlenium.core.css.CssSupport;
import io.fluentlenium.core.domain.ElementUtils;
import io.fluentlenium.core.domain.FluentList;
import io.fluentlenium.core.domain.FluentWebElement;
import io.fluentlenium.core.events.ComponentsEventsRegistry;
import io.fluentlenium.core.events.EventsRegistry;
import io.fluentlenium.core.inject.ContainerContext;
import io.fluentlenium.core.inject.DefaultContainerInstantiator;
import io.fluentlenium.core.inject.FluentInjector;
import io.fluentlenium.core.performance.DefaultPerformanceTiming;
import io.fluentlenium.core.performance.PerformanceTiming;
import io.fluentlenium.core.script.FluentJavascript;
import io.fluentlenium.core.search.Search;
import io.fluentlenium.core.wait.FluentWait;
import io.fluentlenium.utils.Preconditions;
import io.fluentlenium.utils.UrlUtils;
import io.fluentlenium.utils.chromium.ChromiumApi;
import io.fluentlenium.utils.chromium.ChromiumControl;
import io.fluentlenium.utils.chromium.ChromiumControlImpl;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WrapsElement;
import org.openqa.selenium.support.events.EventFiringWebDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.Date;
import java.util.Set;

/**
 * Wrapper class for a {@link WebDriver} instance which also offers shortcut and convenience methods,
 * as well as methods to work with mouse, keyboard and windows.
 */
@SuppressWarnings("PMD.GodClass")
public class FluentDriver extends AbstractFluentDriverSearchControl { // NOPMD GodClass

    private static final Logger LOGGER =
            LoggerFactory.getLogger(FluentDriver.class);

    private final Configuration configuration;
    private final ComponentsManager componentsManager;
    private final EventsRegistry events;
    private final ComponentsEventsRegistry componentsEventsRegistry;
    private final FluentInjector fluentInjector;
    private final CssControl cssControl; // NOPMD UnusedPrivateField
    private final Search search;
    private final WebDriver driver;
    private final MouseActions mouseActions;
    private final KeyboardActions keyboardActions;
    private final WindowAction windowAction;
    private final FluentDriverScreenshotPersister screenshotPersister;
    private final FluentDriverWrappedCapabilitiesProvider capabilitiesProvider;
    private final FluentDriverHtmlDumper htmlDumper;
    private final FluentDriverWait driverWait;
    private final PerformanceTiming performanceTiming;
    private final ChromiumControl chromiumControl;

    /**
     * Wrap the driver into a Fluent driver.
     *
     * @param driver        underlying selenium driver
     * @param configuration configuration
     * @param adapter       adapter fluent control interface
     */
    public FluentDriver(WebDriver driver, Configuration configuration, FluentControl adapter) {
        super(adapter);
        this.configuration = configuration;
        screenshotPersister = new FluentDriverScreenshotPersister(configuration, driver);
        capabilitiesProvider = new FluentDriverWrappedCapabilitiesProvider();
        htmlDumper = new FluentDriverHtmlDumper(configuration);
        componentsManager = new ComponentsManager(adapter);
        driverWait = new FluentDriverWait(configuration);
        this.driver = driver;
        search = new Search(driver, this, componentsManager, adapter);
        if (driver instanceof EventFiringWebDriver) {
            events = new EventsRegistry(this);
            componentsEventsRegistry = new ComponentsEventsRegistry(events, componentsManager);
        } else {
            events = null;
            componentsEventsRegistry = null;
        }
        mouseActions = new MouseActions(driver);
        keyboardActions = new KeyboardActions(driver);
        fluentInjector = new FluentInjector(adapter, events, componentsManager, new DefaultContainerInstantiator(this));
        cssControl = new CssControlImpl(adapter, adapter);
        windowAction = new WindowAction(adapter, componentsManager.getInstantiator(), driver);
        performanceTiming = new DefaultPerformanceTiming(driver);
        chromiumControl = new ChromiumControlImpl(driver);

        new FluentDriverTimeoutConfigurer(configuration, driver).configureDriver();
    }

    public Configuration getConfiguration() {
        return configuration;
    }

    @Override
    public void takeHtmlDump() {
        takeHtmlDump(new Date().getTime() + ".html");
    }

    @Override
    public void takeHtmlDump(String fileName) {
        htmlDumper.takeHtmlDump(fileName, () -> {
            synchronized (FluentDriver.class) {
                return $("html").first().html();
            }
        });
    }

    @Override
    public boolean canTakeScreenShot() {
        return getDriver() instanceof TakesScreenshot;
    }

    @Override
    public File takeScreenshot() {
        return takeScreenshot(new Date().getTime() + ".png");
    }

    @Override
    public File takeScreenshot(String fileName) {
        if (!canTakeScreenShot()) {
            throw new WebDriverException("Current browser doesn't allow taking screenshot.");
        }
        return screenshotPersister.persistScreenshot(fileName);
    }

    @Override
    public WebDriver getDriver() {
        if (driver instanceof AppiumDriver) {
            LOGGER.warn("You should use getAppiumDriver() method for mobile automation");
        }
        return driver;
    }

    @Override
    public AppiumDriver getAppiumDriver() {
        if (!(driver instanceof AppiumDriver)) {
            throw new WrongDriverException("Use getDriver() method for web automation");
        }
        return (AppiumDriver) driver;
    }

    @Override
    public EventsRegistry events() {
        return Preconditions.checkState(events, "An EventFiringWebDriver instance is required to use events. "
                + "You should set 'eventsEnabled' configuration property to 'true' "
                + "or override newWebDriver() to build an EventFiringWebDriver.");
    }

    @Override
    public MouseActions mouse() {
        return mouseActions;
    }

    @Override
    public KeyboardActions keyboard() {
        return keyboardActions;
    }

    @Override
    public WindowAction window() {
        return windowAction;
    }

    @Override
    public FluentWait await() {
        return driverWait.await(this);
    }

    @Override
    public Set<Cookie> getCookies() {
        return getDriver().manage().getCookies();
    }

    @Override
    public Cookie getCookie(String name) {
        return getDriver().manage().getCookieNamed(name);
    }

    @Override
    public String url() {
        String baseUrl = buildUrl(null);

        String currentUrl = getDriver().getCurrentUrl();
        if (currentUrl != null && baseUrl != null && currentUrl.startsWith(baseUrl)) {
            currentUrl = currentUrl.substring(baseUrl.length());
        }

        return currentUrl;
    }

    private String buildUrl(String url) {
        String currentUrl = getDriver().getCurrentUrl();
        String baseUrl = UrlUtils.sanitizeBaseUrl(getBaseUrl(), currentUrl);

        return UrlUtils.concat(baseUrl, url);
    }

    @Override
    public String pageSource() {
        return getDriver().getPageSource();
    }

    @Override
    public <P extends FluentPage> P goTo(P page) {
        Preconditions.checkArgument(page, "It is required to specify an instance of FluentPage for navigation.");
        page.go();
        return page;
    }

    @Override
    public void goTo(String url) {
        Preconditions.checkArgument(url, "It is required to specify a URL to navigate to.");
        getDriver().get(buildUrl(url));
    }

    @Override
    public void goToInNewTab(String url) {
        Preconditions.checkArgument(url, "It is required to specify a URL to navigate to (in a new tab).");
        String newTab;
        synchronized (getClass()) {
            Set<String> initialTabs = getDriver().getWindowHandles();
            executeScript("window.open('" + buildUrl(url) + "', '_blank');");
            Set<String> tabs = getDriver().getWindowHandles();
            tabs.removeAll(initialTabs);
            newTab = tabs.iterator().next();
        }

        getDriver().switchTo().window(newTab);
    }

    @Override
    public Capabilities capabilities() {
        return capabilitiesProvider.getCapabilities(getDriver());
    }

    @Override
    public FluentJavascript executeScript(String script, Object... args) {
        return new FluentJavascript((JavascriptExecutor) getDriver(), false, script, args);
    }

    @Override
    public FluentJavascript executeAsyncScript(String script, Object... args) {
        return new FluentJavascript((JavascriptExecutor) getDriver(), true, script, args);
    }

    @Override
    public void switchTo(FluentList<? extends FluentWebElement> elements) {
        switchTo(elements.first());
    }

    @Override
    public void switchTo(FluentWebElement element) {
        if (null == element || !"iframe".equals(element.tagName())) {
            getDriver().switchTo().defaultContent();
        } else {
            WebElement target = element.getElement();
            while (target instanceof WrapsElement && target != ElementUtils.getWrappedElement(target)) {
                target = ElementUtils.getWrappedElement(target);
            }
            getDriver().switchTo().frame(target);
        }
    }

    @Override
    public void switchTo() {
        switchTo((FluentWebElement) null);
    }

    @Override
    public void switchToDefault() {
        switchTo((FluentWebElement) null);
    }

    @Override
    public Alert alert() {
        return new AlertImpl(getDriver());
    }

    /**
     * Quit the underlying web driver and release fluent driver resources.
     */
    public void quit() {
        if (getDriver() != null) {
            getDriver().quit();
        }
        releaseFluent();
    }

    /**
     * Release fluent driver resources.
     */
    public void releaseFluent() {
        fluentInjector.release();
        if (componentsEventsRegistry != null) {
            componentsEventsRegistry.close();
        }
    }

    @Override
    protected ComponentsManager getComponentsManager() {
        return componentsManager;
    }

    @Override
    protected Search getSearch() {
        return search;
    }

    @Override
    public ContainerContext inject(Object container) {
        return fluentInjector.inject(container);
    }

    @Override
    public <T> T newInstance(Class<T> cls) {
        return fluentInjector.newInstance(cls);
    }

    @Override
    public ContainerContext injectComponent(Object componentContainer, Object parentContainer, SearchContext searchContext) {
        return fluentInjector.injectComponent(componentContainer, parentContainer, searchContext);
    }

    @Override
    public CssSupport css() {
        return cssControl.css();
    }

    @Override
    public PerformanceTiming performanceTiming() {
        return performanceTiming;
    }

    @Override
    public ChromiumApi getChromiumApi() {
        return chromiumControl.getChromiumApi();
    }
}