// Copyright � 2002-2005 Canoo Engineering AG, Switzerland.
package com.canoo.webtest.steps.verify;
import com.canoo.webtest.engine.StepFailedException;
import com.canoo.webtest.extension.StoreElementAttribute;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.apache.log4j.Logger;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* This step verifies if the specified text (CDATA) is enclosed
* by an HTML element (tag) of the specified type. A name can
* be specified in case that the element in question appears
* multiple times. The text can be specified as a regular expression.
* <p/>
* Example 1:<br/>
* HTML source:
* <pre>
* <title>The page title</title>
* </pre>
* <p/>
* Possible statements:
* <pre>
* <verifyElementText type="title" text="The page title"/>
* <verifyElementText type="title" text=".*page title.*" regex="true"/>
* </pre>
* <p/>
* Example 2:
* HTML source:
* <pre>
* <textarea name="Hugo">
* The very large text area named hugo.
* </textarea>
* </pre>
* <p/>
* Possible statements:
* <pre>
* <verifyElementText type="textarea" name="Hugo" text="The very large text area named hugo."/>
* <verifyElementText type="textarea" name="Hugo" text=".*text area.*" regex="true"/>
* </pre><p/>
*
* @author Unknown
* @author Marc Guillemot
* @author Paul King
* @webtest.step
* category="Core"
* name="verifyElementText"
* alias="verifyelementtext"
* description="This step verifies whether the <key>HTML</key> element specified by <em>htmlId</em> or <em>type</em>
* and optional <em>name</em> encloses <em>text</em> between its opening and closing tags."
*/
public class VerifyElementText extends AbstractVerifyTextStep {
private static final Logger LOG = Logger.getLogger(VerifyElementText.class);
private String fType;
private String fName;
private String fHtmlId;
public void doExecute() {
final HtmlElement elt;
if (StringUtils.isEmpty(getHtmlId())) {
elt = findElementByTypeAndOptionalName();
}
else {
elt = StoreElementAttribute.findElement(getContext().getCurrentResponse(), getHtmlId(), null, LOG, this);
}
if (!verifyText(readText(elt))) {
throw new StepFailedException(getFailedMessage(), getText(), readText(elt), this);
}
}
private HtmlElement findElementByTypeAndOptionalName() {
final List li = ((HtmlPage) getContext().getCurrentResponse()).getDocumentElement().getHtmlElementsByTagName(getType());
LOG.debug(li.size() + " elts found of type \"" + getType() + "\"");
if (li.isEmpty()) {
throw new StepFailedException("No element found of type \"" + getType() + "\"", this);
}
if (li.size() > 1 && getName() == null) {
throw new StepFailedException("More than 1 element with type \"" + getType()
+ "\" found! No name is specified.",
this);
}
final HtmlElement elt;
if (getName() != null) {
final List namedElements = findNodesWithAttribute(li, ELEMENT_ATTRIBUTE_NAME, getName());
if (namedElements.isEmpty()) {
throw new StepFailedException("No element of type \"" + getType() + "\" and name \"" + getName()
+ "\" found!",
this);
}
if (namedElements.size() > 1) {
throw new StepFailedException("More than 1 element of type \"" + getType() + "\" with name \"" + getName()
+ "\" found!",
this);
}
elt = (HtmlElement) namedElements.get(0);
}
else {
elt = (HtmlElement) li.get(0);
}
return elt;
}
/**
* Gets the text representation of the element
* @param elt
* @return the text for the element
*/
protected String readText(final HtmlElement elt) {
LOG.debug("Reading text for " + elt);
return elt.asText();
}
protected static List findNodesWithAttribute(final List li, final String attributeName, final String attributeValue) {
LOG.debug("Looking in list for elements with attribute \"" + attributeName + "\"'s value: \""
+ attributeValue + "\"");
List result = new ArrayList();
for (Iterator iter = li.iterator(); iter.hasNext();) {
final HtmlElement elt = (HtmlElement) iter.next();
final String strValue = elt.getAttribute(attributeName);
if (attributeValue.equals(strValue)) {
result.add(elt);
} else {
LOG.debug("Value: \"" + strValue + "\" => not ok for " + elt);
}
}
LOG.debug(result.size() + " element(s) found");
return result;
}
protected String getFailedMessage() {
StringBuffer sb = new StringBuffer();
sb.append("Wrong contents found in HTML element (type=\"");
sb.append(getType());
sb.append("\", name=\"");
sb.append(getName());
sb.append("\", htmlId=\"");
sb.append(getHtmlId());
sb.append("\")!");
return sb.toString();
}
public String getName() {
return fName;
}
/**
* @webtest.parameter
* required="no"
* description="The name of the element, i.e. the value of the 'name' attribute. Ignored if using 'htmlId'."
*/
public void setName(String newName) {
fName = newName;
}
public String getType() {
return fType;
}
/**
* @webtest.parameter
* required="yes/no"
* description="The HTML element (tag) name. One of 'htmlId' or 'type' must be set."
*/
public void setType(String newType) {
fType = newType;
}
public String getHtmlId() {
return fHtmlId;
}
/**
* @webtest.parameter
* required="yes/no"
* description="The HTML htmlId of the element. One of 'htmlId' or 'type' must be set."
*/
public void setHtmlId(String htmlId) {
this.fHtmlId = htmlId;
}
protected void verifyParameters() {
super.verifyParameters();
paramCheck(StringUtils.isEmpty(getType()) && StringUtils.isEmpty(getHtmlId()),
"One of 'htmlId' or 'type' must be set.");
}
}