org.eclipse.che.selenium.core.SeleniumWebDriver.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.che.selenium.core.SeleniumWebDriver.java

Source

/*
 * Copyright (c) 2012-2018 Red Hat, Inc.
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   Red Hat, Inc. - initial API and implementation
 */
package org.eclipse.che.selenium.core;

import static java.lang.String.format;
import static org.eclipse.che.selenium.core.constant.TestTimeoutsConstants.APPLICATION_START_TIMEOUT_SEC;
import static org.eclipse.che.selenium.core.constant.TestTimeoutsConstants.LOADER_TIMEOUT_SEC;
import static org.eclipse.che.selenium.core.utils.WaitUtils.sleepQuietly;
import static org.openqa.selenium.support.ui.ExpectedConditions.frameToBeAvailableAndSwitchToIt;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import java.io.Closeable;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.logging.Level;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.UnauthorizedException;
import org.eclipse.che.api.core.rest.HttpJsonRequestFactory;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.selenium.core.constant.TestBrowser;
import org.eclipse.che.selenium.core.utils.DockerUtil;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.HasInputDevices;
import org.openqa.selenium.interactions.Keyboard;
import org.openqa.selenium.interactions.Mouse;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingPreferences;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Wrapper for {@link WebDriver} to have ability to use in Guice container.
 *
 * @author Anatolii Bazko
 */
