All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.saucelabs.selenium.client.htmlunit.SeleniumHTMLUnit Maven / Gradle / Ivy

The newest version!
/*
 * Title: SeleniumHTMLUnit
 *
 * Description:
 * This class implements the selenium API (current API as of 20070801) using htmlunit,
 * in order to have a suitable load-test engine to be driven by TestMaker.
 *
 * This component is part of a package allowing TestMaker 5.x
 * (http://www.pushtotest.com) to execute Selenium-IDE
 * (http://wiki.openqa.org/display/SIDE/Home) recorded test scenarios.
 * This extension package will remain accessible from the Open-Source section
 * of the Denali web site: http://www.denali.be
 *
 */
package com.saucelabs.selenium.client.htmlunit;

/*
 * Main author(s): Olivier Dony, Denali
 * with contributions from other members of the Denali team
 * $Id: SeleniumHTMLUnit.java,v 1.9 2008/06/16 09:02:49 ndaniels Exp $
 */

/*
 * Copyright (c) 2007, Denali Consulting SA, Belgium
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Denali Consulting SA nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Denali Consulting SA, Belgium, ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Denali Consulting SA, Belgium BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

import com.gargoylesoftware.htmlunit.AjaxController;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import junit.framework.Assert;
import junit.framework.AssertionFailedError;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebWindow;
import com.gargoylesoftware.htmlunit.html.DomAttr;
import com.gargoylesoftware.htmlunit.html.FrameWindow;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlFileInput;
import com.gargoylesoftware.htmlunit.html.HtmlHiddenInput;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlOption;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlRadioButtonInput;
import com.gargoylesoftware.htmlunit.html.HtmlSelect;
import com.thoughtworks.selenium.Selenium;
import java.util.Date;
import java.util.Map;
import java.util.Stack;

/**
 * An implementation of the Selenium API (current as of 20070801) with HTMLUnit.
 *
 * @author Olivier Dony, Denali s.a.
 * @version $Id: SeleniumHTMLUnit.java,v 1.9 2008/06/16 09:02:49 ndaniels Exp $
 */
public class SeleniumHTMLUnit implements Selenium {

    /** The default timeout for HTTP operations * */
    public static final int DEFAULT_HTTP_TIMEOUT = 60000;
    public static final int DEFAULT_WAIT_TIMEOUT = 60000;

    private static final String CLASS = SeleniumHTMLUnit.class.getName();
    protected WebClient webClient;
    protected static Logger logger = Logger.getLogger(CLASS);
    protected List verificationErrors;
    protected String baseUrl;
    protected boolean debugPageOnFailure;
    protected WebWindow originalWindow;
    private boolean verifyActAsAssert;
    private static boolean printErrorPage=true;
    private Stack history = new  Stack ();

    static {
        logger.setLevel(Level.WARNING);
    }
    private  HtmlPage currentPage;
    private HtmlPage oldPage;

    public static void setLoglevel(Level l){
        logger.setLevel(l);
        if (l == l.OFF){
            printErrorPage = false;
        } else {
            printErrorPage = true;
        }
    }

    public SeleniumHTMLUnit() {
        this(false,false);
    }


    public SeleniumHTMLUnit(boolean throwExceptionOnScriptError,
            boolean throwExceptionOnFailingStatusCode) {

        // defaults to severe as to not slow down the tests by default
        // attempt to disable commons-httpclient logging
        try {
        /*    Logger
                    .getLogger(
                    "org.apache.commons.httpclient.HttpMethodDirector")
                    .setLevel(Level.OFF); // java.util.logging
            org.apache.log4j.Logger.getLogger(
                    "org.apache.commons.httpclient.HttpMethodDirector")
                    .setLevel(org.apache.log4j.Level.OFF); // log4j logging/*/
        } catch (Throwable t) {
                        /*
                         * ignored, we're just trying to turn off useless commons-http
                         * logging
                         */
        }
        initWebClient(throwExceptionOnScriptError, throwExceptionOnFailingStatusCode);

    }

