javax.portlet.tck.driver.TCKSimpleTestDriver.java Source code

Java tutorial

Introduction

Here is the source code for javax.portlet.tck.driver.TCKSimpleTestDriver.java

Source

/*  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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 javax.portlet.tck.driver;

import static org.junit.Assert.*;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.safari.SafariDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriverService;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import javax.portlet.tck.constants.Constants;

/**
 * @author nick
 *
 */
@RunWith(value = Parameterized.class)
public class TCKSimpleTestDriver {

    protected static String loginUrl, host, port, testFile, browser, username, usernameId, password, passwordId,
            testContextBase, module;
    protected static int timeout = 3; // for waiting on page load
    protected static boolean useGeneratedUrl = true, debug = false, dryrun = false, scroll;

    protected static WebDriver driver;
    protected String page, tcName;

    protected List<String> debugLines = new ArrayList<>();

    /**
     * Reads the consolidated list of test cases and provides the list to Junit
     * for parameterized testing.
     * @return  a Collection of test cases to run
     */
    @SuppressWarnings("rawtypes")
    @Parameters(name = "{1}")
    public static Collection getTestList() {
        System.out.println("getTestList");
        testFile = System.getProperty("test.list.file");
        System.out.println("   TestFile=" + testFile);
        module = System.getProperty("test.module");
        System.out.println("   Module       =" + module);
        scroll = Boolean.valueOf(System.getProperty("test.scroll"));
        System.out.println("   Scroll       =" + scroll);

        String ignoreFile = System.getProperty("test.ignore.list.file");
        System.out.println("   Ignore file  =" + ignoreFile);
        boolean doIgnore = new Boolean(System.getProperty("test.ignore"));
        System.out.println("   Ignore TCs   =" + doIgnore);

        boolean filterTCs = (module != null && module.length() > 0);
        boolean excTCs = true; // include or exclude TCs
        String filterStr = module;
        if (filterTCs) {
            excTCs = module.startsWith("!");
            filterStr = module.replaceFirst("^!(.*)$", "$1");
            System.out.println("   Filtering    = " + (excTCs ? "Excluding" : "Including") + " all " + filterStr
                    + " testcases");
        }

        Properties tprops = new Properties();
        try {
            FileInputStream fis = new FileInputStream(testFile);
            tprops.loadFromXML(fis);
        } catch (Exception e) {
            System.out.println("Could not read test cases file. Attempted to read file " + testFile);
            e.printStackTrace();
            return null;
        }

        Properties ignoredTCs = new Properties();
        if (doIgnore) {
            try {
                FileInputStream fis = new FileInputStream(ignoreFile);
                ignoredTCs.loadFromXML(fis);
            } catch (Exception e) {
                System.out.println("Could not read test cases file. Attempted to read file " + ignoreFile);
                e.printStackTrace();
                return null;
            }
        }
        System.out.println("   # ignore TCs =" + ignoredTCs.size());

        // See if performance can be improved by sorting the test cases by
        // the page to be accessed. The map uses the page as key and has a 
        // set of test cases for that page as value. Filter according to 
        // test.module.

        TreeMap<String, Set<String>> pages = new TreeMap<String, Set<String>>();
        Set<Object> tcs = tprops.keySet();

        tcloop: for (Object o : tcs) {
            String tcase = (String) o;
            String tpage = tprops.getProperty(tcase);
            if (filterTCs) {
                boolean c = tcase.contains(filterStr);
                if (excTCs && c)
                    continue; // exclude matches
                if (!excTCs && !c)
                    continue; // exclude non-matches
            }
            // handle ignore list
            if (doIgnore) {
                for (Object itc : ignoredTCs.keySet()) {
                    if (tcase.equalsIgnoreCase((String) itc)) {
                        System.out.println("   Ignoring     :" + tcase);
                        continue tcloop;
                    }
                }
            }
            if (!pages.containsKey(tpage)) {
                pages.put(tpage, new TreeSet<String>());
            }
            pages.get(tpage).add(tcase);
        }

        // now pass TCs, sorted by page, to the driver

        List<String[]> tests = new ArrayList<String[]>();
        for (String tpage : pages.keySet()) {
            for (String tcase : pages.get(tpage)) {
                String[] parms = { tpage, tcase };
                tests.add(parms);
            }
        }

        int numP = pages.size();
        int numTC = tests.size();
        System.out.println("Executing " + numTC + " tests on " + numP + " pages.");

        return tests;
    }

