com.liferay.faces.test.showcase.TesterBase.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.faces.test.showcase.TesterBase.java

Source

/**
 * Copyright (c) 2000-2018 Liferay, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.liferay.faces.test.showcase;

import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Pattern;

import org.junit.Assert;

import org.openqa.selenium.By;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Select;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.liferay.faces.test.selenium.browser.BrowserDriver;
import com.liferay.faces.test.selenium.browser.FileUploadTesterBase;
import com.liferay.faces.test.selenium.browser.TestUtil;
import com.liferay.faces.test.selenium.browser.WaitingAsserter;
import com.liferay.faces.test.selenium.expectedconditions.WindowOpened;

/**
 * @author  Kyle Stiemann
 * @author  Philip White
 */
public class TesterBase extends FileUploadTesterBase {

    // Logger
    private static final Logger logger = LoggerFactory.getLogger(TesterBase.class);

    // Protected Constants
    protected static final String DEFAULT_COMPONENT_PREFIX = TestUtil
            .getSystemPropertyOrDefault("integration.default.component.prefix", "h");
    protected static final String SHOWCASE_CONTEXT_URL;

    // Common Xpath
    protected static final String error1Xpath = "(//div[contains(@class,'field form-group has-error') or contains(@class,'field control-group error')])[1]";
    protected static final String immediateMessage1Xpath = "//li[contains(text(),'APPLY_REQUEST_VALUES')]";
    protected static final String immediateMessage2Xpath = "//li[contains(text(),'PROCESS_VALIDATIONS')]";
    protected static final String modelValue1Xpath = "(//span[contains(@id,':modelValue')])[1]";
    protected static final String modelValue2Xpath = "(//span[contains(@id,':modelValue')])[2]";
    protected static final String requiredCheckbox1Xpath = "//input[contains(@id,':requiredCheckbox')]";
    protected static final String submitButton1Xpath = "(//*[contains(@value,'Submit')])[1]";
    protected static final String submitButton2Xpath = "(//*[contains(@value,'Submit')])[2]";
    protected static final String valueIsRequiredError1Xpath = "(//div[(contains(@class,'field form-group has-error') or contains(@class,'field control-group error')) and contains(., 'Validation Error: Value is required.')])[1]";

    // Private Constants
    private static final String CONTAINER = TestUtil.getContainer("tomcat");
    private static final String FIRE_SELECT_CHANGE_EVENT_SCRIPT = "var changeEvent = document.createEvent('HTMLEvents');"
            + "changeEvent.initEvent('change', true, true); arguments[0].parentNode.dispatchEvent(changeEvent);";
    private static final boolean SIGN_IN;

    static {

        String defaultShowcaseContext = "/com.liferay.faces.demo.jsf.showcase.webapp/web/guest/showcase/-/component";
        boolean signIn = false;

        if (CONTAINER.contains("liferay")) {
            defaultShowcaseContext = "/web/guest/jsf-showcase/-/jsf-tag";
        } else if (CONTAINER.contains("pluto")) {

            defaultShowcaseContext = TestUtil.DEFAULT_PLUTO_CONTEXT + "/jsf-showcase";
            signIn = true;
        }

        logger.info("defaultShowcaseContext = {}", defaultShowcaseContext);

        String showcaseContext = TestUtil.getSystemPropertyOrDefault("integration.showcase.context",
                defaultShowcaseContext);
        logger.info("showcaseContext = {}", showcaseContext);

        SHOWCASE_CONTEXT_URL = TestUtil.DEFAULT_BASE_URL + showcaseContext;
        SIGN_IN = signIn;
    }

    protected void assertImageRendered(BrowserDriver browserDriver, WaitingAsserter waitingAsserter,
            String imageXpath) {

        waitingAsserter.assertElementDisplayed(imageXpath);

        WebElement image = browserDriver.findElementByXpath(imageXpath);
        String imageSrc = image.getAttribute("src");
        Assert.assertTrue("Image src " + imageSrc + " is not a valid JSF resource URL.",

                // Context-relative path:
                imageSrc.matches(".*/resources/images/[a-z-]+[.]png.*") ||

                // JSF Resource URL:
                        (imageSrc.matches(".*javax.faces.resource\\p{Punct}[a-z-]+[.]png.*")
                                && imageSrc.matches(".*ln\\p{Punct}images.*")));

        Boolean imageRendered = (Boolean) browserDriver.executeScriptInCurrentWindow(
                "return arguments[0].complete && typeof arguments[0].naturalWidth != 'undefined' && arguments[0].naturalWidth > 0",
                image);
        Assert.assertTrue("Image " + imageXpath + " (src=\"" + imageSrc + "\") is not rendered in the DOM.",
                imageRendered);
    }