    int delay = 0;
    private  void sleep(){
        if (delay == 0)
            return;
        try {
            Thread.sleep(delay);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    public void initWebClient(boolean throwExceptionOnScriptError,
            boolean throwExceptionOnFailingStatusCode) {
        webClient = new WebClient(BrowserVersion.FIREFOX_2);
        webClient.setAjaxController(new AjaxController(){

        });
        originalWindow = webClient.getCurrentWindow();
        webClient.setThrowExceptionOnScriptError(throwExceptionOnScriptError);
        webClient.setRedirectEnabled(true);
        webClient.setThrowExceptionOnFailingStatusCode(throwExceptionOnFailingStatusCode);
        webClient.setPrintContentOnFailingStatusCode(printErrorPage);
        verificationErrors = new ArrayList();
        verifyActAsAssert = false;

        // Set a default timeout on HTTP connect and read, as by default
        // WebClient waits forever!
        webClient.setTimeout(DEFAULT_HTTP_TIMEOUT);
        try {
            currentPage = (HtmlPage) webClient.getPage(WebClient.URL_ABOUT_BLANK);
        } catch (Exception e){
            e.printStackTrace();
        }

    }


    /**
     * Returns the baseUrl. Important note: please keep in
     * mind that this 'baseUrl' is not combined with relative URLs in the usual
     * sense, but always concatenated. That means that whenever you
     * {@link #open(String)} a relative URL, the resulting URL will always be
     * baseURL+relativeUrl, no matter what.
     *
     * @return the baseUrl.
     */
    public String getBaseUrl() {
        return baseUrl;
    }

    private void setCurrentPage(HtmlPage newPage){

        history.push(currentPage.getWebResponse().getRequestUrl());
        currentPage = newPage;
    }

    /**
     * Sets the baseUrl to use when a URL passed to {@link #open(String)} is not
     * absolute. Important note: please keep in mind that this
     * 'baseUrl' is not combined with relative URLs in the usual sense, but
     * always concatenated. That means that whenever you {@link #open(String)} a
     * URL, the resulting URL will always be baseURL+relativeUrl, no matter
     * what. DO NOT SET A BASEURL UNLESS YOU REALLY MEAN IT.
     *
     * @param baseUrl
     *            the baseUrl to set.
     */
    public void setBaseUrl(String theBaseUrl) {
        if (theBaseUrl.endsWith("/"))
            baseUrl = theBaseUrl.substring(0,theBaseUrl.length()-1);
        else
            baseUrl = theBaseUrl;
    }

    /**
     * Set the {@link Level} for the {@link Logger} used by this
     * SeleniumHTMLUnit.
     *
     * @param level
     *            a String containing the label of the value for a {@link Level}
     *            (e.g. "INFO" or "800" for
     *            {@link Level#INFO}).
     * @see Level
     */
   /* public void setLogLevel(String level) {
        logger.setLevel(Level.parse(level));
    }*/

    /**
     * Return the label ({@link Level#getName()}) for the {@link Logger} used
     * by this SeleniumHTMLUnit.
     *
     * @see Level
     */
    public String getLogLevel() {
        return logger.getLevel().getName();
    }

    public void setLogLevel(String level) {
        logger.setLevel(Level.parse(level));
    }

    /**
     * Returns whether page debugging is enabled when a failure occurs.
     *
     * @return whether page debugging is enabled when a failure occurs.
     */
    public boolean hasDebugPageOnFailure() {
        return debugPageOnFailure;
    }

    /**
     * Sets whether page debugging is enabled when a failure occurs.
     *
     * @param debugPageOnFailure
     *            true if debugging should be enabled.
     */
    public void setDebugPageOnFailure(boolean debugPageOnFailure) {
        this.debugPageOnFailure = debugPageOnFailure;
    }

    /**
     * Returns the current page, resulting from the last action, and on which
     * the next action will be executed. The current page can also be changed
     * indirectly using {@link #selectWindow(String)}.
     *
     * @return the current page, resulting from the last action, and on which
     *         the next action will be executed.
     * @see #selectWindow(String)
     */
    public HtmlPage getPage() {
        return currentPage;
    }

    /**
     * Returns the underlying htmlunit webClient.
     *
     * @return the underlying htmlunit webClient.
     */
    public WebClient getWebClient() {
        return webClient;
    }

    public void assertEval(String script,String pattern){

        assertEquals(pattern,getEval(script));
    }

    /**
     * Opens an URL in the test frame. This accepts both absolute URLs and URLs
     * relative to the {@link #getBaseUrl()}. Important:
     * Relative URLs are not combined with the baseURL, but simply concatenated
     * with it.
     *
     * The "open" command waits for the page to load before proceeding, ie. the
     * "AndWait" suffix is implicit. Note: The URL must be on the
     * same domain as the runner HTML due to security restrictions in the
     * browser (Same Origin Policy). If you need to open an URL on another
     * domain, use the Selenium Server to start a new browser session on that
     * domain.
     *
     * @param location
     *            the URL to open; may be relative or absolute
     */
    public void open(String location) {

        if (!location.startsWith("/")){
            try {
                new URL(location);
            } catch (Exception e){
                location = "/"+location;
            }
        }
        // Note: Selenium has a peculiar notion of relative URLs: the relative
        // URL
        // is appended directly to the base URL, no matter what this
        // relative URL is (even if it starts with a forward slash (/) )
        try {
            URL url = (baseUrl != null) ? new URL(baseUrl + location)
            : new URL(location);
            setCurrentPage((HtmlPage)webClient.getPage(url));
            logger.info("open: opened url = " + location);
        } catch (MalformedURLException e) {
            throw new RuntimeException(
                    "open: URL is malformed, maybe the baseURL is incorrect: ",
                    e);
        } catch (IOException e) {
            throw new RuntimeException("open: failed to open URL: ", e);
        }
        sleep();
    }

    /**
     * Sets the value of an input field, as though you typed it in.
     * 

* Can also be used to set the value of combo boxes, check boxes, etc. In * these cases, value should be the value of the option selected, not the * visible text. *

* * @param locator * an element locator * @param value * the value to type */ public void type(String locator, String value) { List results = getElements(locator); for (Object elemObj : results) { HtmlElement elem = (HtmlElement) elemObj; try { elem.focus(); if(elem instanceof HtmlFileInput)//Hack because type method is not working on upload input ((HtmlFileInput)elem).setValueAttribute(value); else elem.type(value); } catch (IOException e) { throw new RuntimeException("type: failed to type on element "+locator, e); } logger.info("type: "+value+" typed in element " + elem.getNodeName()); } sleep(); } /** * Clicks on a link, button, checkbox or radio button. If the click action * causes a new page to load (like a link usually does), call * waitForPageToLoad. * * @param locator * an element locator */ public void clickAndWait(String locator){ click(locator); } /** * Clicks on a link, button, checkbox or radio button. If the click action * causes a new page to load (like a link usually does), call * waitForPageToLoad. * * @param locator * an element locator */ public void click(String locator) { try { HtmlElement elem = getElement(locator); logger.info("click on " + elem); setCurrentPage( (HtmlPage)(elem).click()); } catch (IOException e) { throw new RuntimeException( "click: failed to perform click on element @ locator " + locator, e); } sleep(); } /** * Returns the title of the current page, or null if there is no title. * * @return the title of the current page, or null if there is no title. */ public String getTitle() { try { return getPage().getTitleText(); } catch (Exception e) { logger .log( Level.WARNING, "getTitle: could not get page title, maybe there was no page title or head section : " + e.getMessage()); return null; } } /** * Verifies that the specified text pattern appears somewhere on the * rendered page shown to the user. * * @param pattern * a pattern to match with the text of * the page * @return true if the pattern matches the text, false otherwise */ public boolean isTextPresent(String pattern) { return Pattern.compile(pattern).matcher(getPage().asText()).find(); } /** * Waits for a new page to load. * *

* You can use this command instead of the "AndWait" suffixes, * "clickAndWait", "selectAndWait", "typeAndWait" etc. (which are only * available in the JS API). *

*

* Selenium constantly keeps track of new pages loading, and sets a * "newPageLoaded" flag when it first notices a page load. Running any other * Selenium command after turns the flag to false. Hence, if you want to * wait for a page to load, you must wait immediately after a Selenium * command that caused a page-load. *

* * @param strTimeout * a timeout in milliseconds, after which this command will * return with an error */ public void waitForPageToLoad(String strTimeout) { // Selenium is asynchronous but HtmlUnit is synchronous, so this cannot // be mapped easily. logger.info("Action ignored: waitForPageToLoad, timeout = " + strTimeout); } /** * Select an option from a drop-down using an option locator. *

* Option locators provide different ways of specifying options of an HTML * Select element (e.g. for selecting a specific option, or for asserting * that the selected option satisfies a specification). There are several * forms of Select Option Locator. *

*
    *
  • label=labelPattern: matches options * based on their labels, i.e. the visible text. (This is the default.) *
      *
    • label=regexp:^[Oo]ther
    • *
    *
  • *
  • value=valuePattern: matches options * based on their values. *
      *
    • value=other
    • *
    *
  • *
  • id=id: matches options based on their * ids. *
      *
    • id=option1
    • *
    *
  • *
  • index=index: matches an option based * on its index (offset from zero). *
      *
    • index=2
    • *
    *
  • *
*

* If no option locator prefix is provided, the default behaviour is to * match on label. *

* * @param selectLocator * an element locator identifying a * drop-down menu * @param optionLocator * an option locator (a label by default) */ public void select(final String selectLocator, final String optionLocator) { setSelectedOption(selectLocator, optionLocator, true); } /** * Add a selection to the set of selected options in a multi-select element * using an option locator. * * @see #select for details of option locators * @param locator * an element locator identifying a * multi-select box * @param optionLocator * an option locator (a label by default) */ public void addSelection(String locator, String optionLocator) { setSelectedOption(locator, optionLocator, true); } /** * Remove a selection from the set of selected options in a multi-select * element using an option locator. * * @see #select for details of option locators * @param locator * an element locator identifying a * multi-select box * @param optionLocator * an option locator (a label by default) */ public void removeSelection(String locator, String optionLocator) { setSelectedOption(locator, optionLocator, false); } /** * Unselects all of the selected options in a multi-select element. * * @param locator * an element locator identifying a * multi-select box */ public void removeAllSelections(String locator) { HtmlSelect select = (HtmlSelect) getElement(locator); List options = select.getOptions(); for (HtmlOption tmp : options) { HtmlPage newPage = (HtmlPage) select.setSelectedAttribute(tmp, false); if (newPage != null) setCurrentPage( newPage); } sleep(); } /** * Gets all option labels (visible text) for selected options in the * specified select or multi-select element. * * @param selectLocator * an element locator identifying a * drop-down menu * @return an array of all selected option labels in the specified select * drop-down */ public String[] getSelectedLabels(String selectLocator) { String[] result = null; List selectedOptions = getSelectedOptions(selectLocator); result = new String[selectedOptions.size()]; int i = 0; for (HtmlOption optionItem : selectedOptions) { result[i++] = optionItem.asText(); } return result; } /** * Gets option label (visible text) for selected option in the specified * select element. * * @param selectLocator * an element locator identifying a * drop-down menu * @return the selected option label in the specified select drop-down */ public String getSelectedLabel(String selectLocator) { String[] result = getSelectedLabels(selectLocator); if (result != null && result.length > 0) { return result[0]; } return null; } /** * Gets all option values (value attributes) for selected options in the * specified select or multi-select element. * * @param selectLocator * an element locator identifying a * drop-down menu * @return an array of all selected option values in the specified select * drop-down */ public String[] getSelectedValues(String selectLocator) { String[] result = null; List selectedOptions = getSelectedOptions(selectLocator); result = new String[selectedOptions.size()]; int i = 0; for (HtmlOption optionItem : selectedOptions) { result[i++] = optionItem.getValueAttribute(); } return result; } /** * Gets option value (value attribute) for selected option in the specified * select element. * * @param selectLocator * an element locator identifying a * drop-down menu * @return the selected option value in the specified select drop-down */ public String getSelectedValue(String selectLocator) { String[] result = getSelectedValues(selectLocator); if (result.length > 0) { return result[0]; } return null; } /** * Gets all option indexes (option number, starting at 0) for selected * options in the specified select or multi-select element. * * @param selectLocator * an element locator identifying a * drop-down menu * @return an array of all selected option indexes in the specified select * drop-down */ public String[] getSelectedIndexes(String selectLocator) { String[] result = null; HtmlSelect select = (HtmlSelect) getElement(selectLocator); List options = select.getOptions(); List list = new ArrayList(); int i = 0; for (HtmlOption option : options) { if (option.isSelected()) { list.add(String.valueOf(i)); } i++; } result = new String[list.size()]; result = list.toArray(result); return result; } /** * Gets option index (option number, starting at 0) for selected option in * the specified select element. * * @param selectLocator * an element locator identifying a * drop-down menu * @return the selected option index in the specified select drop-down */ public String getSelectedIndex(String selectLocator) { String[] result = getSelectedIndexes(selectLocator); if (result.length > 0) { return result[0]; } return "-1"; } /** * Gets all option element IDs for selected options in the specified select * or multi-select element. * * @param selectLocator * an element locator identifying a * drop-down menu * @return an array of all selected option IDs in the specified select * drop-down */ public String[] getSelectedIds(String selectLocator) { String[] result = null; List selectedOptions = getSelectedOptions(selectLocator); result = new String[selectedOptions.size()]; int i = 0; for (HtmlOption optionItem : selectedOptions) { result[i++] = optionItem.getId(); } return result; } /** * Gets option element ID for selected option in the specified select * element. * * @param selectLocator * an element locator identifying a * drop-down menu * @return the selected option ID in the specified select drop-down */ public String getSelectedId(String selectLocator) { String[] result = getSelectedIds(selectLocator); if (result.length > 0) { return result[0]; } return null; } /** * Determines whether some option in a drop-down menu is selected. * * @param selectLocator * an element locator identifying a * drop-down menu * @return true if some option has been selected, false otherwise */ public boolean isSomethingSelected(String selectLocator) { HtmlSelect select = (HtmlSelect) getElement(selectLocator); return select.getSelectedOptions().size() > 0; } /** * Gets all option labels in the specified select drop-down. * * @param selectLocator * an element locator identifying a * drop-down menu * @return an array of all option labels in the specified select drop-down */ public String[] getSelectOptions(String selectLocator) { String[] result = null; HtmlSelect select = (HtmlSelect) getElement(selectLocator); List options = select.getOptions(); result = new String[options.size()]; int i = 0; for (HtmlOption option : options) { result[i++] = option.asText(); } return result; } /** * Check a toggle-button (checkbox/radio) * * @param locator * an element locator */ public void check(String locator) { HtmlCheckBoxInput checkbox = (HtmlCheckBoxInput) getElement(locator); setCurrentPage((HtmlPage)checkbox.setChecked(true)); sleep(); } /** * Uncheck a toggle-button (checkbox/radio) * * @param locator * an element locator */ public void uncheck(String locator) { HtmlCheckBoxInput checkbox = (HtmlCheckBoxInput) getElement(locator); setCurrentPage ( (HtmlPage) checkbox.setChecked(false)); sleep(); } /** * Gets whether a toggle-button (checkbox/radio) is checked. Fails if the * specified element doesn't exist or isn't a toggle-button. * * @param locator * an element locator pointing to a * checkbox or radio button * @return true if the checkbox is checked, false otherwise */ public boolean isChecked(String locator) { HtmlCheckBoxInput checkbox = (HtmlCheckBoxInput) getElement(locator); return checkbox.isChecked(); } /** * Simulates a user pressing the mouse button (without releasing it yet) on * the specified element. * * @param locator * an element locator */ public void mouseDown(String locator) { HtmlElement element = getElement(locator); setCurrentPage ((HtmlPage) element.mouseDown()); sleep(); } public void mouseDownRight(String locator) { HtmlElement element = getElement(locator); setCurrentPage ((HtmlPage) element.mouseDown(false,false,false,1)); sleep(); } /** * Simulates a user moving the mouse pointer away from the specified * element. * * @param locator * an element locator */ public void mouseOut(String locator) { HtmlElement element = getElement(locator); setCurrentPage ((HtmlPage) element.mouseOut()); sleep(); } /** * Simulates a user hovering a mouse over the specified element. * * @param locator * an element locator */ public void mouseOver(String locator) { HtmlElement element = getElement(locator); setCurrentPage ( (HtmlPage) element.mouseOver()); sleep(); } /** * Simulates the event that occurs when the user releases the mouse button * (i.e., stops holding the button down) on the specified element. * * @param locator * an element locator */ public void mouseUp(String locator) { HtmlElement element = getElement(locator); setCurrentPage ((HtmlPage) element.mouseUp()); sleep(); } /** * Wait for an element to appear on the current page * * @param locator * an element locator */ public void waitForElementPresent(String locator) { logger.info("waitForElementPresent "+locator); waitForElementPresent(locator, DEFAULT_WAIT_TIMEOUT); } /** * Wait for an element to appear on the current page * * @param locator * an element locator * @param timeout * the number of millis to wait before timeout * @throws InterruptedException */ private void waitForElementPresent(String locator, long timeout) { int count = 0; for (; count < timeout; count += 500) { if (isElementPresent(locator)) { break; } synchronized (getPage()) { try { getPage().wait(500); } catch (InterruptedException e) { e.printStackTrace(); } } } if (count >= timeout) { System.err.println("Timeout value reached"); } } /** * Runs the specified JavaScript snippet repeatedly until it evaluates to * "true". The snippet may have multiple lines, but only the result of the * last line will be considered. *

* Note that, by default, the snippet will be run in the runner's test * window, not in the window of your application. To get the window of your * application, you can use the JavaScript snippet * selenium.browserbot.getCurrentWindow(), and then run your * JavaScript in there *

* * @param script * the JavaScript snippet to run * @param timeout * a timeout in milliseconds, after which this command will * return with an error */ public void waitForCondition(String script, String timeout) { long theTimeout = Integer.parseInt(timeout); long initialTime = new Date().getTime(); while (true){ if (new Date().getTime()-initialTime > theTimeout) break; Object obj = webClient.getJavaScriptEngine().execute(this.getPage(),script,"title",0); try { Thread.sleep(100); Thread.yield(); } catch (InterruptedException e) { throw new java.lang.RuntimeException ("Thread interrupted",e); } if (obj == null) continue; if (obj instanceof org.mozilla.javascript.Undefined) continue; if (obj instanceof Boolean) if (((Boolean)obj).booleanValue() == false) continue; //not boolean but also not null // Thread.sleep(1000); //Sleep some time after aceptance is done return; } throw new java.lang.RuntimeException ("waitForCondition: Timeout reached"); //logger.warning("waitForCondition: action not implemented"); } /** * Gets the text of an element. This works for any element that contains * text. This command uses either the textContent (Mozilla-like browsers) or * the innerText (IE-like browsers) of the element, which is the rendered * text shown to the user. * * @param locator * an element locator * @return the text of the element */ public String getText(String locator) { HtmlElement elem = getElement(locator); return elem.asText(); } /* * (non-Javadoc) * * @see com.thoughtworks.selenium.Selenium#getHtmlSource() */ public String getHtmlSource() { return getPage().asXml(); } /** * Verifies that the specified element is somewhere on the getPage(). * * @param locator * an element locator * @return true if the element is present, false otherwise */ public boolean isElementPresent(String locator) { try { return getElement(locator) != null; } catch (Exception e) { /* * ignored: this is one case where it is legal to fail to locate an * element */ } return false; } /** * Selects a popup window; once a popup window has been selected, all * commands go to that window. To select the main window again, use null as * the target. *

* Note that there is a big difference between a window's internal * JavaScript "name" property and the "title" of a given window's document * (which is normally what you actually see, as an end user, in the title * bar of the window). The "name" is normally invisible to the end-user; * it's the second parameter "windowName" passed to the JavaScript method * window.open(url, windowName, windowFeatures, replaceFlag) (which selenium * intercepts). *

*

* Selenium has several strategies for finding the window object referred to * by the "windowID" parameter. *

*

* 1.) if windowID is null, (or the string "null") then it is assumed the * user is referring to the original window instantiated by the browser). *

*

* 2.) if the value of the "windowID" parameter is a JavaScript variable * name in the current application window, then it is assumed that this * variable contains the return value from a call to the JavaScript * window.open() method. *

*

* 3.) Otherwise, selenium looks in a hash it maintains that maps string * names to window "names". *

*

* 4.) If that fails, we'll try looping over all of the known * windows to try to find the appropriate "title". Since "title" is not * necessarily unique, this may have unexpected behavior. *

*

* If you're having trouble figuring out what is the name of a window that * you want to manipulate, look at the selenium log messages which identify * the names of windows created via window.open (and therefore intercepted * by selenium). You will see messages like the following for each window as * it is opened: *

*

* debug: window.open call intercepted; window ID (which you can use with selectWindow()) is "myNewWindow" *

*

* In some cases, Selenium will be unable to intercept a call to window.open * (if the call occurs during or before the "onLoad" event, for example). * (This is bug SEL-339.) In those cases, you can force Selenium to notice * the open window's name by using the Selenium openWindow command, using an * empty (blank) url, like this: openWindow("", "myFunnyWindow"). *

* * @param windowID * the JavaScript window ID of the window to select */ public void selectWindow(final String windowID) { // Selenium's "null" windowID designates the original browser window. if (windowID == null || "null".equals(windowID)) { webClient.setCurrentWindow(originalWindow); } else { // throws WebWindowNotFoundException if not found. webClient.setCurrentWindow(webClient .getWebWindowByName(windowID != null ? windowID : "")); } logger.info("selectWindow(" + windowID + "): action done"); } /** * Selects a frame within the current window. (You may invoke this command * multiple times to select nested frames.) To select the parent frame, use * "relative=parent" as a locator; to select the top frame, use * "relative=top". *

* You may also use a DOM expression to identify the frame you want * directly, like this: dom=frames["main"].frames["subframe"] *

* * @param locator * an element locator identifying a * frame or iframe */ public void selectFrame(final String frameID) { WebWindow frame = null; // handle selenium's 'special' frameIDs if (frameID != null) { if (frameID.startsWith("relative=")) { String targetFrame = frameID.substring(9); if ("parent".equals(targetFrame) || "up".equals(targetFrame)) { if (webClient.getCurrentWindow() instanceof FrameWindow) { frame = webClient.getCurrentWindow().getParentWindow(); } else { // ignored, top frame already. logger .info("selectFrame(" + frameID + ") seems to reference current frame, using self."); frame = webClient.getCurrentWindow(); } } else if ("top".equals(targetFrame)) { frame = webClient.getCurrentWindow().getTopWindow(); } } else if (frameID.startsWith("dom=")) { logger .warning("selectFrame() with 'dom=' locator not implemented yet!"); throw new ElementNotFoundException("frame", "locator", frameID); } } if (frame == null) { // No special selenium frame found, locate by id. try { // throws WebWindowNotFoundException if not found. frame = getPage().getFrameByName(frameID != null ? frameID : ""); } catch (ElementNotFoundException e) { // selenium uses frameID="null" for the default frame, so we // attempt to // find a frame without name if (frameID == null || "null".equals(frameID)) { List frames = getPage().getFrames(); for (Iterator iter = frames.iterator(); iter .hasNext();) { FrameWindow frameElem = (FrameWindow) iter.next(); if (frameElem.getName() == null) { frame = frameElem; break; } } } if (frame == null) throw e; // rethrow -- still not found } } webClient.setCurrentWindow(frame); logger.info("selectFrame(" + frameID + "): action done"); } /** * Gets the (whitespace-trimmed) value of an input field (or anything else * with a value parameter). For checkbox/radio elements, the value will be * "on" or "off" depending on whether the element is checked or not. * * @param locator * an element locator * @return the element value, or "on/off" for checkbox/radio elements */ public String getValue(String locator) { HtmlElement elem = getElement(locator); if (elem instanceof HtmlRadioButtonInput) { HtmlRadioButtonInput input = (HtmlRadioButtonInput) elem; return input.isChecked() ? "on" : "off"; } if (elem instanceof HtmlCheckBoxInput) { HtmlCheckBoxInput input = (HtmlCheckBoxInput) elem; return input.isChecked() ? "on" : "off"; } if (elem instanceof HtmlInput) { HtmlInput input = (HtmlInput) elem; return input.getValueAttribute(); } throw new RuntimeException( "Cannot return value for non-input element with locator :" + locator); } public void stop(){ List windows = webClient.getWebWindows(); for (WebWindow window: windows){ try { window.getEnclosedPage().cleanUp(); window.setEnclosedPage(null); } catch (java.lang.Exception e){ //Stop browser threads } } } // **** Util selenium-rc equivalent methods **** // /** Like assertTrue, but fails at the end of the test (during tearDown) */ public void verifyTrue(boolean b) { try { Assert.assertTrue(b); } catch (AssertionFailedError e) { if (verifyActAsAssert) { throw e; } else { logger.warning("Verify failed : " + e.getMessage()); addToVerificationErrors(e); } } } /** Like assertTrue, but fails at the end of the test (during tearDown) */ public void verifyTrue(boolean b, String message) { try { Assert.assertTrue(message, b); } catch (AssertionFailedError e) { if (verifyActAsAssert) { throw e; } else { logger.warning("Verify failed : " + e.getMessage()); addToVerificationErrors(e); } } } /** Like assertFalse, but fails at the end of the test (during tearDown) */ public void verifyFalse(boolean b) { try { Assert.assertFalse(b); } catch (AssertionFailedError e) { if (verifyActAsAssert) { throw e; } else { logger.warning("Verify failed : " + e.getMessage()); addToVerificationErrors(e); } } } /** * Like assertTextPresent, but fails at the end of the test (during * tearDown) */ public void verifyTextPresent(String text) { try { verifyTrue(isTextPresent(text), "Text \"" + text + "\" not found"); } catch (AssertionFailedError e) { if (verifyActAsAssert) { throw e; } else { logger.warning("Verify failed : " + e.getMessage()); addToVerificationErrors(e); } } } /** Check if the text is present in the current page */ public void assertTextPresent(String text) { Assert.assertTrue("Text \"" + text + "\" not found", isTextPresent(text)); logger.info("Text "+text+" found"); } /** Check the title of the current page */ public void assertTitle(String text) { String title = getTitle(); Assert.assertTrue("Title is not correct, expecting a title matching \"" + text + "\" and found \"" + title + "\"", title.matches(text)); } /** Check if the text is NOT present in the current page */ public void assertTextNotPresent(String text) { Assert.assertFalse("Text \"" + text + "\" found", isTextPresent(text)); } public void assertTrue(boolean b) { Assert.assertTrue(b); } public void assertFalse(boolean b) { Assert.assertFalse(b); } public void assertTrue(String msg, boolean b) { Assert.assertTrue(msg, b); } public void assertFalse(String msg, boolean b) { Assert.assertFalse(msg, b); } /** Returns the body text of the current page */ /* * public String getText() { return * webClient.getJavaScriptEngine().execute(page, * "this.page().bodyText()","getText").toString(); } */ /** Like assertEquals, but fails at the end of the test (during tearDown) */ public void verifyEquals(Object s1, Object s2) { try { assertEquals(s1, s2); } catch (AssertionFailedError e) { if (verifyActAsAssert) { throw e; } else { logger.warning("Verify failed : " + e.getMessage()); addToVerificationErrors(e); } } } /** Like assertEquals, but fails at the end of the test (during tearDown) */ public void verifyEquals(boolean s1, boolean s2) { try { assertEquals(new Boolean(s1), new Boolean(s2)); } catch (AssertionFailedError e) { if (verifyActAsAssert) { throw e; } else { logger.warning("Verify failed : " + e.getMessage()); addToVerificationErrors(e); } } } /** Like JUnit's Assert.assertEquals, but knows how to compare string arrays */ public void assertEquals(Object s1, Object s2) { if (s1 instanceof String && s2 instanceof String) { assertEquals((String) s1, (String) s2); } else if (s1 instanceof String && s2 instanceof String[]) { assertEquals((String) s1, (String[]) s2); } else if (s1 instanceof String && s2 instanceof Number) { assertEquals((String) s1, ((Number) s2).toString()); } else { if (s1 instanceof String[] && s2 instanceof String[]) { String[] sa1 = (String[]) s1; String[] sa2 = (String[]) s2; if (sa1.length != sa2.length) { throw new AssertionFailedError("Expected " + sa1 + " but saw " + sa2); } for (int j = 0; j < sa1.length; j++) { Assert.assertEquals(sa1[j], sa2[j]); } } } } /** * Like JUnit's Assert.assertEquals, but handles "regexp:" strings like HTML * Selenese */ public void assertEquals(String s1, String s2) { Assert.assertTrue("Expected \"" + s1 + "\" but saw \"" + s2 + "\" instead", seleniumEquals(s1, s2)); } /** * Like JUnit's Assert.assertEquals, but joins the string array with commas, * and handles "regexp:" strings like HTML Selenese */ public void assertEquals(String s1, String[] s2) { Assert.assertEquals(s1, stringArrayToSimpleString(s2)); } /** * Compares two strings, but handles "regexp:" strings like HTML Selenese * * @param expectedPattern * @param actual * @return true if actual matches the expectedPattern, or false otherwise */ public boolean seleniumEquals(String expectedPattern, String actual) { if (actual.startsWith("regexp:") || actual.startsWith("regex:")) { // swap 'em String tmp = actual; actual = expectedPattern; expectedPattern = tmp; } if (expectedPattern.startsWith("regexp:")) { String expectedRegEx = expectedPattern .replaceFirst("regexp:", ".*") + ".*"; if (!actual.matches(expectedRegEx)) { System.out.println("expected " + actual + " to match regexp " + expectedPattern); return false; } return true; } if (expectedPattern.startsWith("regex:")) { String expectedRegEx = expectedPattern.replaceFirst("regex:", ".*") + ".*"; if (!actual.matches(expectedRegEx)) { System.out.println("expected " + actual + " to match regex " + expectedPattern); return false; } return true; } if (expectedPattern.startsWith("exact:")) { String expectedExact = expectedPattern.replaceFirst("exact:", ""); if (!expectedExact.equals(actual)) { System.out.println("expected " + actual + " to match " + expectedPattern); return false; } return true; } String expectedGlob = expectedPattern.replaceFirst("glob:", ""); expectedGlob = expectedGlob.replaceAll( "([\\]\\[\\\\{\\}$\\(\\)\\|\\^\\+.])", "\\\\$1"); expectedGlob = expectedGlob.replaceAll("\\*", ".*"); expectedGlob = expectedGlob.replaceAll("\\?", "."); if (!Pattern.compile(expectedGlob, Pattern.DOTALL).matcher(actual) .matches()) { if (logger.isLoggable(Level.WARNING)) { logger.warning("seleniumEquals: expected \"" + actual + "\" to match glob \"" + expectedPattern + "\" (had transformed the glob into regexp \"" + expectedGlob + "\")"); } return false; } return true; } /** * Compares two objects, but handles "regexp:" strings like HTML Selenese * * @see #seleniumEquals(String, String) * @return true if actual matches the expectedPattern, or false otherwise */ public boolean seleniumEquals(Object expected, Object actual) { if (expected instanceof String && actual instanceof String) { return seleniumEquals((String) expected, (String) actual); } return expected.equals(actual); } /** Asserts that two string arrays have identical string contents */ public void assertEquals(String[] s1, String[] s2) { String comparisonDumpIfNotEqual = verifyEqualsAndReturnComparisonDumpIfNot( s1, s2); if (comparisonDumpIfNotEqual != null) { throw new AssertionFailedError(comparisonDumpIfNotEqual); } } /** * Asserts that two string arrays have identical string contents (fails at * the end of the test, during tearDown) */ public void verifyEquals(String[] s1, String[] s2) { String comparisonDumpIfNotEqual = verifyEqualsAndReturnComparisonDumpIfNot( s1, s2); if (comparisonDumpIfNotEqual != null) { if (verifyActAsAssert) { throw new AssertionFailedError(comparisonDumpIfNotEqual); } else { logger.warning("Verify failed : " + comparisonDumpIfNotEqual); addToVerificationErrors(new AssertionFailedError( "Verify failed : " + comparisonDumpIfNotEqual)); } } } private String verifyEqualsAndReturnComparisonDumpIfNot(String[] s1, String[] s2) { boolean misMatch = false; if (s1.length != s2.length) { misMatch = true; } for (int j = 0; j < s1.length; j++) { if (!seleniumEquals(s1[j], s2[j])) { misMatch = true; break; } } if (misMatch) { return "Expected " + stringArrayToString(s1) + " but saw " + stringArrayToString(s2); } return null; } private String stringArrayToString(String[] sa) { StringBuffer sb = new StringBuffer("{"); for (int j = 0; j < sa.length; j++) { sb.append(" ").append("\"").append(sa[j]).append("\""); } sb.append(" }"); return sb.toString(); } private String stringArrayToSimpleString(String[] sa) { StringBuffer sb = new StringBuffer(); for (int j = 0; j < sa.length; j++) { sb.append(sa[j]); if (j < sa.length - 1) { sb.append(','); } } return sb.toString(); } /** Like assertNotEquals, but fails at the end of the test (during tearDown) */ public void verifyNotEquals(Object s1, Object s2) { try { assertNotEquals(s1, s2); } catch (AssertionFailedError e) { if (verifyActAsAssert) { throw e; } else { logger.warning("Verify failed : " + s1.toString() + " is equal to " + s2.toString()); addToVerificationErrors(e); } } } /** Like assertNotEquals, but fails at the end of the test (during tearDown) */ public void verifyNotEquals(boolean s1, boolean s2) { try { assertNotEquals(new Boolean(s1), new Boolean(s2)); } catch (AssertionFailedError e) { if (verifyActAsAssert) { throw e; } else { logger.warning("Verify failed : " + e.getMessage()); addToVerificationErrors(e); } } } /** Asserts that two objects are not the same (compares using .equals()) */ public void assertNotEquals(Object obj1, Object obj2) { if (obj1.equals(obj2)) { Assert.fail("did not expect values to be equal (" + obj1.toString() + ")"); } } /** Asserts that two booleans are not the same */ public void assertNotEquals(boolean b1, boolean b2) { assertNotEquals(new Boolean(b1), new Boolean(b2)); } /** Sleeps for the specified number of milliseconds */ public void pause(int millisecs) { try { Thread.sleep(millisecs); } catch (InterruptedException e) {/* ignored */ } } // **** A few helper methods... **** // /** * Returns a list of selected HtmlOption elements in the Select element * located with selectLocator. */ private List getSelectedOptions(String selectLocator) { HtmlSelect select = (HtmlSelect) getElement(selectLocator); if (select == null) throw new RuntimeException("Could not find