selenium_tumblr_test.BasePage.java Source code

Java tutorial

Introduction

Here is the source code for selenium_tumblr_test.BasePage.java

Source

package selenium_tumblr_test;

import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;

import org.junit.Assert;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.LoadableComponent;
import org.openqa.selenium.support.ui.WebDriverWait;
import com.google.common.base.Predicate;

/**
 * --------------------------
 * BasePage.java
 * --------------------------
 * Copyright (c) 2015 John Antony
 * This code is licensed under the terms of the MIT License
 * see https://github.com/jantonypdx/selenium-tumblr-test/blob/master/license.txt
 * 
 * This is a base class for Selenium web pages that both extends LoadableComponent 
 * and handles repetitive functions. This BasePage class has page URL and page title
 * properties that simplify any derived class load() and isLoaded() functions.
 *  
 * Other  variables and functions handle text input and button clicking that
 * need time to dynamically update the page. Alerts pop ups are handled, too.
 * -------------------------- 
 * Original Author: John Antony;
 * Changes:
 * --------
 * 19-Feb-2015 : Version 1 (JJA);
 */
public class BasePage<T extends BasePage<T>> extends LoadableComponent<T> {

    private String pageURL;
    private String pageTitle;
    private int defaultClickTimeout = 15;
    private int defaultPageReloadTimeout = 15;
    private int pollInterval = 2;

    protected WebDriver driver = null;
    protected LoadableComponent<?> parent = null;

    // Overridden LoadableComponent function. Make sure that we're on the 
    // page that we expect to be on.
    @Override
    protected void isLoaded() throws Error {
        try {
            Assert.assertTrue("Not on correct page", getPageTitle().equals(driver.getTitle()));
        } catch (NoSuchElementException ex) {
            throw new AssertionError();
        }
    }

    // Overridden LoadableComponent function. First, tell the parent object
    // to load its page, then load our own page.
    @Override
    protected void load() {
        // if parent present, load it first
        if (parent != null)
            parent.get();

        // then load page URL
        driver.get(getPageURL());
    }

    /*
     * Getter/setter functions
     */

    // pageURL property getter
    public String getPageURL() {
        return pageURL;
    }

    // pageURL property setter   
    public void setPageURL(String pageURL) {
        this.pageURL = pageURL;
    }

    // pageTitle property getter   
    public String getPageTitle() {
        return pageTitle;
    }

    // pageTitle property setter   
    public void setPageTitle(String pageTitle) {
        this.pageTitle = pageTitle;
    }

    // defaultSecondsToWait property getter 
    public int getDefaultClickTimeout() {
        return defaultClickTimeout;
    }

    // defaultSecondsToWait property setter
    public void setDefaultClickTimeout(int defaultSecondsToWait) {
        this.defaultClickTimeout = defaultSecondsToWait;
    }

    // defaultPageReloadTimeout property getter   
    public int getDefaultPageReloadTimeout() {
        return defaultPageReloadTimeout;
    }

    // defaultPageReloadTimeout property setter   
    public void setDefaultPageReloadTimeout(int defaultPageReloadTimeout) {
        this.defaultPageReloadTimeout = defaultPageReloadTimeout;
    }

    /*
     * Text and Button utility functions
     */

    /*
     * Tumblr pages have dynamic elements that disappear after they are clicked.
     * This function clicks the button, then waits for the element to disappear.
     * It also handles any "are you sure?" type alert popup dialogs that appear.
     */
    public void clickThenWaitForElementToDisappear(By elementBy) {
        clickThenWaitForElementToDisappear(elementBy, getDefaultClickTimeout());
    }

    // same as above only timeout seconds can be specifically set
    public void clickThenWaitForElementToDisappear(By elementBy, int seconds) {
        try {
            // find element & click it
            WebElement element = driver.findElement(elementBy);
            element.click();

            // now wait until element is no longer present or timeout
            try {
                (new FluentWait(driver)).withTimeout(seconds, TimeUnit.SECONDS)
                        .pollingEvery(pollInterval, TimeUnit.SECONDS)
                        .until(ExpectedConditions.not(ExpectedConditions.presenceOfElementLocated(elementBy)));
            } catch (NoSuchElementException noSuchElementException) {

            } catch (TimeoutException timeoutException) {

            }

            // handle any alerts if they pop up
        } catch (org.openqa.selenium.UnhandledAlertException unhandledAlertException) {
            try {
                // try to switch to the alert dialog and accept it
                Alert alert = driver.switchTo().alert();
                alert.accept();
            } catch (org.openqa.selenium.NoAlertPresentException noAlertPresentException) {
                // alert may have gone away. if so, then ignore
            }
        }
    }

