Utilities and common

GDAPComon.java

package testNG;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.Reporter;
import org.testng.annotations.BeforeSuite;

public class GDAPCommon {
    /*
     * Constants & functionality used across multiple application pages
     */
    
    /*
     *  ************ constants *************
     */
    
    public static final int waitLongSeconds = 60;
    public static final int waitNormalSeconds = 10;
    public static final int waitShortSeconds = 2;
    
    /*
     * Used where a job state is needed so we have a single point of update
     */
    public enum JOBSTATES {
        INDRAFT("In Draft"),
        FORREVIEW("For Review"),
        REVIEWED("Reviewed"),
        FINISHED("Finished");
        private String text;
        private JOBSTATES(String text){
            this.text = text;
        }
        public String getText() {
            return text;
        }
    }
    
    /*
     * Entity selections
     */
    public enum ENTITIES {
        ACCESSAUTHORITY        ("Access Authority"),
        ACCESSION            ("Accession"),
        Agency                ("Agency"),
        DISPOSALAUTHORITY    ("Disposal Authority"),
        FUNCTION            ("Function"),
        ITEMGROUP            ("Item group"),
        JURISDICTION        ("Jurisdiction"),
        ORGANISATION        ("Organisation"),
        SERIES                ("Series");
        private String text;
        private ENTITIES(String text){
            this.text = text;
        }
        public String getText() {
            return text;
        }
    }
    
    /*
     * user rights (by role) INCOMPLETE
     */
    public enum ROLES {
        EDITOR("Editor"),
        REVIEWER("Reviewer"),
        MANAGER("Manager");
        private String text;
        private ROLES(String text){
            this.text = text;
        }
        public String getText() {
            return text;
        }
    }
    
    /**
     * ************ Date helpers *****************
     */
    public static String getDateFormatted(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy");
        return sdf.format(date);
    }

    public static String getTimeHHMMSS(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
        return sdf.format(new Date());
    }
    
    public static String appendCurrentDateTime(String target) {
        return target + "_" + getDateFormatted(new Date()) + "_" + getTimeHHMMSS(new Date());
    }
    
    public static String prefixCurrentDateTime(String target) {
        return getDateFormatted(new Date()) + "_" + getTimeHHMMSS(new Date()) + " " + target;
    }
    
    /*
     * ************ TestNG Context *****************
     */

    // Doing as @Beforesuite here as I don't know how else to get the TestNG context needed
    // for getting XML parameters
    private static ITestContext gdapTestNGContext;
    @BeforeSuite(alwaysRun = true)
    public void startTest(ITestContext context) {
        gdapTestNGContext = context;
    }
    
    public static String getTestNGXMLParameter(String parameterName) {
        GDAPCommon.report("getTestNGXMLParameter: '" + parameterName + "'");
        String param = gdapTestNGContext.getCurrentXmlTest().getParameter(parameterName);
        if (param == null) {
            reportAndFail("XML parameter not found: '" + parameterName + "'");
        }
        return param;
    }

    private static int reportStartStackDepth = 0;
    public static void report(String message) {
        /*
         * Log entry short form
         * Queries call stack depth to indent current logging message accordingly
         */
        int currentStackDepth;
        
        //StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        currentStackDepth = Thread.currentThread().getStackTrace().length;
        if (reportStartStackDepth == 0) {
            reportStartStackDepth = currentStackDepth;
        }
        currentStackDepth -= reportStartStackDepth;
        Reporter.log(prefixCurrentDateTime(StringUtils.repeat("&nbsp", currentStackDepth*4)) + message + "<br>");
    }
    
    public static void reportAndFail(String message) {
        /*
         * Log entry & force fail test
         */
        Assert.fail(prefixCurrentDateTime(message) + message);
    }
    
    /*
     * ************* Manage browser ************
     */
    
