001: // Copyright © 2002-2007 Canoo Engineering AG, Switzerland.
002: package com.canoo.webtest.util;
003:
004: import com.canoo.webtest.engine.Context;
005: import com.canoo.webtest.steps.Step;
006: import com.gargoylesoftware.htmlunit.html.HtmlElement;
007: import com.gargoylesoftware.htmlunit.html.HtmlForm;
008: import com.gargoylesoftware.htmlunit.html.HtmlInput;
009: import com.gargoylesoftware.htmlunit.html.HtmlPage;
010: import org.apache.log4j.Logger;
011:
012: import java.util.Iterator;
013: import java.util.List;
014:
015: /**
016: * Utilities for working with forms.
017: *
018: * @author Paul King
019: */
020: public class FormUtil {
021: private static final Logger LOG = Logger.getLogger(FormUtil.class);
022:
023: /**
024: * Tests if the form contains the desired field.
025: */
026: private static boolean hasField(final HtmlForm form,
027: final String tag, final String type, final String name) {
028: List elements = form.getHtmlElementsByTagName(tag);
029: for (Iterator iter = elements.iterator(); iter.hasNext();) {
030: HtmlElement element = (HtmlElement) iter.next();
031: if (name.equals(element
032: .getAttributeValue(HtmlConstants.NAME))
033: && (type == null || type.equalsIgnoreCase(element
034: .getAttributeValue(HtmlConstants.TYPE)))) {
035: return true;
036: }
037: }
038: return false;
039: }
040:
041: /**
042: * Indicates if the form has a "text field" (text, password or textarea) with the given name.
043: */
044: public static boolean hasTextField(final HtmlForm form,
045: final String name) {
046: if (hasTextAreaField(form, name)) {
047: return true;
048: }
049: return hasTextOrPasswordField(form, name);
050: }
051:
052: private static boolean hasTextOrPasswordField(final HtmlForm form,
053: final String name) {
054: final List li = form.getInputsByName(name);
055: for (final Iterator iter = li.iterator(); iter.hasNext();) {
056: final HtmlInput element = (HtmlInput) iter.next();
057: if (HtmlConstants.TEXT.equalsIgnoreCase(element
058: .getTypeAttribute())
059: || HtmlConstants.PASSWORD.equalsIgnoreCase(element
060: .getTypeAttribute())) {
061: return true;
062: }
063: }
064: return false;
065: }
066:
067: private static boolean hasTextAreaField(final HtmlForm form,
068: final String name) {
069: return !form.getTextAreasByName(name).isEmpty();
070: }
071:
072: /**
073: * Gets the form from the current response containing the desired field. If there is a current form then this form is
074: * considered, else the first form containing such a field (this form is then set as the current form for further
075: * calls).<br/> Note: the test is currently only performed on the name of the field.
076: *
077: * @param context
078: * @param givenFormName
079: * @param tag the html tag corresponding to the field
080: * @param type the type of the input field (html attribute "type") if tag is "input"
081: * @param name the name of the input field (html attribute "name")
082: * @param step
083: * @return <code>null</code> if no form found.
084: */
085: public static HtmlForm findFormForField(Context context,
086: String givenFormName, final String tag, final String type,
087: final String name, Step step) {
088: LOG.debug("Looking for form with " + tag + " field " + type
089: + " named \"" + name + "\"");
090: HtmlForm form = null;
091: if (givenFormName != null) {
092: HtmlForm givenForm = findFormByName(context
093: .getCurrentHtmlResponse(step), givenFormName);
094: form = checkFormIsSuitable(givenForm, tag, type, name);
095: }
096: if (form != null) {
097: return form;
098: }
099: LOG
100: .debug("No given form or given form not suitable, trying others");
101: form = checkFormIsSuitable(context.getCurrentForm(), tag, type,
102: name);
103: if (form != null) {
104: return form;
105: }
106: LOG
107: .debug("No current form or current form not suitable, trying others");
108: return searchAllFormsForSuitableOne(context, tag, type, name,
109: step);
110: }
111:
112: private static HtmlForm checkFormIsSuitable(
113: final HtmlForm candidateForm, final String tag,
114: final String type, final String name) {
115: if (candidateForm != null
116: && hasField(candidateForm, tag, type, name)) {
117: LOG.debug("Form '" + candidateForm.getNameAttribute()
118: + "' has suitable field, using it");
119: return candidateForm;
120: }
121: return null;
122: }
123:
124: private static HtmlForm searchAllFormsForSuitableOne(
125: final Context context, final String tag, final String type,
126: final String name, Step step) {
127: for (final Iterator iter = context.getCurrentHtmlResponse(step)
128: .getForms().iterator(); iter.hasNext();) {
129: final HtmlForm curForm = (HtmlForm) iter.next();
130: if (hasField(curForm, tag, type, name)) {
131: context.setCurrentForm(curForm);
132: return curForm;
133: }
134: }
135: return null;
136: }
137:
138: /**
139: * Gets the form from the current response containing the desired text field. If there is a current form then this form
140: * is considered, else the first form containing such a field (this form is then set a the current form for further
141: * calls).
142: *
143: * @param context
144: * @param givenFormName
145: * @param name the name of the text field of interest (<input type="text"...> or
146: * <input type="password" ...> or <textarea ...>...</textarea>)
147: * @param step
148: * @return <code>null</code> if no form found.
149: */
150: public static HtmlForm findFormForTextField(Context context,
151: String givenFormName, final String name, Step step) {
152: LOG.debug("Looking for form with text field named \"" + name
153: + "\"");
154: HtmlForm form = null;
155: if (givenFormName != null) {
156: HtmlForm givenForm = findFormByName(context
157: .getCurrentHtmlResponse(step), givenFormName);
158: form = checkFormIsSuitable(givenForm, name);
159: }
160: if (form != null) {
161: return form;
162: }
163: LOG
164: .debug("No given form or given form not suitable, trying others");
165: form = checkFormIsSuitable(context.getCurrentForm(), name);
166: if (form != null) {
167: return form;
168: }
169: LOG
170: .debug("No current form or current form not suitable, trying others");
171: return searchAllFormsForSuitableOne(context, name, step);
172: }
173:
174: private static HtmlForm checkFormIsSuitable(HtmlForm candidateForm,
175: final String name) {
176: if (candidateForm != null && hasTextField(candidateForm, name)) {
177: LOG.debug("Form '" + candidateForm.getNameAttribute()
178: + "' has suitable text field, using it");
179: return candidateForm;
180: }
181: return null;
182: }
183:
184: private static HtmlForm searchAllFormsForSuitableOne(
185: Context context, final String name, Step step) {
186: for (final Iterator iter = context.getCurrentHtmlResponse(step)
187: .getForms().iterator(); iter.hasNext();) {
188: final HtmlForm curForm = (HtmlForm) iter.next();
189: if (hasTextField(curForm, name)) {
190: context.setCurrentForm(curForm);
191: return curForm;
192: }
193: }
194: return null;
195: }
196:
197: public static HtmlForm findFormByName(final HtmlPage currentResp,
198: final String name) {
199: LOG.debug("Looking for form named '" + name + "'");
200: try {
201: return currentResp.getFormByName(name);
202: } catch (Exception e) {
203: LOG.debug("Exception: " + e.getMessage());
204: }
205: return null;
206: }
207:
208: public static HtmlForm findFormByIndex(final HtmlPage currentResp,
209: final String indexStr) {
210: LOG.debug("Looking for form with index '" + indexStr + "'");
211: final int index = ConversionUtil.convertToInt(indexStr, 0);
212: final int numForms = currentResp.getForms().size();
213: if (index >= numForms) {
214: LOG.info("Index value of '" + index
215: + "' not in expected range: 0.." + (numForms - 1));
216: return null;
217: }
218: return (HtmlForm) currentResp.getForms().get(index);
219: }
220:
221: }
|