    /*
     * Tumblr pages have elements that reload after a button is pressed.
     * This function clicks a button, then waits for the page to be reloaded.
     * Reloading is verified by looking for a timestamp value in the page's
     * source code. As soon as it sees a different timestamp, it knows that
     * the page has been reloaded. This function also handles any "are you 
     * sure?" type alert popup dialogs that appear.
     */
    public void clickThenWaitForPageReload(By elementBy) {
        clickThenWaitForPageReload(elementBy, getDefaultPageReloadTimeout());
    }

    // same as above only timeout seconds can be specifically set   
    public void clickThenWaitForPageReload(By elementBy, int seconds) {

        try {

            // first get page source timestamp
            long timeStampValue1 = getPageSourceTimestamp();

            // find element & click it
            WebElement element = driver.findElement(elementBy);
            element.click();

            // now wait until element is no longer present or timeout
            try {
                (new FluentWait(driver)).withTimeout(seconds, TimeUnit.SECONDS)
                        .pollingEvery(pollInterval, TimeUnit.SECONDS)
                        .ignoring(java.util.NoSuchElementException.class).until(new Predicate<WebDriver>() {
                            @Override
                            public boolean apply(WebDriver driver) {
                                long timeStampValue2 = getPageSourceTimestamp();
                                return timeStampValue1 != timeStampValue2;
                            }
                        });
            } catch (TimeoutException timeoutException) {

            }

            // handle any alerts if they pop up
        } catch (org.openqa.selenium.UnhandledAlertException unhandledAlertException) {
            try {
                // try to switch to the alert dialog and accept it
                Alert alert = driver.switchTo().alert();
                alert.accept();
            } catch (org.openqa.selenium.NoAlertPresentException noAlertPresentException) {
                // alert may have gone away. if so, then ignore
            }
        }

    }

    /*
     * Tumblr pages have dynamic elements that appear only after elements are clicked.
     * This function waits until a specific element is visible.
     */
    public void waitForElementToBeVisible(By elementBy) {
        waitForElementToBeVisible(elementBy, getDefaultClickTimeout());
    }

    // same as above only timeout seconds can be specifically set
    public void waitForElementToBeVisible(By elementBy, int seconds) {
        WebElement element = (new WebDriverWait(driver, seconds))
                .until(ExpectedConditions.visibilityOf(driver.findElement(elementBy)));
    }

    /*
     * Tumblr pages have dynamic elements that are clickable only after elements are clicked.
     * This function waits until a specific element is clickable.
     */
    public void waitForElementToBeClickable(By elementBy) {
        waitForElementToBeClickable(elementBy, getDefaultClickTimeout());
    }

    // same as above only timeout seconds can be specifically set   
    public void waitForElementToBeClickable(By elementBy, int seconds) {
        WebElement element = (new WebDriverWait(driver, seconds))
                .until(ExpectedConditions.elementToBeClickable(elementBy));
    }

    /* 
     * function to find "start_timestamp" in web page'ssource code, such as this:
     *   
     *   Thoth polling
     *   Tumblr.Thoth = new Tumblr.Thoth({
     *      start_timestamp: '1234567890',
     *      primary_tumblelog: 'yourblogname',
     *      check_posts: true,
     *      check_inbox: false,
     *      toast_mode: 1,
     *      token: '12a34567890123b45c67d890def12345'            });
    */
    public long getPageSourceTimestamp() {
        // get page source code
        String pageSource = driver.getPageSource();

        // strip out all but the start_timestamp line
        String strippedLines = pageSource.replaceAll("(?m)^((?!start_timestamp).)*", "");
        String strippedLines2 = strippedLines.replaceAll("(?m)^[ \t]*\r?\n", "");

        // tokenize the timestamp line, get the timestamp value as a long, return it
        StringTokenizer st = new StringTokenizer(strippedLines2, ": '',");
        st.nextToken();
        long timeStampValue = Long.parseLong(st.nextToken());
        return timeStampValue;
    }
}