/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.seam.example.common.test.selenium;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.SeleniumException;
import com.thoughtworks.selenium.Wait;
/**
* This class slightly enhaces a Selenium API for controlling a browser.
*
* @author Jozef Hartinger
*
*/
public class SeamSelenium extends DefaultSelenium
{
private String timeout = "30000";
private boolean icefacesDetection = false;
private long icefacesWaitTime = 1000;
private long windowMaximizeWaitTime = 5000L;
private final String ICEFACES_CONNECTION_STATUS = "xpath=//div[@class='iceOutConStat connectionStatus']";
private final String ICEFACES_IDLE_VISIBLE = "xpath=//div[@class='iceOutConStatInactv connectionStatusInactv'][@style='visibility: visible;']";
public SeamSelenium(String serverHost, int serverPort, String browserStartCommand, String browserURL)
{
super(serverHost, serverPort, browserStartCommand, browserURL);
}
/**
* Same as click method but waits for page to load after clicking. Default
* timeout can be changed by setTimeout() method.
*
* @param locator
*/
public void clickAndWait(String locator)
{
click(locator);
waitForPageToLoad();
}
/**
* Simulates a user pressing "back" button and waits for page to load.
* Default timeout can be changed by setTimeout() method.
*/
public void goBackAndWait()
{
super.goBack();
super.waitForPageToLoad(timeout);
}
/**
* Simulates a user pressing "refresh" button and waits for page to load.
* Default timeout can be changed by setTimeout() method.
*/
public void refreshAndWait()
{
super.refresh();
super.waitForPageToLoad(timeout);
}
@Override
public void setTimeout(String timeout)
{
super.setTimeout(timeout);
this.timeout = timeout;
}
public String getTimeout()
{
return timeout;
}
public void waitForPageToLoad()
{
waitForPageToLoad(timeout);
}
@Override
public void waitForPageToLoad(String timeout)
{
if (icefacesDetection && isElementPresent(ICEFACES_CONNECTION_STATUS))
{
waitForIcefaces(icefacesWaitTime, Long.valueOf(timeout));
}
else
{
super.waitForPageToLoad(timeout);
}
}
/**
* Waits until any AJAX worker is registered by underlying framework performs update.
* Uses default (global) timeout
*/
public void waitForAJAXUpdate()
{
waitForAJAXUpdate(timeout);
}
/**
* Waits until any AJAX worker is registered by underlying framework performs update.
*
* @param timeout Timeout in milliseconds
*/
public void waitForAJAXUpdate(String timeout)
{
// there are two frameworks supposed, either jQuery or Prototype
if (icefacesDetection)
{
// Prototype style
waitForCondition("selenium.browserbot.getCurrentWindow().Ajax.activeRequestCount===0", timeout);
}
else
{
// jQuery style
waitForCondition("selenium.browserbot.getCurrentWindow().jQuery.active===0", timeout);
}
}
/**
* Waits until element is asynchronously loaded on page. Uses global Selenium
* timeout
*
* @param locator Locator of element
*/
public void waitForElement(final String locator)
{
waitForElement(locator, Long.valueOf(timeout));
}
/**
* Waits until element is asynchronously loaded on page.
*
* @param timeout Timeout in milliseconds
* @param locator Locator of element
*/
public void waitForElement(final String locator, long timeout)
{
new Wait()
{
@Override
public boolean until()
{
return isElementPresent(locator);
}
}.wait("Timeout while waiting for asynchronous update of " + locator, timeout);
}
/**
* Waits until element is asynchronously unloaded from page.
*
* @param timeout Timeout in milliseconds
* @param locator Locator of element
*/
public void waitForElementNotPresent(final String locator, long timeout)
{
new Wait()
{
@Override
public boolean until()
{
return !isElementPresent(locator);
}
}.wait("Timeout while waiting for asynchronous update of " + locator, timeout);
}
/**
* Selects windows by its id. Waits until windows is refreshed.
*
* @param windowID Identification of window which is selected
*/
@Override
public void selectWindow(String windowID)
{
super.selectWindow(windowID);
refresh();
waitForPageToLoad();
}
/**
* Returns true if icefaces detection is turned on
*/
public boolean isIcefacesDetection()
{
return icefacesDetection;
}
/**
* Switch icefaces detection on/off
*
* @param icefacesDetection
*/
public void setIcefacesDetection(boolean icefacesDetection)
{
this.icefacesDetection = icefacesDetection;
}
/**
* This wait time will be used when waiting for response after invoking
* icefaces action
*/
public long getIcefacesWaitTime()
{
return icefacesWaitTime;
}
/**
* This wait time will be used when waiting for response after invoking
* icefaces action
*
* @param icefacesWaitTime
*/
public void setIcefacesWaitTime(long icefacesWaitTime)
{
this.icefacesWaitTime = icefacesWaitTime;
}
/**
* Captures a screenshot and stores it into a file. Active windows is
* maximized before capturing a screenshot.
*/
@Override
public void captureScreenshot(String path)
{
windowMaximize();
try
{
Thread.sleep(windowMaximizeWaitTime);
}
catch (InterruptedException e)
{
}
super.captureScreenshot(path);
}
/**
* Logs HTML body into a file.
*
* @param path
*/
public void logHTMLContext(String path)
{
String source = getHtmlSource();
BufferedWriter writer = null;
try
{
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path)));
writer.write(source);
writer.flush();
}
catch (Exception e)
{
throw new RuntimeException("Unable to save HTML body", e);
}
finally
{
try
{
writer.close();
}
catch (Exception e)
{
}
}
}
private void waitForIcefaces(Long waitTime, Long timeout)
{
new Wait()
{
@Override
public boolean until()
{
return isElementPresent(ICEFACES_IDLE_VISIBLE);
}
}.wait("Timeout while waiting for icefaces idle state.", timeout);
try
{
Thread.sleep(icefacesWaitTime);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
new Wait()
{
@Override
public boolean until()
{
return isElementPresent("xpath=//body");
}
}.wait("Timeout while waiting for document body after icefaces click.", timeout);
}
@Override
public void open(String url)
{
try
{
super.open(url);
}
catch (SeleniumException e)
{
// since 1.0.3 Selenium throws SeleniumException when a server returns 404
// we suppress this behavior in order to retain backward compatibility
}
}
}