001: // Copyright © 2002-2005 Canoo Engineering AG, Switzerland.
002: package com.canoo.webtest.steps.request;
003:
004: import com.canoo.webtest.boundary.HtmlUnitBoundary;
005: import com.canoo.webtest.engine.StepFailedException;
006: import com.gargoylesoftware.htmlunit.ElementNotFoundException;
007: import com.gargoylesoftware.htmlunit.html.ClickableElement;
008: import com.gargoylesoftware.htmlunit.html.HtmlElement;
009: import com.gargoylesoftware.htmlunit.html.HtmlPage;
010: import org.apache.log4j.Logger;
011:
012: /**
013: * @author Unknown
014: * @author Marc Guillemot
015: * @author Denis N. Antonioli
016: * @webtest.step
017: */
018: public abstract class AbstractIdOrLabelTarget extends
019: AbstractTargetAction {
020: private static final Logger LOG = Logger
021: .getLogger(AbstractIdOrLabelTarget.class);
022:
023: private String fLabel;
024: private String fHtmlId;
025: private String fXPath;
026:
027: /**
028: * @param newLabel The Label to set.
029: * @webtest.parameter required="yes/no"
030: * description="The label of the element to click.
031: * One of 'label', 'htmlid' or 'xpath' must be set."
032: */
033: public void setLabel(String newLabel) {
034: fLabel = newLabel;
035: }
036:
037: public String getLabel() {
038: return fLabel;
039: }
040:
041: /**
042: * @param htmlId The HtmlId to set.
043: * @webtest.parameter required="yes/no"
044: * description="The htmlId of the element to click.
045: * One of 'label', 'htmlid' or 'xpath' must be set."
046: */
047: public void setHtmlId(final String htmlId) {
048: fHtmlId = htmlId;
049: }
050:
051: public String getHtmlId() {
052: return fHtmlId;
053: }
054:
055: /**
056: * @param xpath The xpath to set.
057: * @webtest.parameter required="yes/no"
058: * description="The xpath of the element to click.
059: * One of 'label', 'htmlid' or 'xpath' must be set."
060: */
061: public void setXpath(final String xpath) {
062: fXPath = xpath;
063: }
064:
065: public String getXpath() {
066: return fXPath;
067: }
068:
069: /**
070: * Finds the element in the page according to the properties set on this step
071: *
072: * @param page the page to search in
073: * @return the clickable element, <code>null</code> if not found
074: */
075: protected ClickableElement findClickableElement(final HtmlPage page) {
076: if (getHtmlId() != null) {
077: return findClickableElementById(page);
078: }
079: if (getXpath() != null) {
080: return findClickableElementByXPath(page);
081: }
082: return findClickableElementByAttribute(page);
083: }
084:
085: protected abstract ClickableElement findClickableElementByAttribute(
086: HtmlPage page);
087:
088: /**
089: * Finds the button with the configured id.
090: *
091: * @param page the page to search in
092: * @return the clickable element, <code>null</code> if no button with this id is found
093: * or if label and name don't match
094: */
095: ClickableElement findClickableElementById(final HtmlPage page) {
096: LOG.debug("Looking for html element with id: " + getHtmlId());
097: final HtmlElement elt;
098: try {
099: elt = page.getHtmlElementById(getHtmlId());
100: } catch (final ElementNotFoundException e) {
101: LOG.info("No html element found with id: " + getHtmlId());
102: return null;
103: }
104:
105: return checkFoundElement(elt);
106: }
107:
108: /**
109: * Finds the button with the configured xpath.
110: *
111: * @param page the page to search in
112: * @return the button, <code>null</code> if no button with this xpath is found
113: * or if label and name don't match
114: */
115: ClickableElement findClickableElementByXPath(final HtmlPage page) {
116: LOG.debug("Looking for html element with xpath: " + getXpath());
117: final Object node = HtmlUnitBoundary
118: .trySelectSingleNodeByXPath(getXpath(), page, this );
119: LOG.debug("XPath evaluates to: " + node);
120: if (node == null) {
121: return null;
122: }
123: if (node instanceof HtmlElement) {
124: return checkFoundElement((HtmlElement) node);
125: }
126: throw new StepFailedException(
127: "The xpath doesn't select an HTML element but a '"
128: + node.getClass() + "'");
129: }
130:
131: /**
132: * Checks that the element is of the desired html type and has the right name and label (if needed)
133: *
134: * @param elt the element to check
135: * @return the element if ok, <code>null</code> if the elment has the correct type has wrong attribute.
136: * @throws StepFailedException If the element has a wrong type.
137: */
138: abstract ClickableElement checkFoundElement(HtmlElement elt)
139: throws StepFailedException;
140: }
|