    protected String capitalize(String string) {

        String capitalizedString = string;

        if (string != null) {

            if (string.length() > 1) {
                capitalizedString = string.substring(0, 1).toUpperCase(Locale.ENGLISH) + string.substring(1);
            } else {
                capitalizedString = string.toUpperCase(Locale.ENGLISH);
            }
        }

        return capitalizedString;
    }

    /**
     * Click an option and wait for Ajax to rerender the option. This method exists because {@link
     * BrowserDriver#clickElementAndWaitForRerender(java.lang.String)} does not work on selectOneMenu,
     * selectManyListbox, and SelectManyMenu. For more information see method comments.
     */
    protected void clickOptionAndWaitForRerender(BrowserDriver browserDriver, String optionXpath) {

        browserDriver.centerElementInCurrentWindow(optionXpath);

        WebElement optionElement = browserDriver.findElementByXpath(optionXpath);

        // Note: clicking a selectOneMenu option on Chrome and PhantomJS via Actions.click(WebElement) (which is used
        // by Browser.clickAndWaitForAjaxRerender(String)) does not fire the select element's change event, so the
        // element must be clicked via Element.click().
        optionElement.click();

        // phantomjs browser does not fire a change event when a <select multiple="multiple"> <option> is clicked,
        // so the event must be fired manually.
        if ("phantomjs".equals(browserDriver.getBrowserName())) {

            try {

                WebElement selectElement = optionElement.findElement(By.xpath(".."));
                Select select = new Select(selectElement);

                if (select.isMultiple()) {
                    browserDriver.executeScriptInCurrentWindow(FIRE_SELECT_CHANGE_EVENT_SCRIPT, optionElement);
                }
            } catch (StaleElementReferenceException e) {
                // do nothing. The element is stale because an ajax rerender has correctly occured.
            }
        }

        browserDriver.waitFor(ExpectedConditions.stalenessOf(optionElement));
        browserDriver.waitForElementEnabled(optionXpath);
    }

    @Override
    protected void doSetUp() {

        if (SIGN_IN) {
            TestUtil.signIn(getBrowserDriver(), CONTAINER);
        }
    }

    protected String getExampleImageXpath(String exampleLabelText) {
        return "//label[contains(.,'Example')][contains(.,'" + exampleLabelText
                + "')]/ancestor::div[@class='showcase-example']//img";
    }

    protected boolean isHeadlessChrome(BrowserDriver browserDriver) {
        return "chrome".equals(browserDriver.getBrowserName()) && browserDriver.isBrowserHeadless();
    }

    protected void navigateToUseCase(BrowserDriver browserDriver, String componentName, String componentUseCase) {
        navigateToUseCase(browserDriver, DEFAULT_COMPONENT_PREFIX, componentName, componentUseCase);
    }

    protected void navigateToUseCase(BrowserDriver browserDriver, String componentPrefix, String componentName,
            String componentUseCase) {

        if (CONTAINER.contains("pluto")) {

            // Since pluto does not support friendly URLs, obtain the "general" use case URL from the showcase accordion
            // and replace "general" with the specified use case. Note: non-"general" use cases are shown conditionally
            // so we cannot rely on those links being present, but the "general" use case links are always present.

            String linkText = componentPrefix + ":" + componentName;

            if (componentPrefix.equals("util")) {
                linkText = componentName;
            }

            String componentLinkXpath = "//a[contains(@href, 'general')][contains(@class,'showcase-link')][normalize-space(text())='"
                    + linkText + "']";
            List<WebElement> componentLinkElements = browserDriver.findElementsByXpath(componentLinkXpath);

            // Initially, navigateToUseCase() may be called when the browser is on the default pluto page, so
            // navigate to the showcase if no component link element is found.
            if (componentLinkElements.isEmpty()) {

                browserDriver.navigateWindowTo(SHOWCASE_CONTEXT_URL);
                waitForShowcasePageReady(browserDriver);
                browserDriver
                        .clickElement("//img[contains(@src,'max.png')]/parent::a[contains(@href,'maximized')]");
                waitForShowcasePageReady(browserDriver);
                componentLinkElements = browserDriver.findElementsByXpath(componentLinkXpath);
            }

            if (componentLinkElements.isEmpty()) {
                throw new Error("Could not obtain pluto use case URL because no link for " + componentPrefix + ":"
                        + componentName + " was found on the page.");
            }

            if (componentLinkElements.size() > 1) {
                throw new IllegalStateException(
                        "Could not obtain pluto use case URL because multiple links matching xpath \""
                                + componentLinkXpath + "\" for " + componentPrefix + ":" + componentName
                                + " were found on the page.\nXpath is ambiguous.");
            }

            String hrefAttribute = componentLinkElements.get(0).getAttribute("href");
            String plutoUseCaseURL = hrefAttribute.replace("general", componentUseCase);
            browserDriver.navigateWindowTo(plutoUseCaseURL);
        } else {
            browserDriver.navigateWindowTo(SHOWCASE_CONTEXT_URL + "/" + componentPrefix + "/"
                    + componentName.toLowerCase(Locale.ENGLISH) + "/" + componentUseCase);
        }

        waitForShowcasePageReady(browserDriver);
    }

