1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.jameleon.plugin.htmlunit.util;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25 import java.util.List;
26
27 import net.sf.jameleon.util.JameleonUtility;
28
29 import org.jaxen.JaxenException;
30 import org.jaxen.Navigator;
31
32 import com.gargoylesoftware.htmlunit.ElementNotFoundException;
33 import com.gargoylesoftware.htmlunit.Page;
34 import com.gargoylesoftware.htmlunit.WebClient;
35 import com.gargoylesoftware.htmlunit.WebResponse;
36 import com.gargoylesoftware.htmlunit.WebWindow;
37 import com.gargoylesoftware.htmlunit.html.ClickableElement;
38 import com.gargoylesoftware.htmlunit.html.DomNode;
39 import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
40 import com.gargoylesoftware.htmlunit.html.HtmlElement;
41 import com.gargoylesoftware.htmlunit.html.HtmlForm;
42 import com.gargoylesoftware.htmlunit.html.HtmlInput;
43 import com.gargoylesoftware.htmlunit.html.HtmlOption;
44 import com.gargoylesoftware.htmlunit.html.HtmlPage;
45 import com.gargoylesoftware.htmlunit.html.HtmlRadioButtonInput;
46 import com.gargoylesoftware.htmlunit.html.HtmlSelect;
47 import com.gargoylesoftware.htmlunit.html.HtmlTextArea;
48 import com.gargoylesoftware.htmlunit.html.xpath.HtmlUnitXPath;
49
50 /***
51 * This class is used as a facade around the HtmlUnit API and is used by both
52 * the HtmlUnitSessionTag and the HtmlUnitFunctionTag.
53 */
54 public class HtmlUnitHelper {
55
56 protected HtmlUnitDelegate delegate;
57
58 public HtmlUnitHelper(HtmlUnitDelegate delegate) {
59 this.delegate = delegate;
60 }
61
62 /***
63 * Clicks on an HtmlElement (ClickableElement) defined by the provided XPath expression
64 * @param xpath - The XPath expression to locate the element to click on.
65 */
66 public void clickElementWithXPath(String xpath) {
67 HtmlElement element = getHtmlElementByXPath(xpath);
68 if ( element != null && element instanceof ClickableElement ) {
69 try {
70 ((ClickableElement)element).click();
71 } catch ( IOException ioe ) {
72 throw new RuntimeException(ioe.getMessage(), ioe);
73 }
74 } else {
75 String errMsg;
76 if ( element == null ) {
77 errMsg = "No element found to click on that matches the given XPath '"+xpath+"'";
78 } else {
79 errMsg = "The element returned ("+element.getTagName()+") can not be clicked on";
80 }
81 throw new RuntimeException(errMsg);
82 }
83 }
84
85 /***
86 * Gets the HtmlUnitDelegate that this object uses to communicate with the
87 * existing session.
88 *
89 * @return The HtmlUnitDelegate that this object uses to communicate with the
90 * existing session.
91 */
92 public HtmlUnitDelegate getDelegate() {
93 return delegate;
94 }
95
96 /***
97 * Gets the current page in the currently active WebWindow
98 *
99 * @return The current page in the currently active WebWindow
100 */
101 public Page getCurrentPage() {
102 Page page = null;
103 WebWindow window = delegate.getCurrentWebWindow();
104 if ( window != null ) {
105 page = window.getEnclosedPage();
106 }
107 return page;
108 }
109
110 /***
111 * Gets the HTML source from the currently active window
112 *
113 * @return The HTML source used in the current window
114 */
115 public String getCurrentPageContent() {
116 String content = null;
117 WebResponse res = getCurrentWebResponse();
118 if ( res != null ) {
119 content = res.getContentAsString();
120 }
121 return content;
122 }
123
124 /***
125 * Gets the currnet WebResponse
126 *
127 * @return The current WebResponse
128 */
129 public WebResponse getCurrentWebResponse() {
130 WebResponse res = null;
131 Page page = getCurrentPage();
132 if ( page != null ) {
133 res = page.getWebResponse();
134 }
135 return res;
136 }
137
138 /***
139 * Gets an HtmlElement matching the provided xpath expression
140 * @param xpath - An XPath expression that matches the desired HtmlElement
141 *
142 * @return The matching HtmlElement
143 */
144 public HtmlElement getHtmlElementByXPath(String xpath) {
145 HtmlElement element = null;
146 if ( xpath != null ) {
147 element = getHtmlElementByXPath((HtmlPage)getCurrentPage(), xpath);
148 } else {
149 throw new RuntimeException("xpath was null! Supply an xpath expression.");
150 }
151 return element;
152 }
153
154 /***
155 * Gets an HtmlElement matching the provided xpath expression
156 * @param container - The DOM to start at
157 * @param xpath - An XPath expression that matches the desired HtmlElement
158 *
159 * @return The matching HtmlElement
160 */
161 public HtmlElement getHtmlElementByXPath(DomNode container, String xpath) {
162 HtmlElement element = null;
163 if ( xpath != null && container != null ) {
164 Navigator nav = HtmlUnitXPath.buildSubtreeNavigator(container);
165 try {
166 HtmlUnitXPath xp = new HtmlUnitXPath(xpath, nav);
167 element = (HtmlElement)xp.selectSingleNode(getCurrentPage());
168 } catch ( JaxenException je ) {
169 throw new RuntimeException("Problem processing XPath '"+xpath+"'", je);
170 }
171 } else {
172 throw new RuntimeException("Neither xpath nor container can be null! Supply an xpath expression and the container to execute it in.");
173 }
174 return element;
175 }
176
177 /***
178 * Gets an HTMLElement by the tag name, attribute name and the attribute value.
179 * This then in turn gets translated to an XPath expression.
180 * An example of this might be to get a form with its id='ten'.
181 * @param tagname - The name of the tag to get back. In the above example, the value would be 'form'
182 * @param attributeName - The name of attribute to check against. In the above example, the value would be 'id'
183 * @param attributeValue - The value of the attribute to check against. In the above example, the value would be 'ten'
184 *
185 * @return HtmlElement - An element that matches the criteria.
186 */
187 public HtmlElement getHtmlElementByAttributeNameAndValue(String tagname, String attributeName, String attributeValue) {
188 HtmlElement element = null;
189 if ( tagname != null && attributeName != null && attributeValue != null ) {
190 String xpath = "//"+tagname+"[@"+attributeName+"='"+attributeValue+"']";
191 element = getHtmlElementByXPath(xpath);
192 } else {
193 throw new RuntimeException("The 'tagname', 'attributeName' and 'attributeValue' parameters must all be set!");
194 }
195 return element;
196 }
197
198 /***
199 * Gets a form element back by its id attribute.
200 * @param id - the value of the id attribute.
201 *
202 * @return HtmlForm
203 */
204 public HtmlForm getHtmlFormById(String id) {
205 HtmlForm form = null;
206 if ( id != null ) {
207 HtmlPage page = (HtmlPage)getCurrentPage();
208 HtmlElement elmnt = null;
209 try {
210 elmnt = page.getHtmlElementById(id);
211 if ( elmnt instanceof HtmlForm ) {
212 form = (HtmlForm) elmnt;
213 }
214 } catch ( ElementNotFoundException enfe ) {
215
216 }
217 } else {
218 throw new RuntimeException("The 'id' parameter was null!");
219 }
220 return form;
221 }
222
223 /***
224 * Gets a form element back by its index or location on the page.
225 * For the first form on the page, pass in '1'
226 * @param index - the nth form on the page
227 *
228 * @return HtmlForm
229 */
230 public HtmlForm getHtmlFormByIndex(int index) {
231 return(HtmlForm)getHtmlElementByXPath("//form["+index+"]");
232 }
233
234 /***
235 * Gets a form element back by its name attribute.
236 * @param formName - the value of the name attribute.
237 *
238 * @return HtmlForm
239 */
240 public HtmlForm getHtmlFormByName(String formName) {
241 HtmlForm form = null;
242 if ( formName != null ) {
243 HtmlPage page = (HtmlPage)getCurrentPage();
244 try {
245 form = page.getFormByName(formName);
246 } catch ( ElementNotFoundException enfe ) {
247
248 }
249 } else {
250 throw new RuntimeException("The 'formName' parameter was null!");
251 }
252 return form;
253 }
254
255 /***
256 * Gets a form element back by an XPath expression
257 * @param xpath - The XPath expression matching the desired form
258 *
259 * @return HtmlForm
260 */
261 public HtmlForm getHtmlFormByXPath(String xpath) {
262 HtmlForm form = null;
263 HtmlElement e = getHtmlElementByXPath(xpath);
264 if ( e instanceof HtmlForm ) {
265 form = (HtmlForm) e;
266 }
267 return form;
268 }
269
270 /***
271 * Gets an HtmlInput tag based on the current workingForm or the currently active page if the workingForm is not set.
272 * @param fieldName - The name of the input field
273 *
274 * @return HtmlForm
275 */
276 public HtmlInput getHtmlInputByName(String fieldName) {
277 HtmlInput input = null;
278 HtmlForm form = delegate.getWorkingForm();
279 if ( form != null ) {
280 input = form.getInputByName(fieldName);
281 } else {
282 HtmlElement element = getHtmlElementByXPath("//input[@name='"+fieldName+"']");
283 if ( element != null && element instanceof HtmlInput ) {
284 input = (HtmlInput)element;
285 }
286 }
287 return input;
288 }
289
290 /***
291 * Gets an HtmlInput tag based on the current workingForm or the currently active page if the workingForm is not set.
292 * @param fieldName - The name of the input field
293 * @param fieldValue - The value of the input field
294 *
295 * @return HtmlForm
296 */
297 public HtmlInput getHtmlInputByNameAndValue(String fieldName, String fieldValue) {
298 HtmlInput input = null;
299 HtmlForm form = delegate.getWorkingForm();
300 String xpath = "//input[@name='"+fieldName+"' and @value='"+fieldValue+"']";
301 if ( form != null ) {
302 input = (HtmlInput) getHtmlElementByXPath(form, xpath);
303 } else {
304 input = (HtmlInput) getHtmlElementByXPath(xpath);
305 }
306 return input;
307 }
308
309 /***
310 * Navigates to the provided URL
311 * @param url - the url to navigate to.
312 */
313 public void navigate(String url) {
314 try {
315 WebClient client = delegate.getWebClient();
316 URL u = new URL(url);
317 client.getPage(u);
318 } catch ( MalformedURLException mfue ) {
319 throw new RuntimeException("The provided url '"+url+"' is not valid.", mfue);
320 } catch ( IOException ioe ) {
321 throw new RuntimeException("Could not coneect to '"+url+"'.", ioe);
322 }
323 }
324
325 /***
326 * Checks or unchecks the checkbox that either exists in the workingForm or in the current page
327 * @param fieldName - The name of the input field to set the value of
328 * @param checked - set to <code>true</code> to check the checkbox and to <code>false</code> to uncheck it
329 */
330 public void setCheckBox(String fieldName, boolean checked) {
331 HtmlInput input = getHtmlInputByName(fieldName);
332 if ( input != null ) {
333 if ( input instanceof HtmlCheckBoxInput ) {
334 ((HtmlCheckBoxInput)input).setChecked(checked);
335 } else {
336 throw new RuntimeException("expected checkbox, but was a '"+input.getTypeAttribute()+"' field!");
337 }
338 } else {
339 throw new RuntimeException("No checkbox named '"+fieldName+"' was found!");
340 }
341 }
342
343 /***
344 * Checks or unchecks the checkbox that either exists in the workingForm or in the current page.
345 * This method is used for pages that contain several checkboxes with the same name, but different values
346 * @param fieldName - The name of the checkbox to check
347 * @param fieldValue - The value of the input field to check
348 * @param checked - set to <code>true</code> to check the checkbox and to <code>false</code> to uncheck it
349 */
350 public void setCheckBox(String fieldName, String fieldValue, boolean checked) {
351 HtmlInput input = getHtmlInputByNameAndValue(fieldName, fieldValue);
352 if ( input != null ) {
353 if ( input instanceof HtmlCheckBoxInput ) {
354 ((HtmlCheckBoxInput)input).setChecked(checked);
355 } else {
356 throw new RuntimeException("expected checkbox, but was a '"+input.getTypeAttribute()+"' field!");
357 }
358 } else {
359 throw new RuntimeException("No checkbox named '"+fieldName+"' with the value '"+fieldValue+"' was found!");
360 }
361 }
362
363 /***
364 * Sets the file field that either exists in the workingForm or in the current page
365 * @param fieldName - The name of the input field to set the value of
366 * @param value - The value to set the input field to
367 */
368 public void setFileField(String fieldName, String value) {
369 HtmlInput input = getHtmlInputByName(fieldName);
370 setHtmlInputValue(input, value, "file");
371 }
372
373 /***
374 * Sets the hidden field that either exists in the workingForm or in the current page
375 * @param fieldName - The name of the input field to set the value of
376 * @param value - The value to set the input field to
377 */
378 public void setHiddenField(String fieldName, String value) {
379 HtmlInput input = getHtmlInputByName(fieldName);
380 setHtmlInputValue(input, value, "hidden");
381 }
382
383 /***
384 * Sets the password field that either exists in the workingForm or in the current page
385 * @param fieldName - The name of the input field to set the value of
386 * @param value - The value to set the input field to
387 */
388 public void setPasswordField(String fieldName, String value) {
389 HtmlInput input = getHtmlInputByName(fieldName);
390 setHtmlInputValue(input, value, "password");
391 }
392
393 /***
394 * Checks or unchecks the radio button that either exists in the workingForm or in the current page.
395 * @param fieldName - The name of the radio button to check
396 * @param fieldValue - The value of the radio button to check
397 * @param checked - set to <code>true</code> to check the radio button and to <code>false</code> to uncheck it
398 */
399 public void setRadioButton(String fieldName, String fieldValue, boolean checked) {
400 HtmlInput input = getHtmlInputByNameAndValue(fieldName, fieldValue);
401 if ( input != null ) {
402 if ( input instanceof HtmlRadioButtonInput ) {
403 ((HtmlRadioButtonInput)input).setChecked(checked);
404 } else {
405 throw new RuntimeException("expected radio, but was a '"+input.getTypeAttribute()+"' field!");
406 }
407 } else {
408 throw new RuntimeException("No radio button named '"+fieldName+"' with the value '"+fieldValue+"' was found!");
409 }
410 }
411
412 /***
413 * Selects or unselects the option by its index order that either exists in the workingForm or in the current page.
414 * @param fieldName - The name of the select field to select
415 * @param index - The nth option in the list. 1st option = 1
416 * @param selected - set to <code>true</code> to select and to <code>false</code> to unselect it
417 */
418 public void setSelectFieldByIndex(String fieldName, int index, boolean selected) {
419 HtmlOption option = null;
420 HtmlForm form = delegate.getWorkingForm();
421 String xpath = "//select[@name='"+fieldName+"']/option["+index+"]";
422 HtmlElement element = null;
423 if ( form != null ) {
424 element = getHtmlElementByXPath(form, xpath);
425 } else {
426 element = getHtmlElementByXPath(xpath);
427 }
428 if ( element != null && element instanceof HtmlOption ) {
429 option = (HtmlOption)element;
430 option.setSelected(selected);
431 } else {
432 throw new RuntimeException("select field with the name '"+fieldName+"' and option was not found!");
433 }
434 }
435
436 /***
437 * Selects or unselects the option with the displayed text that either exists in the workingForm or in the current page.
438 * @param fieldName - The name of the select field to select
439 * @param optionText - The text displayed in the drop-down
440 * @param selected - set to <code>true</code> to select and to <code>false</code> to unselect it
441 */
442 public void setSelectFieldByOptionText(String fieldName, String optionText, boolean selected) {
443 HtmlOption option = null;
444 HtmlForm form = delegate.getWorkingForm();
445 String xpath = "//select[@name='"+fieldName+"']/option[text()='"+optionText+"']";
446 HtmlElement element = null;
447 if ( form != null ) {
448 element = getHtmlElementByXPath(form, xpath);
449 } else {
450 element = getHtmlElementByXPath(xpath);
451 }
452 if ( element != null && element instanceof HtmlOption ) {
453 option = (HtmlOption)element;
454 option.setSelected(selected);
455 } else {
456 throw new RuntimeException("select field with the name '"+fieldName+"' was not found!");
457 }
458 }
459
460 /***
461 * Selects or unselects the option with the given attribute value that either exists in the workingForm or in the current page.
462 * @param fieldName - The name of the select field to select
463 * @param valueAttribute - The value of option field to select
464 * @param selected - set to <code>true</code> to select and to <code>false</code> to unselect it
465 */
466 public void setSelectFieldByValue(String fieldName, String valueAttribute, boolean selected) {
467 HtmlSelect select = null;
468 HtmlForm form = delegate.getWorkingForm();
469 if ( form != null ) {
470 select = form.getSelectByName(fieldName);
471 } else {
472 HtmlElement element = getHtmlElementByXPath("//select[@name='"+fieldName+"']");
473 if ( element != null && element instanceof HtmlSelect ) {
474 select = (HtmlSelect)element;
475 }
476 }
477 if ( select != null ) {
478 select.setSelectedAttribute(valueAttribute, selected);
479 } else {
480 throw new RuntimeException("select field with the name '"+fieldName+"' was not found!");
481 }
482 }
483
484 /***
485 * Selects or unselects the option defined by XPath.
486 * @param xpath - The XPath expression that matches an HtmlOption (not a select) to be selected
487 * @param selected - set to <code>true</code> to select and to <code>false</code> to unselect it
488 */
489 public void setSelectFieldByXPath(String xpath, boolean selected) {
490 HtmlOption option = null;
491 HtmlElement element = null;
492 element = getHtmlElementByXPath(xpath);
493 if ( element != null && element instanceof HtmlOption ) {
494 option = (HtmlOption)element;
495 option.setSelected(selected);
496 } else {
497 throw new RuntimeException("select field defined by '"+xpath+"' was not found!");
498 }
499 }
500
501 /***
502 * Sets the text area that either exists in the workingForm or in the current page
503 * @param fieldName - The name of the input field to set the value of
504 * @param value - The value to set the input field to
505 */
506 public void setTextArea(String fieldName, String value) {
507 HtmlTextArea textArea = null;
508 HtmlForm form = delegate.getWorkingForm();
509 if ( form != null ) {
510 List textAreas = form.getTextAreasByName(fieldName);
511 if ( textAreas.size() > 0 ) {
512 textArea = (HtmlTextArea)textAreas.get(0);
513 }
514 } else {
515 HtmlElement element = getHtmlElementByXPath("//textarea[@name='"+fieldName+"']");
516 if ( element != null && element instanceof HtmlTextArea ) {
517 textArea = (HtmlTextArea)element;
518 }
519 }
520 if ( textArea != null ) {
521 textArea.setText(value);
522 } else {
523 throw new RuntimeException("textarea with the name '"+fieldName+"' was not found!");
524 }
525 }
526
527 /***
528 * Sets the text field that either exists in the workingForm or in the current page
529 * @param fieldName - The name of the input field to set the value of
530 * @param value - The value to set the input field to
531 */
532 public void setTextField(String fieldName, String value) {
533 HtmlInput input = getHtmlInputByName(fieldName);
534 setHtmlInputValue(input, value, "text");
535 }
536
537 /***
538 * Sets an input field type's value
539 * @param input - The HtmlInput to set the value on
540 * @param value - The value to set the input element to.
541 * @param type - The input type. If this does not match the given field, then this method will fail
542 */
543 public void setHtmlInputValue(HtmlInput input, String value, String type) {
544 if ( input != null ) {
545 String elementType = input.getAttributeValue("type");
546 if ( type.equalsIgnoreCase(elementType) ) {
547 input.setValueAttribute(value);
548 } else {
549 throw new RuntimeException("input field defined '"+input.getTagName()+"' of type '"+elementType+"' was not expected '"+type+"'!");
550 }
551 } else {
552 throw new RuntimeException("input field was null!");
553 }
554 }
555
556 /***
557 * Sets an input field type's value
558 * @param xpath - An XPath expression that matches the desired HtmlInput Element.
559 * @param value - The value to set the input element to.
560 * @param type - The input type. If this does not match the given field, then this method will fail
561 */
562 public void setHtmlInputValueByXPath(String xpath, String value, String type) {
563 HtmlElement element = getHtmlElementByXPath(xpath);
564 if ( element != null && element instanceof HtmlInput ) {
565 HtmlInput input = (HtmlInput) element;
566 setHtmlInputValue(input, value, type);
567 } else {
568 throw new RuntimeException("Could not find the input element defined by '"+xpath+"'");
569 }
570 }
571
572 /***
573 * Store the contents of the currently active window
574 * @param fName - The name of the file to store the source to.
575 */
576 public File store(String fName) throws IOException{
577 WebResponse res = getCurrentWebResponse();
578 File stateFile = null;
579 if ( res != null ) {
580 String html = res.getContentAsString();
581 String charset = res.getContentCharSet();
582 String filename = fName+".html";
583 if ( html != null && html.length() > 0 ) {
584 stateFile = new File(filename);
585 if ( charset != null && charset.length() > 0 ) {
586 JameleonUtility.recordResultsToFile(stateFile, html, charset);
587 } else {
588 JameleonUtility.recordResultsToFile(stateFile, html);
589 }
590 }
591 }
592 return stateFile;
593 }
594
595 /***
596 * Checks that the the provided XPath expression matches something on the current page.
597 * @param xpath - The XPath expression to evaulate
598 *
599 * @return boolean - true if the XPath expresssion matches
600 */
601 public boolean xPathMatches(String xpath) {
602 boolean matches = (getHtmlElementByXPath(xpath) != null);
603 return matches;
604 }
605 }