    public TCKSimpleTestDriver(String p, String t) {
        page = p;
        tcName = t;
        StringBuilder sb = new StringBuilder();
        sb.append("http://");
        sb.append(host);
        if (port != null && !port.isEmpty()) {
            sb.append(":");
            sb.append(port);
        }
        sb.append("/");
        sb.append(testContextBase);
        sb.append(page);
        sb.toString();
        System.out.println("Testing: " + tcName);
    }

    /**
     * @throws java.lang.Exception
     */
    @BeforeClass
    public static void setUpBeforeClass() throws Exception {

        loginUrl = System.getProperty("test.server.login.url");
        host = System.getProperty("test.server.host");
        port = System.getProperty("test.server.port");
        username = System.getProperty("test.server.username");
        usernameId = System.getProperty("test.server.username.id");
        password = System.getProperty("test.server.password");
        passwordId = System.getProperty("test.server.password.id");
        browser = System.getProperty("test.browser");
        testContextBase = System.getProperty("test.context.base");
        String str = System.getProperty("test.url.strategy");
        useGeneratedUrl = str.equalsIgnoreCase("generateURLs");
        str = System.getProperty("test.debug");
        debug = str.equalsIgnoreCase("true");
        str = System.getProperty("test.timeout");
        dryrun = new Boolean(System.getProperty("test.dryrun"));
        timeout = ((str != null) && str.matches("\\d+")) ? Integer.parseInt(str) : 3;
        String wd = System.getProperty("test.browser.webDriver");
        String binary = System.getProperty("test.browser.binary");
        boolean browserDefaultHeadless = browser.equalsIgnoreCase("chrome") || browser.equalsIgnoreCase("firefox")
                || browser.equalsIgnoreCase("htmlunit") || browser.equalsIgnoreCase("phantomjs");
        String headlessProperty = System.getProperty("test.browser.headless");
        boolean headless = (((headlessProperty == null) || (headlessProperty.length() == 0))
                && browserDefaultHeadless);

        System.out.println("before class.");
        System.out.println("   Debug        =" + debug);
        System.out.println("   Dryrun       =" + dryrun);
        System.out.println("   Timeout      =" + timeout);
        System.out.println("   Login URL    =" + loginUrl);
        System.out.println("   Host         =" + host);
        System.out.println("   Port         =" + port);
        System.out.println("   Context      =" + testContextBase);
        System.out.println("   Generate URL =" + useGeneratedUrl);
        System.out.println("   Username     =" + username);
        System.out.println("   UsernameId   =" + usernameId);
        System.out.println("   Password     =" + password);
        System.out.println("   PasswordId   =" + passwordId);
        System.out.println("   Browser      =" + browser);
        System.out.println("   Driver       =" + wd);
        System.out.println("   binary       =" + binary);
        System.out.println("   headless     =" + headless);

        if (browser.equalsIgnoreCase("firefox")) {

            System.setProperty("webdriver.gecko.driver", wd);
            FirefoxOptions options = new FirefoxOptions();
            options.setLegacy(true);
            options.setAcceptInsecureCerts(true);

            if ((binary != null) && (binary.length() != 0)) {
                options.setBinary(binary);
            }

            if (headless) {
                options.setHeadless(true);
            }

            driver = new FirefoxDriver(options);

        } else if (browser.equalsIgnoreCase("internetExplorer")) {
            System.setProperty("webdriver.ie.driver", wd);
            driver = new InternetExplorerDriver();
        } else if (browser.equalsIgnoreCase("chrome")) {

            System.setProperty("webdriver.chrome.driver", wd);
            ChromeOptions options = new ChromeOptions();

            if ((binary != null) && (binary.length() > 0)) {
                options.setBinary(binary);
            }

            if (headless) {
                options.addArguments("--headless");
            }

            options.addArguments("--disable-infobars");
            options.setAcceptInsecureCerts(true);

            driver = new ChromeDriver(options);

        } else if (browser.equalsIgnoreCase("phantomjs")) {
            DesiredCapabilities capabilities = DesiredCapabilities.phantomjs();
            capabilities.setJavascriptEnabled(true);
            capabilities.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, binary);
            driver = new PhantomJSDriver(capabilities);
        } else if (browser.equalsIgnoreCase("htmlUnit")) {
            driver = new HtmlUnitDriver(true);
        } else if (browser.equalsIgnoreCase("safari")) {
            driver = new SafariDriver();
        } else {
            throw new Exception("Unsupported browser: " + browser);
        }