@Singleton
public class SeleniumWebDriver
        implements Closeable, WebDriver, JavascriptExecutor, TakesScreenshot, HasInputDevices {
    private static final Logger LOG = LoggerFactory.getLogger(SeleniumWebDriver.class);
    private static final int MAX_ATTEMPTS = 5;
    private static final int DELAY_IN_SECONDS = 5;

    private TestBrowser browser;
    private boolean gridMode;
    private String gridNodeContainerId;
    private String webDriverPort;
    private final RemoteWebDriver driver;
    private final HttpJsonRequestFactory httpJsonRequestFactory;
    private final DockerUtil dockerUtil;
    private final String downloadDir;

    @Inject
    public SeleniumWebDriver(@Named("sys.browser") TestBrowser browser,
            @Named("sys.driver.port") String webDriverPort, @Named("sys.grid.mode") boolean gridMode,
            HttpJsonRequestFactory httpJsonRequestFactory, DockerUtil dockerUtil,
            @Named("tests.tmp_dir") String downloadDir) {
        this.browser = browser;
        this.webDriverPort = webDriverPort;
        this.gridMode = gridMode;
        this.httpJsonRequestFactory = httpJsonRequestFactory;
        this.dockerUtil = dockerUtil;
        this.downloadDir = downloadDir;

        try {
            URL webDriverUrl = new URL(format("http://localhost:%s%s", webDriverPort, gridMode ? "/wd/hub" : ""));
            this.driver = createDriver(webDriverUrl);
        } catch (MalformedURLException e) {
            throw new RuntimeException("Error of construction URL to web driver.", e);
        }
    }

    @Override
    public void get(String url) {
        driver.get(url);
    }

    @Override
    public String getCurrentUrl() {
        return driver.getCurrentUrl();
    }

    @Override
    public String getTitle() {
        return driver.getTitle();
    }

    @Override
    public List<WebElement> findElements(By by) {
        return driver.findElements(by);
    }

    @Override
    public WebElement findElement(By by) {
        return driver.findElement(by);
    }

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

    @Override
    public void close() {
        driver.close();
    }

    @Override
    public void quit() {
        driver.quit();
    }

    @Override
    public Set<String> getWindowHandles() {
        return driver.getWindowHandles();
    }

    @Override
    public String getWindowHandle() {
        return driver.getWindowHandle();
    }

    @Override
    public TargetLocator switchTo() {
        return driver.switchTo();
    }

    @Override
    public Navigation navigate() {
        return driver.navigate();
    }

    @Override
    public Options manage() {
        return driver.manage();
    }

    @Override
    public Object executeScript(String script, Object... args) {
        return driver.executeScript(script, args);
    }

    @Override
    public Object executeAsyncScript(String script, Object... args) {
        return driver.executeAsyncScript(script, args);
    }

    @Override
    public <X> X getScreenshotAs(OutputType<X> target) throws WebDriverException {
        return driver.getScreenshotAs(target);
    }

    @Override
    public Keyboard getKeyboard() {
        return driver.getKeyboard();
    }

    @Override
    public Mouse getMouse() {
        return driver.getMouse();
    }

    private RemoteWebDriver createDriver(URL webDriverUrl) {
        for (int i = 1;;) {
            try {
                return doCreateDriver(webDriverUrl);
            } catch (WebDriverException e) {
                if (i++ >= MAX_ATTEMPTS) {
                    throw e;
                }
            }

            sleepQuietly(DELAY_IN_SECONDS);
        }
    }

    /**
     * Read supported version info from official site.
     *
     * @param webDriverOfficialNotes address of official page with Google driver info
     * @return string with supported version range (for example, "36-40"), or null if version info
     *     doesn't found inside the official notes.
     * @throws IOException
     */
    @Nullable
    private String readSupportedVersionInfoForGoogleDriver(URL webDriverOfficialNotes) throws IOException {
        try (Scanner scanner = new Scanner(webDriverOfficialNotes.openStream(), "UTF-8")) {
            while (scanner.hasNextLine()) {
                String versionLine = scanner.findInLine("Supports Chrome v([\\d-]+)");
                if (versionLine != null) {
                    return scanner.match().group(1);
                }

                scanner.nextLine();
            }
        }

        return null;
    }

    private RemoteWebDriver doCreateDriver(URL webDriverUrl) {
        DesiredCapabilities capability;

        switch (browser) {
        case GOOGLE_CHROME:
            LoggingPreferences loggingPreferences = new LoggingPreferences();
            loggingPreferences.enable(LogType.PERFORMANCE, Level.ALL);
            loggingPreferences.enable(LogType.BROWSER, Level.ALL);

            ChromeOptions options = new ChromeOptions();
            options.addArguments("--no-sandbox");
            options.addArguments("--dns-prefetch-disable");
            options.addArguments("--ignore-certificate-errors");

            // set parameters required for automatic download capability
            Map<String, Object> chromePrefs = new HashMap<>();
            chromePrefs.put("download.default_directory", downloadDir);
            chromePrefs.put("download.prompt_for_download", false);
            chromePrefs.put("download.directory_upgrade", true);
            chromePrefs.put("safebrowsing.enabled", true);
            chromePrefs.put("profile.default_content_settings.popups", 0);
            chromePrefs.put("plugins.plugins_disabled", "['Chrome PDF Viewer']");
            options.setExperimentalOption("prefs", chromePrefs);

            capability = DesiredCapabilities.chrome();
            capability.setCapability(ChromeOptions.CAPABILITY, options);
            capability.setCapability(CapabilityType.LOGGING_PREFS, loggingPreferences);
            capability.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
            break;

        default:
            capability = DesiredCapabilities.firefox();
            capability.setCapability("dom.max_script_run_time", 240);
            capability.setCapability("dom.max_chrome_script_run_time", 240);
        }

        RemoteWebDriver driver = new RemoteWebDriver(webDriverUrl, capability);
        if (driver.getErrorHandler().isIncludeServerErrors()
                && driver.getCapabilities().getCapability("message") != null) {
            String errorMessage = format("Web driver creation error occurred: %s",
                    driver.getCapabilities().getCapability("message"));
            LOG.error(errorMessage);
            throw new RuntimeException(errorMessage);
        }

        driver.manage().window().setSize(new Dimension(1920, 1080));

        return driver;
    }

    /** wait while in a browser appears more the 1 window */
    public void waitOpenedSomeWin() {
        new WebDriverWait(this, 30).until((ExpectedCondition<Boolean>) input -> {
            Set<String> driverWindows = getWindowHandles();
            return (driverWindows.size() > 1);
        });
    }

    /**
     * calculate name of workspace from browser url cut symbols from end of slash symbol ("/") to end
     */
    public String getWorkspaceNameFromBrowserUrl() {
        String currentUrl = getCurrentUrl();
        return currentUrl.substring(currentUrl.lastIndexOf("/") + 1, currentUrl.length());
    }

    /**
     * switch to the next browser window (this means that if opened 2 windows, and we are in the
     * window 1, we will be switched into the window 2 )
     *
     * @param currentWindowHandler
     */
    public void switchToNoneCurrentWindow(String currentWindowHandler) {
        waitOpenedSomeWin();
        for (String handle : getWindowHandles()) {
            if (!currentWindowHandler.equals(handle)) {
                switchTo().window(handle);
                break;
            }
        }
    }

    public void switchFromDashboardIframeToIde() {
        switchFromDashboardIframeToIde(APPLICATION_START_TIMEOUT_SEC);
    }

    public void switchFromDashboardIframeToIde(int timeout) {
        wait(timeout).until(visibilityOfElementLocated(By.id("ide-application-iframe")));

        wait(LOADER_TIMEOUT_SEC).until((ExpectedCondition<Boolean>) driver -> (((JavascriptExecutor) driver)
                .executeScript("return angular.element('body').scope().showIDE")).toString().equals("true"));

        wait(timeout).until(frameToBeAvailableAndSwitchToIt(By.id("ide-application-iframe")));
    }

    private WebDriverWait wait(int timeOutInSeconds) {
        return new WebDriverWait(this, timeOutInSeconds);
    }

    public String getGridNodeContainerId() throws IOException {
        if (!gridMode) {
            throw new UnsupportedOperationException("We can't get grid node container id in local mode.");
        }

        if (gridNodeContainerId == null) {
            String getGridNodeInfoUrl = format("http://localhost:%s/grid/api/testsession?session=%s", webDriverPort,
                    driver.getSessionId());

            Map<String, String> gridNodeInfo;
            try {
                gridNodeInfo = httpJsonRequestFactory.fromUrl(getGridNodeInfoUrl).request().asProperties();
            } catch (ServerException | UnauthorizedException | ForbiddenException | NotFoundException
                    | ConflictException | BadRequestException e) {
                throw new IOException(e);
            }

            if (!gridNodeInfo.containsKey("proxyId")) {
                throw new IOException("Proxy ID of grid node wasn't found.");
            }

            URL proxyId = new URL(gridNodeInfo.get("proxyId"));
            gridNodeContainerId = dockerUtil.findGridNodeContainerByIp(proxyId.getHost());
        }

        return gridNodeContainerId;
    }
}