    public WebDriver startGDAP() {
        /*
         * Start browser & application
         */
        report("startGDAP: Starting Browser");
        String gdapURL = getTestNGXMLParameter("gdap.url");
        WebDriver gdap_Driver = new FirefoxDriver();
        gdap_Driver.manage().timeouts().implicitlyWait(GDAPCommon.waitNormalSeconds, TimeUnit.SECONDS);
        report("startGDAP: Starting GDAP, URL is " + gdapURL);
        gdap_Driver.get(gdapURL);
        return gdap_Driver;
    }
    
    public static void closeGDAP(WebDriver driver) {
        /*
         * Close application tab
         */
        report("closeGDAP: Closing browser");
        driver.close();
    }
    
    public static void browserMaximise(WebDriver driver) {
        driver.manage().window().maximize();
    }
    
    public static void browserMinimise(WebDriver driver) {
        driver.manage().window().maximize();
    }
    
    public static void browserRestorer(WebDriver driver) {
        driver.manage().window().maximize();
    }

    /* ********* Left behind from when was using PageFactory *********** */

    /* ******  WILL DELETE ONCE SURE NO LONGER NEEDED  *********
    
    public WebElement ifElementsValidReturnFirstElement(WebDriver driver, List<WebElement> elements) {
        if (elements.size() > 0)
            return (WebElement) elements.get(0);
        return null;
    }
    
    public List<WebElement> ifElementsValidReturnElements(WebDriver driver, List<WebElement> elements) {
        if (elements.size() > 0)
            return elements;
        return null;
    }
    
    public void assertWebElement(WebDriver driver, WebElement element, String errorMessage) {
        System.out.println("assertWebElement: " + errorMessage);
        if (!doesWebElementExist(driver, element)) {
            report("assertWebElement failed: '" + errorMessage + "'");
            Assert.fail("assertWebElement failed: '" + errorMessage + "'");
        }
    }

    */
    
    /* ******************** Wait for helpers & wrappers *******************/
    
    /* perhaps not needed
    public enum WAITFOR {
        PRESENT,
        NOTPRESENT,
        VISIBLE,
        NOTVISIBLE;
    }
    public static void waitForElement(WebDriver driver, By by, WAITFOR waitFor) {
        switch (waitFor)
        {
        case PRESENT:
            waitForElementPresentBy(driver, by);
            break;
        case NOTPRESENT:
            waitForElementNotPresentBy(driver, by);
            break;
        case VISIBLE:
            waitForElementVisibleBy(driver, by);
            break;
        case NOTVISIBLE:
            waitForElementNotVisibleBy(driver, by);
            break;
        }
    }
    */
    
    /*
     * Simple waits
     * Any timeouts in use will cause test to fail
     */
    
    public static void waitForElementPresentBy(WebDriver driver, By by) {
        WebDriverWait wait = new WebDriverWait(driver, GDAPCommon.waitLongSeconds);
        wait.until(ExpectedConditions.presenceOfElementLocated(by));
    }
    
    public static void waitForElementNotPresentBy(WebDriver driver, By by) {
        WebDriverWait wait = new WebDriverWait(driver, GDAPCommon.waitLongSeconds);
        wait.until(ExpectedConditions.not(ExpectedConditions.presenceOfElementLocated(by)));
    }
    
    public static void waitForElementVisibleBy(WebDriver driver, By by) {
        WebDriverWait wait = new WebDriverWait(driver, GDAPCommon.waitLongSeconds);
        wait.until(ExpectedConditions.visibilityOfElementLocated(by));
    }
    
    public static void waitForElementNotVisibleBy(WebDriver driver, By by) {
        WebDriverWait wait = new WebDriverWait(driver, GDAPCommon.waitLongSeconds);
        wait.until(ExpectedConditions.invisibilityOfElementLocated(by));
    }
    
    public static void waitForElementTextBy(WebDriver driver, By by, String text) {
        WebDriverWait wait = new WebDriverWait(driver, GDAPCommon.waitLongSeconds);
        wait.until(ExpectedConditions.textToBePresentInElement(by, text));
    }
    