        if (!dryrun) {
            login();
        }

    }

    /**
     * @throws java.lang.Exception
     */
    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        if (driver != null) {
            driver.quit();
        }
        System.out.println("   after class.");
    }

    /**
     * @throws java.lang.Exception
     */
    @Before
    public void setUp() throws Exception {
        debugLines.add("   before test.");
    }

    /**
     * @throws java.lang.Exception
     */
    @After
    public void tearDown() throws Exception {
        debugLines.add("   after test.");
        if (debug) {
            for (String line : debugLines) {
                System.out.println(line);
            }
        }
    }

    @Test
    public void test() {
        debugLines.add("   execute test.");

        if (dryrun) {
            return;
        }

        try {

            // This is optimized for many results being present on the same page.
            // First look for the test results or links already being present on the page. 

            List<WebElement> wels = driver.findElements(By.name(tcName));
            debugLines.add("   TC elements already on page: " + !wels.isEmpty() + ", tcname===" + tcName + "===");
            if (wels.isEmpty()) {
                wels = accessPage();
            }

            // process links if present
            wels = processClickable(wels);
            debugLines.add("   After processing clickable, results found: " + !wels.isEmpty());

            // wait for any async JavaScript tests to complete
            processAsync();

            checkResults(wels);

        } catch (Exception e) {

            // Some type of unexpected error occurred, so generate text
            // and mark the TC as failed.

            System.out.println("   Exception occurred: " + e.getMessage());
            for (String line : debugLines) {
                System.out.println(line);
            }

            assertTrue("Test case " + tcName + " failed. " + " Setup link could not be accessed. \nException: "
                    + e.toString(), false);
        }
    }

    /**
     * Tries to access the page for the test case. Looks for the page link
     * and clicks it, waiting for the page to load.
     * 
     * @return  a list of elements for the TC (should only be one)
     */
    protected List<WebElement> accessPage() throws Exception {
        List<WebElement> wels = driver.findElements(By.linkText(page));
        debugLines.add("   Access page, link found: " + !wels.isEmpty() + ", page===" + page + "===");

        if (wels.isEmpty()) {
            // retry through login page
            debugLines.add("   logging in ... ");
            login();
            wels = driver.findElements(By.linkText(page));
            if (wels.isEmpty()) {
                throw new Exception("Page " + page + ": link could not be found.");
            }
        }

        WebElement wel = wels.get(0);
        if (scroll) {
            JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
            javascriptExecutor.executeScript(
                    "window.scrollTo(0, (arguments[0].getBoundingClientRect().top + window.pageYOffset) - (window.innerHeight / 2));",
                    wel);
        }
        wel.click();
        WebDriverWait wdw = new WebDriverWait(driver, timeout);
        wdw.until(ExpectedConditions.visibilityOfElementLocated(By.name(tcName)));
        wels = driver.findElements(By.name(tcName));
        if (wels.isEmpty()) {
            throw new Exception("For test case " + tcName + ": no elements found.");
        }
        return wels;
    }

    /**
     * Called to login to the portal if necessary. 
     */
    protected static void login() {

        driver.get(loginUrl);

        List<WebElement> uels = driver.findElements(By.id(usernameId));
        List<WebElement> pwels = driver.findElements(By.id(passwordId));

        // If there is no login or password fields, don't need to login.
        if (!uels.isEmpty() && !pwels.isEmpty()) {

            System.out.println("   No userid / password fields");
            WebElement userEl = uels.get(0);
            WebElement pwEl = pwels.get(0);

            // perform login
            userEl.clear();
            userEl.sendKeys(username);
            pwEl.clear();
            pwEl.sendKeys(password);
            pwEl.submit();

        }
    }

    /**
     * Analyzes the page based on the test case name and records success or failure.
     */
    protected void checkResults(List<WebElement> tcels) {
        String resultId = tcName + Constants.RESULT_ID;
        String detailId = tcName + Constants.DETAIL_ID;

        debugLines.add("   Checking results, #TC elements: " + tcels.size());

        List<WebElement> rels = driver.findElements(By.id(resultId));
        List<WebElement> dels = driver.findElements(By.id(detailId));

        if (!rels.isEmpty()) {
            String res = rels.get(0).getText();
            String det = "Test case " + tcName + ": ";
            det += dels.isEmpty() ? "No details provided." : dels.get(0).getText();
            boolean ok = res.contains(Constants.SUCCESS);
            debugLines.add("   Test OK: " + ok + ", results: " + res + ", details: " + det);
            assertTrue(det, ok);
        } else {
            debugLines.add("   Results not found");
            assertTrue("Test case " + tcName + " failed. Results could not be found.", false);
        }
    }

    /**
     * Looks for a link or button that can be clicked for the TC and clicks it if found.
     * 
     * First looks for a test case setup link or button and clicks it if found. Then it 
     * looks for a test case execution link and clicks it if found. 
     * 
     * @return  web element list containing the test case results.
     * @throws Exception 
     */
    @SuppressWarnings("unused")
    protected List<WebElement> processClickable(List<WebElement> wels) throws Exception {
        String setupId = tcName + Constants.SETUP_ID;
        String actionId = tcName + Constants.CLICK_ID;
        String resultId = tcName + Constants.RESULT_ID;
        String detailId = tcName + Constants.DETAIL_ID;
        String asyncId = tcName + Constants.ASYNC_ID;
        String notreadyId = tcName + Constants.NOTREADY_ID;
        List<WebElement> tcels = null;

        for (WebElement wel : wels) {
            tcels = wel.findElements(By.id(setupId));
            if (!tcels.isEmpty())
                break;
        }
        debugLines.add("   Setup link found: " + ((tcels != null) && !tcels.isEmpty()));

        // If were dealing with async, make sure the JavaScript is initialized
        List<WebElement> acels = driver.findElements(By.id(asyncId));
        debugLines.add("   Async elements found: " + ((acels != null) && !acels.isEmpty()));
        if (acels != null && !acels.isEmpty()) {
            WebDriverWait wdw = new WebDriverWait(driver, timeout);
            wdw.until(ExpectedConditions.invisibilityOfElementLocated(By.id(notreadyId)));
            debugLines.add("   Async elements are now ready.");
        }

        // Click setup link if found
        if ((tcels != null) && !tcels.isEmpty()) {
            WebElement wel = tcels.get(0);
            if (scroll) {
                JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
                javascriptExecutor.executeScript(
                        "window.scrollTo(0, (arguments[0].getBoundingClientRect().top + window.pageYOffset) - (window.innerHeight / 2));",
                        wel);
            }
            wel.click();
            debugLines.add("   Clicked setup link.");

            WebDriverWait wdw = new WebDriverWait(driver, timeout);

            String expr = "//*[@id='" + resultId + "'] | //*[@id='" + actionId + "']";
            debugLines.add("   xpath string: ===" + expr + "===");

            wdw.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath(expr)));
            wels = driver.findElements(By.name(tcName));

            debugLines.add("   Found elements: " + (!wels.isEmpty()));
            List<WebElement> xels = driver.findElements(By.xpath(expr));
            for (WebElement w : xels) {
                debugLines.add("      Element: " + w.getTagName() + ", id=" + w.getAttribute("id"));
            }
        }

        // Now click the action link, if present
        for (WebElement wel : wels) {
            tcels = wel.findElements(By.id(actionId));
            if (!tcels.isEmpty())
                break;
        }
        debugLines.add("   Clickable link found: " + ((tcels != null) && !tcels.isEmpty()));

        if (tcels != null && !tcels.isEmpty()) {
            WebElement wel = tcels.get(0);
            if (scroll) {
                JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
                javascriptExecutor.executeScript(
                        "window.scrollTo(0, (arguments[0].getBoundingClientRect().top + window.pageYOffset) - (window.innerHeight / 2));",
                        wel);
            }
            wel.click();
            WebDriverWait wdw = new WebDriverWait(driver, timeout);
            wdw.until(ExpectedConditions.visibilityOfElementLocated(By.id(resultId)));
            wels = driver.findElements(By.name(tcName));
            if ((wels == null) || wels.isEmpty()) {
                throw new Exception("Test case " + tcName + " failed. No results after action link click.");
            }
        }

        return wels;
    }

    /**
     * Looks for an async element on the page. The async element will be filed in 
     * with results by the test case JavaScript code, which runs asynchronously.  
     * 
     * If an async element is found, this function waits the timeout period to 
     * let the async test case code update the results.
     * 
     * @return  <code>true</code> if async was handled; <code>false</code> otherwise.
     * @throws Exception 
     */
    protected boolean processAsync() throws Exception {
        String asyncId = tcName + Constants.ASYNC_ID;
        String resultId = tcName + Constants.RESULT_ID;

        List<WebElement> tcels = null;

        tcels = driver.findElements(By.id(asyncId));

        debugLines.add("   Element with async id=" + asyncId + " found: " + !tcels.isEmpty());

        if (tcels.isEmpty()) {
            // no async element
            return false;
        }

        WebDriverWait wdw = new WebDriverWait(driver, timeout);
        wdw.until(ExpectedConditions.visibilityOfElementLocated(By.id(resultId)));

        return true;
    }

}