| /* 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; |
| } |
| |
| } |