    public static void waitForElementNotTextBy(WebDriver driver, By by, String text) {
        WebDriverWait wait = new WebDriverWait(driver, GDAPCommon.waitLongSeconds);
        wait.until(ExpectedConditions.not(ExpectedConditions.textToBePresentInElement(by, text)));
    }
    
    public static void waitForElementDateBy(WebDriver driver, By by, Date date) {
        WebDriverWait wait = new WebDriverWait(driver, GDAPCommon.waitLongSeconds);
        wait.until(ExpectedConditions.textToBePresentInElement(by, getDateFormatted(date)));
    }

    public static void waitForElementByEqualsElementBy(WebDriver driver, By by1, By by2) {
        WebDriverWait wait = new WebDriverWait(driver, GDAPCommon.waitLongSeconds);
        wait.until(elementEqualsElement(by1, by2));
    }
    
    
    private static ExpectedCondition<Boolean> elementEqualsElement(final By by1, final By by2) {
        /*
         * An expectation that that an element selected 2 different ways is the same
         * Example use:
         *   - is element selected by title same as one selected by row number?
         */
        return new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver driver) {
                try {
                    WebElement element1 =  driver.findElement(by1);
                    WebElement element2 =  driver.findElement(by2);
                    if (element1.equals(element2)) {
                            return true;
                    }
                    return false;
                }    catch (NoSuchElementException e) {
                    return null;
                }
            }
        };
    }
    
        
    /* ******************** Query current state of elements *************** */
    
    public static void waitForAjax(WebDriver driver, int timeoutInSeconds)  {
        /*
         * http://hedleyproctor.com/2012/07/effective-selenium-testing/
         * Queries target page ajax connection queue depth
         */
        System.out.println("Checking active ajax calls by calling jquery.active");
        try {
            if (driver instanceof JavascriptExecutor) {
                JavascriptExecutor jsDriver = (JavascriptExecutor)driver;
                for (int i = 0; i< timeoutInSeconds; i++) {
                    Object numberOfAjaxConnections = jsDriver.executeScript("return jQuery.active");
                    // return should be a number
                    if (numberOfAjaxConnections instanceof Long) {
                        Long n = (Long)numberOfAjaxConnections;
                        System.out.println("Number of active jquery ajax calls: " + n);
                        if (n.longValue() == 0L) {
                            break;
                        }
                    }
                    Thread.sleep(1000);
                }
            }
            else {
                System.out.println("Web driver: " + driver + " cannot execute javascript");
                report("ERROR: Web driver: " + driver + " cannot execute javascript");
            }
        }
        catch (InterruptedException e) {
            System.out.println(e);
        }
    }
    
    public static boolean isElementPresentBy(WebDriver driver, By by) {
        /*
         * For conditional test flow
         */
        @SuppressWarnings("unused")
        WebElement element;
        waitForAjax(driver, waitNormalSeconds);
        boolean result = false;
        try {
            element = driver.findElement(by);    // just a nothing operation to force selenium to try to find this element
            result = true;
        } catch (NoSuchElementException e) {
        }
        return result;
    }
    
    public boolean isPresentElementEnabledBy(WebDriver driver, By by) {
        waitForAjax(driver, waitNormalSeconds);
        return (driver.findElement(by)).isEnabled();
    }

    public boolean isPresentElementDisabledBy(WebDriver driver, By by) {
        waitForAjax(driver, waitNormalSeconds);
        return (!driver.findElement(by).isEnabled());
    }

    public boolean isPresentElementVisibleBy(WebDriver driver, By by) {
        waitForAjax(driver, waitNormalSeconds);
        return (driver.findElement(by).isDisplayed());
    }

    public static boolean isPresentElementInvisibleBy(WebDriver driver, By by) {
        waitForAjax(driver, waitNormalSeconds);
        return (!driver.findElement(by).isDisplayed());
    }
    
    public static  String getElementTextBy(WebDriver driver, By by) {
        // See how this goes may need to be by element type
        waitForAjax(driver, waitNormalSeconds);
        return driver.findElement(by).getText();
    }
    
    public static int getElementsCountBy(WebDriver driver, By by) {
        List<WebElement> elements = driver.findElements(by);
        return elements.size();
    }
    
    /* ******************** Rich text specific **************************** */
    /*
     * Richtext tinyMCE fields are all in their own IFrame
     *
     * Note: http://watirmelon.com/tag/javascript/ suggest using JavaScript is better
     * for multi browser compatibility BUT relies on tinyMCE on javascript.. so... is
     * it robust to rely on that?
     *
     * Note: Caution: TinyMCE inserts/removes  '<br data-mce-bogus="1">' so we make allowances for that
     */
    
    private static final By TINYMCETARGETELEMENTINIFRAMEXPATH =     By.xpath("//body/p");
    private static final String TINYMCEBOGUSINDICATOR =             "<br data-mce-bogus=\"1\">";
    
    private static void switchToIFrameBy(WebDriver driver, By by) {
        // Focus on iFrame
        WebElement frame = driver.findElement(by);
        driver.switchTo().frame(frame);
    }
    
    public String tinyMCEFieldGetContent(WebDriver driver, By by) {
        /*
         * Function to get target field content from within parent IFrame
         * Returns Selenium focus back to main DOM afterwards
         *
         * @by = IFrame container By locator
         *

         */
        
        switchToIFrameBy(driver, by);
        // Action
        isPresentElementInvisibleBy(driver, TINYMCETARGETELEMENTINIFRAMEXPATH);    // will this ensure TinyMCE JS completed?
        String content = getElementTextBy(driver, TINYMCETARGETELEMENTINIFRAMEXPATH);
        // Strip out TinyMCE bogus data bit
        content = content.replace("<br data-mce-bogus=\"1\">", "");
        // Switch back to main context
        driver.switchTo().defaultContent() ;
        // Done
        return content;
    }
    
    public void tinyMCEFieldSetContent(WebDriver driver, By by, String text) {
        /*
         * Function to set target field content within parent IFrame
         * Returns Selenium focus back to main DOM afterwards
         *
         * @by = IFrame container By locator
         */
        
        switchToIFrameBy(driver, by);
        // Action
        isPresentElementEnabledBy(driver, TINYMCETARGETELEMENTINIFRAMEXPATH);
        clearAndEnterTextBy(driver, TINYMCETARGETELEMENTINIFRAMEXPATH, text);
        // Switch back to main context
        driver.switchTo().defaultContent();
        // Done
    }
    
    public static void waitForTinyMCEElementTextBy(WebDriver driver, By by, String text) {
        /*
         * @by = IFrame container By locator
         */
        WebDriverWait wait = new WebDriverWait(driver, GDAPCommon.waitLongSeconds);
        wait.until(textToBePresentInTinyMCEElement(by, text));
    }
    
    /**
     * An expectation for checking if the given text is present in the specified
     * TinyMCE Iframe editor content.
     *
     * Strips '<br data-mce-bogus="1">' from found text
     */
    private static ExpectedCondition<Boolean> textToBePresentInTinyMCEElement(
        final By locator, final String text) {
    
        return new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver driver) {
                try {
                    String elementText = driver.findElement(locator).getText();
                    elementText = elementText.replaceAll(TINYMCEBOGUSINDICATOR, "");
                    return elementText.contains(text);
                } catch (NoSuchElementException e) {
                    return null;
                }
            }
        };
    }


    /* ******************** Action utilities **************************** */
    
    // Where actions act on a single element they return the target WebElement
    // 20130122 Can probably no longer return WebElement now that PageFactory not used
    //            but no harm for now
    
    public static WebElement clickHarmlessly(WebDriver driver) {
        return clickBy(driver, PageCommon.byArchwayLogo);
    }

    public static WebElement clickBy(WebDriver driver, By by) {
        WebElement element = driver.findElement(by);
        element.click();
        return element;
    }
    
    public static WebElement clearAndEnterTextBy(WebDriver driver, By by, String text) {
        WebElement element = driver.findElement(by);
        element.clear();
        element.sendKeys(text);
        return element;
    }
}

xx