// Copyright � 2002-2005 Canoo Engineering AG, Switzerland.
package com.canoo.webtest.steps.request;
import javax.xml.xpath.XPathException;
import org.apache.log4j.Logger;
import com.canoo.webtest.boundary.HtmlUnitBoundary;
import com.canoo.webtest.engine.StepFailedException;
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
/**
* @author Unknown
* @author Marc Guillemot
* @author Denis N. Antonioli
* @webtest.step
*/
public abstract class AbstractIdOrLabelTarget extends AbstractTargetAction {
private static final Logger LOG = Logger.getLogger(AbstractIdOrLabelTarget.class);
private String fLabel;
private String fHtmlId;
private String fXPath;
/**
* @param newLabel The Label to set.
* @webtest.parameter required="yes/no"
* description="The label of the element to click.
* One of 'label', 'htmlid' or 'xpath' must be set."
*/
public void setLabel(String newLabel) {
fLabel = newLabel;
}
public String getLabel() {
return fLabel;
}
/**
* @param htmlId The HtmlId to set.
* @webtest.parameter required="yes/no"
* description="The htmlId of the element to click.
* One of 'label', 'htmlid' or 'xpath' must be set."
*/
public void setHtmlId(final String htmlId) {
fHtmlId = htmlId;
}
public String getHtmlId() {
return fHtmlId;
}
/**
* @param xpath The xpath to set.
* @webtest.parameter required="yes/no"
* description="The xpath of the element to click.
* One of 'label', 'htmlid' or 'xpath' must be set."
*/
public void setXpath(final String xpath) {
fXPath = xpath;
}
public String getXpath() {
return fXPath;
}
/**
* Finds the element in the page according to the properties set on this step
*
* @param page the page to search in
* @return the clickable element, <code>null</code> if not found
*/
protected HtmlElement findClickableElement(final HtmlPage page) throws XPathException {
if (getHtmlId() != null) {
return findClickableElementById(page);
}
if (getXpath() != null) {
return findClickableElementByXPath(page);
}
return findClickableElementByAttribute(page);
}
protected abstract HtmlElement findClickableElementByAttribute(HtmlPage page);
/**
* Finds the button with the configured id.
*
* @param page the page to search in
* @return the clickable element, <code>null</code> if no button with this id is found
* or if label and name don't match
*/
HtmlElement findClickableElementById(final HtmlPage page) {
LOG.debug("Looking for html element with id: " + getHtmlId());
final HtmlElement elt;
try {
elt = page.getHtmlElementById(getHtmlId());
} catch (final ElementNotFoundException e) {
LOG.info("No html element found with id: " + getHtmlId());
return null;
}
return checkFoundElement(elt);
}
/**
* Finds the button with the configured xpath.
*
* @param page the page to search in
* @return the button, <code>null</code> if no button with this xpath is found
* or if label and name don't match
*/
HtmlElement findClickableElementByXPath(final HtmlPage page) throws XPathException {
LOG.debug("Looking for html element with xpath: " + getXpath());
final Object node = HtmlUnitBoundary.trySelectSingleNodeByXPath(getXpath(), page, this);
LOG.debug("XPath evaluates to: " + node);
if (node == null) {
return null;
}
if (node instanceof HtmlElement) {
return checkFoundElement((HtmlElement) node);
}
throw new StepFailedException("The xpath doesn't select an HTML element but a '" + node.getClass() + "'");
}
/**
* Checks that the element is of the desired html type and has the right name and label (if needed)
*
* @param elt the element to check
* @return the element if ok, <code>null</code> if the elment has the correct type has wrong attribute.
* @throws StepFailedException If the element has a wrong type.
*/
abstract HtmlElement checkFoundElement(HtmlElement elt) throws StepFailedException;
}