    /**
     * Click the link and assert that it opens a new window/tab with the correct domain name.
     */
    protected void testLink(BrowserDriver browserDriver, WaitingAsserter waitingAsserter, String exampleLinkXpath,
            String domainNameRegex) {

        waitingAsserter.assertElementDisplayed(exampleLinkXpath);

        String newTabURL = null;
        String originalWindowHandle = null;
        Set<String> originalWindowIds = browserDriver.getWindowIds();
        int initialNumberOfWindows = originalWindowIds.size();
        WebElement linkElement = browserDriver.findElementByXpath(exampleLinkXpath);
        linkElement.click();
        waitingAsserter.assertTrue(new WindowOpened(initialNumberOfWindows));
        browserDriver.setPageLoadTimeout(5);

        try {

            Set<String> windowIds = new HashSet<String>(browserDriver.getWindowIds());
            originalWindowHandle = browserDriver.getCurrentWindowId();

            // Obtain the URL of the newly opened tab.
            windowIds.removeAll(originalWindowIds);
            browserDriver.switchToWindow(windowIds.iterator().next());
            newTabURL = browserDriver.getCurrentWindowUrl();
        } catch (TimeoutException e) {
            // The browser likely could not connect to the website.
        }

        // Reset to page load timeout to inifinity (the default).
        browserDriver.setPageLoadTimeout(-1);

        // If the url is null or "about:blank", the browser likely could not connect to the website, so fall back
        // to testing the link on the original page.
        if ((newTabURL == null) || "about:blank".equals(newTabURL)) {

            if (originalWindowHandle != null) {

                if (!isHeadlessChrome(browserDriver)) {
                    browserDriver.closeCurrentWindow();
                }

                browserDriver.switchToWindow(originalWindowHandle);
            }

            linkElement = browserDriver.findElementByXpath(exampleLinkXpath);
            newTabURL = linkElement.getAttribute("href");
        }

        Pattern pattern = Pattern.compile(domainNameRegex);
        Assert.assertTrue("The url does not contain text matching the pattern " + domainNameRegex
                + ". The full URL is " + newTabURL + ".", pattern.matcher(newTabURL).find());

        if ((originalWindowHandle != null) && !browserDriver.getCurrentWindowId().equals(originalWindowHandle)) {

            if (!isHeadlessChrome(browserDriver)) {
                browserDriver.closeCurrentWindow();
            }

            browserDriver.switchToWindow(originalWindowHandle);
        }
    }

    /**
     * Test that the web page shows an error message when a value is required and an empty value is submitted.
     */
    protected void testRequiredCheckboxError(BrowserDriver browserDriver, WaitingAsserter waitingAsserter) {

        browserDriver.clickElementAndWaitForRerender(submitButton1Xpath);
        waitingAsserter.assertElementNotDisplayed(valueIsRequiredError1Xpath);
        browserDriver.clickElement(requiredCheckbox1Xpath);
        browserDriver.clickElementAndWaitForRerender(submitButton1Xpath);
        waitingAsserter.assertElementDisplayed(valueIsRequiredError1Xpath);
    }

    protected void waitForShowcasePageReady(BrowserDriver browserDriver) {
        browserDriver.waitFor(ExpectedConditions.jsReturnsValue("return window.liferay_faces_showcase_ready;"));
    }
}