Java tutorial
/* 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.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.apache.portals.pluto.test.utilities.SimpleTestDriver; import org.junit.After; import org.junit.Before; 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.StaleElementReferenceException; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import javax.portlet.tck.constants.Constants; import org.junit.Assume; /** * @author nick * */ @RunWith(value = Parameterized.class) public class TCKTestDriver extends SimpleTestDriver { protected static final Set<String> IGNORED_TC_NAMES; protected String page, tcName; protected List<String> debugLines = new ArrayList<>(); static { String ignoreFile = System.getProperty("test.ignore.list.file"); System.out.println(" Ignore file =" + ignoreFile); boolean doIgnore = Boolean.parseBoolean(System.getProperty("test.ignore")); System.out.println(" Ignore TCs =" + doIgnore); Properties ignoredTCs = new Properties(); if (doIgnore) { try { FileInputStream fis = new FileInputStream(ignoreFile); ignoredTCs.loadFromXML(fis); } catch (IOException e) { throw new RuntimeException("Could not read test cases file. Attempted to read file " + ignoreFile, e); } } System.out.println(" # ignore TCs =" + ignoredTCs.size()); IGNORED_TC_NAMES = Collections.unmodifiableSet(ignoredTCs.stringPropertyNames()); } /** * 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); 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 (IOException e) { throw new RuntimeException("Could not read test cases file. Attempted to read file " + testFile, e); } // 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 } 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 TCKTestDriver(String p, String t) { page = p; tcName = t; System.out.println("Testing: " + tcName); } /** * @throws java.lang.Exception */ @Before public void setUp() throws Exception { Assume.assumeFalse(" Ignoring :" + tcName, IGNORED_TC_NAMES.contains(tcName)); 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(); } 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); } throw new AssertionError("Test case " + tcName + " failed. " + "\nException: ", e); } } /** * 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("accessPage: debugLines: 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); } click(wel); 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; } protected void click(WebElement wel) { wel.click(); } /** * Analyzes the page based on the test case name and records success or failure. */ protected void checkResults() { String resultId = tcName + Constants.RESULT_ID; String detailId = tcName + Constants.DETAIL_ID; List<WebElement> rels = driver.findElements(By.id(resultId)); List<WebElement> dels = driver.findElements(By.id(detailId)); if (!rels.isEmpty()) { String res = ""; try { res = rels.get(0).getText(); } catch (StaleElementReferenceException e) { System.out.println( e.getClass().getName() + " caught when trying to use WebElements found with " + resultId); rels = driver.findElements(By.id(resultId)); res = rels.get(0).getText(); } String det = "Test case " + tcName + ": "; try { det += dels.isEmpty() ? "No details provided." : dels.get(0).getText(); } catch (StaleElementReferenceException e) { System.out.println( e.getClass().getName() + " caught when trying to use WebElements found with " + detailId); dels = driver.findElements(By.id(detailId)); 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); } try { wel.click(); } catch (StaleElementReferenceException e) { System.out.println("setup link: " + e.getClass().getName() + " caught when trying to use WebElements found with " + tcName); wels = driver.findElements(By.name(tcName)); for (WebElement welly : wels) { tcels = welly.findElements(By.id(setupId)); if (!tcels.isEmpty()) break; } wel = tcels.get(0); 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); } try { wel.click(); } catch (StaleElementReferenceException e) { System.out.println("action link: " + e.getClass().getName() + " caught when trying to use WebElements found with " + tcName); wels = driver.findElements(By.name(tcName)); for (WebElement welly : wels) { tcels = welly.findElements(By.id(actionId)); if (!tcels.isEmpty()) break; } wel = tcels.get(0); 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; } }