// Copyright � 2002-2007 Canoo Engineering AG, Switzerland.
package com.canoo.webtest.util;
import com.canoo.webtest.engine.Context;
import com.canoo.webtest.steps.Step;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.apache.log4j.Logger;
import java.util.Iterator;
import java.util.List;
/**
* Utilities for working with forms.
*
* @author Paul King
*/
public class FormUtil
{
private static final Logger LOG = Logger.getLogger(FormUtil.class);
/**
* Tests if the form contains the desired field.
*/
private static boolean hasField(final HtmlForm form, final String tag, final String type, final String name) {
List elements = form.getHtmlElementsByTagName(tag);
for (Iterator iter = elements.iterator(); iter.hasNext();) {
HtmlElement element = (HtmlElement) iter.next();
if (name.equals(element.getAttribute(HtmlConstants.NAME))
&& (type == null || type.equalsIgnoreCase(element.getAttribute(HtmlConstants.TYPE)))) {
return true;
}
}
return false;
}
/**
* Indicates if the form has a "text field" (text, password or textarea) with the given name.
*/
public static boolean hasTextField(final HtmlForm form, final String name) {
if (hasTextAreaField(form, name)) {
return true;
}
return hasTextOrPasswordField(form, name);
}
private static boolean hasTextOrPasswordField(final HtmlForm form, final String name) {
final List li = form.getInputsByName(name);
for (final Iterator iter = li.iterator(); iter.hasNext();) {
final HtmlInput element = (HtmlInput) iter.next();
if (HtmlConstants.TEXT.equalsIgnoreCase(element.getTypeAttribute())
|| HtmlConstants.PASSWORD.equalsIgnoreCase(element.getTypeAttribute())) {
return true;
}
}
return false;
}
private static boolean hasTextAreaField(final HtmlForm form, final String name) {
return !form.getTextAreasByName(name).isEmpty();
}
/**
* Gets the form from the current response containing the desired field. If there is a current form then this form is
* considered, else the first form containing such a field (this form is then set as the current form for further
* calls).<br/> Note: the test is currently only performed on the name of the field.
*
* @param context
* @param givenFormName
* @param tag the html tag corresponding to the field
* @param type the type of the input field (html attribute "type") if tag is "input"
* @param name the name of the input field (html attribute "name")
* @param step
* @return <code>null</code> if no form found.
*/
public static HtmlForm findFormForField(Context context, String givenFormName, final String tag, final String type, final String name, Step step) {
LOG.debug("Looking for form with " + tag + " field " + type + " named \"" + name + "\"");
HtmlForm form = null;
if (givenFormName != null) {
HtmlForm givenForm = findFormByName(context.getCurrentHtmlResponse(step), givenFormName);
form = checkFormIsSuitable(givenForm, tag, type, name);
}
if (form != null) {
return form;
}
LOG.debug("No given form or given form not suitable, trying others");
form = checkFormIsSuitable(context.getCurrentForm(), tag, type, name);
if (form != null) {
return form;
}
LOG.debug("No current form or current form not suitable, trying others");
return searchAllFormsForSuitableOne(context, tag, type, name, step);
}
private static HtmlForm checkFormIsSuitable(final HtmlForm candidateForm, final String tag, final String type, final String name) {
if (candidateForm != null && hasField(candidateForm, tag, type, name)) {
LOG.debug("Form '" + candidateForm.getNameAttribute() + "' has suitable field, using it");
return candidateForm;
}
return null;
}
private static HtmlForm searchAllFormsForSuitableOne(final Context context, final String tag, final String type, final String name, Step step) {
for (final Iterator iter = context.getCurrentHtmlResponse(step).getForms().iterator(); iter.hasNext();) {
final HtmlForm curForm = (HtmlForm) iter.next();
if (hasField(curForm, tag, type, name)) {
context.setCurrentForm(curForm);
return curForm;
}
}
return null;
}
/**
* Gets the form from the current response containing the desired text field. If there is a current form then this form
* is considered, else the first form containing such a field (this form is then set a the current form for further
* calls).
*
* @param context
* @param givenFormName
* @param name the name of the text field of interest (<input type="text"...> or
* <input type="password" ...> or <textarea ...>...</textarea>)
* @param step
* @return <code>null</code> if no form found.
*/
public static HtmlForm findFormForTextField(Context context, String givenFormName, final String name, Step step) {
LOG.debug("Looking for form with text field named \"" + name + "\"");
HtmlForm form = null;
if (givenFormName != null) {
HtmlForm givenForm = findFormByName(context.getCurrentHtmlResponse(step), givenFormName);
form = checkFormIsSuitable(givenForm, name);
}
if (form != null) {
return form;
}
LOG.debug("No given form or given form not suitable, trying others");
form = checkFormIsSuitable(context.getCurrentForm(), name);
if (form != null) {
return form;
}
LOG.debug("No current form or current form not suitable, trying others");
return searchAllFormsForSuitableOne(context, name, step);
}
private static HtmlForm checkFormIsSuitable(HtmlForm candidateForm, final String name) {
if (candidateForm != null && hasTextField(candidateForm, name)) {
LOG.debug("Form '" + candidateForm.getNameAttribute() + "' has suitable text field, using it");
return candidateForm;
}
return null;
}
private static HtmlForm searchAllFormsForSuitableOne(Context context, final String name, Step step) {
for (final Iterator iter = context.getCurrentHtmlResponse(step).getForms().iterator(); iter.hasNext();) {
final HtmlForm curForm = (HtmlForm) iter.next();
if (hasTextField(curForm, name)) {
context.setCurrentForm(curForm);
return curForm;
}
}
return null;
}
public static HtmlForm findFormByName(final HtmlPage currentResp, final String name) {
LOG.debug("Looking for form named '" + name + "'");
try {
return currentResp.getFormByName(name);
} catch (Exception e) {
LOG.debug("Exception: " + e.getMessage());
}
return null;
}
public static HtmlForm findFormByIndex(final HtmlPage currentResp, final String indexStr) {
LOG.debug("Looking for form with index '" + indexStr + "'");
final int index = ConversionUtil.convertToInt(indexStr, 0);
final int numForms = currentResp.getForms().size();
if (index >= numForms) {
LOG.info("Index value of '" + index + "' not in expected range: 0.." + (numForms - 1));
return null;
}
return (HtmlForm) currentResp.getForms().get(index);
}
}