001: /* WebBrowser.java
002: *
003: * DDSteps - Data Driven JUnit Test Steps
004: * Copyright (C) 2005 Jayway AB
005: * www.ddsteps.org
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License version 2.1 as published by the Free Software Foundation.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, visit
018: * http://www.opensource.org/licenses/lgpl-license.php
019: */
020:
021: package org.ddsteps.web.jwebunit;
022:
023: import java.io.File;
024: import java.io.IOException;
025:
026: import junitx.framework.Assert;
027: import junitx.util.PrivateAccessor;
028: import net.sourceforge.jwebunit.HttpUnitDialog;
029: import net.sourceforge.jwebunit.WebTester;
030: import net.sourceforge.jwebunit.util.ExceptionUtility;
031:
032: import org.apache.commons.lang.ArrayUtils;
033: import org.apache.commons.lang.Validate;
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036: import org.ddsteps.DDStepsException;
037: import org.ddsteps.util.StringUtils;
038: import org.ddsteps.web.WebBrowser;
039: import org.ddsteps.web.trail.FileTrailWriter;
040: import org.ddsteps.web.trail.TrailPage;
041: import org.ddsteps.web.trail.WebTrail;
042: import org.xml.sax.SAXException;
043:
044: import com.meterware.httpunit.Button;
045: import com.meterware.httpunit.SubmitButton;
046: import com.meterware.httpunit.WebClient;
047: import com.meterware.httpunit.WebForm;
048: import com.meterware.httpunit.WebResponse;
049:
050: /**
051: * Extends the WebTester to provide easy-of-use config properties, and a nice
052: * HTML trail functionality.
053: *
054: * @author adam
055: * @version $Id$
056: */
057: public class JWebUnitWebBrowser extends WebTester implements WebBrowser {
058:
059: /**
060: * Logger for this class
061: */
062: public static final Log logger = LogFactory
063: .getLog(JWebUnitWebBrowser.class);
064:
065: /**
066: * Dependency / delegate: WebTrail that is used to write trail.
067: */
068: protected WebTrail webTrail = new FileTrailWriter();
069:
070: /**
071: * No-args. There will be no trail by default.
072: */
073: public JWebUnitWebBrowser() {
074: super ();
075: }
076:
077: /**
078: * @see org.ddsteps.web.WebBrowser#assertOptionsEqual(java.lang.String,
079: * java.lang.String[])
080: */
081: public void assertOptionsEqual(String selectName,
082: String[] expectedOptions) {
083:
084: if (expectedOptions == null)
085: expectedOptions = ArrayUtils.EMPTY_STRING_ARRAY;
086:
087: super .assertOptionsEqual(selectName, expectedOptions);
088: }
089:
090: /**
091: * @see org.ddsteps.web.WebBrowser#endTrail()
092: */
093: public void endTrail() {
094: webTrail.endTrail();
095: }
096:
097: /**
098: * @see org.ddsteps.web.WebBrowser#getTrailFolder()
099: */
100: public File getTrailFolder() {
101: return webTrail.getTrailFolder();
102: }
103:
104: /**
105: * @see org.ddsteps.web.WebBrowser#isTrailEnabled()
106: */
107: public boolean isTrailEnabled() {
108: return webTrail.isTrailEnabled();
109: }
110:
111: /**
112: * @see org.ddsteps.web.WebBrowser#setTrailEnabled(boolean)
113: */
114: public void setTrailEnabled(boolean trailEnabled) {
115: webTrail.setTrailEnabled(trailEnabled);
116: }
117:
118: /**
119: * @see org.ddsteps.web.WebBrowser#setTrailFolder(java.io.File)
120: */
121: public void setTrailFolder(File trailFolder) {
122: webTrail.setTrailFolder(trailFolder);
123: }
124:
125: /**
126: * @see org.ddsteps.web.WebBrowser#setUrl(java.lang.String)
127: */
128: public void setUrl(String url) {
129: getTestContext().setBaseUrl(url);
130: }
131:
132: /**
133: * @see org.ddsteps.web.WebBrowser#startTrail(java.lang.String)
134: */
135: public void startTrail(String trailName) {
136: webTrail.startTrail(trailName);
137: }
138:
139: /**
140: * @see org.ddsteps.web.WebBrowser#writeTrail(java.lang.String)
141: */
142: public void writeTrail(String pageName) {
143:
144: Validate.notEmpty("Page name must not be empty.");
145:
146: if (!webTrail.isTrailEnabled()) {
147: logger.debug("Trail disabled.");
148: return;
149: }
150:
151: String pageAsString;
152: try {
153: pageAsString = getDialog().getResponse().getText();
154: } catch (IOException e) {
155: throw new DDStepsException(
156: "Exception getting page contents when writing trail.",
157: e);
158: }
159: String encoding = getDialog().getResponse().getCharacterSet();
160: String pageTitle = getDialog().getResponsePageTitle();
161:
162: TrailPage page = new TrailPage(pageName, pageTitle, encoding,
163: pageAsString);
164:
165: webTrail.writeTrail(page);
166:
167: }
168:
169: /**
170: * Assert that a button is present and disabled.
171: *
172: * @param buttonId
173: */
174: public void assertButtonDisabled(String buttonId) {
175: Button button = getButton(buttonId);
176: Assert.assertTrue("Button [" + buttonId + "] not disabled.",
177: button.isDisabled());
178: }
179:
180: /**
181: * Assert that a button is present and enabled.
182: *
183: * @param buttonId
184: */
185: public void assertButtonEnabled(String buttonId) {
186: Button button = getButton(buttonId);
187: Assert.assertFalse("Button [" + buttonId + "] not enabled.",
188: button.isDisabled());
189: }
190:
191: /**
192: * Assert that a form element is not present or disabled.
193: *
194: * @param formElementName
195: * name of the form element
196: */
197: public void assertFormElementNotPresentOrDisabled(
198: String formElementName) {
199: HttpUnitDialog dialog = getDialog();
200:
201: if (!dialog.hasFormParameterNamed(formElementName)) {
202: // All is well - the element is not present
203: return;
204: }
205:
206: WebForm form = dialog.getForm();
207: Assert.assertTrue("Element [" + formElementName
208: + "] is not disabled", form
209: .isDisabledParameter(formElementName));
210: }
211:
212: /**
213: * Assert that a form element is present and enabled.
214: *
215: * @param formElementName
216: * name of the form element
217: */
218: public void assertFormElementPresentAndEnabled(
219: String formElementName) {
220: assertFormElementPresent(formElementName);
221:
222: HttpUnitDialog dialog = getDialog();
223: WebForm form = dialog.getForm();
224: Assert.assertFalse("Element [" + formElementName
225: + "] is not enabled", form
226: .isDisabledParameter(formElementName));
227:
228: }
229:
230: /**
231: * @param selectId
232: * The select tag.
233: * @param selectedValue
234: * The VALUE that should be selected.
235: */
236: public void assertOptionIsSelectedByValue(String selectId,
237: String selectedValue) {
238:
239: Assert.assertEquals(selectedValue,
240: getSelectedOptionValue(selectId));
241: }
242:
243: /**
244: * @param selectId
245: * @param value
246: */
247: public void assertOptionValuePresent(String selectId, String value) {
248: String[] values = getOptionValues(selectId);
249:
250: for (int i = 0; i < values.length; i++) {
251: if (values[i].equals(value)) {
252: return;
253: }
254: }
255:
256: Assert.fail("Select " + selectId + " does not contain value "
257: + value);
258: }
259:
260: /**
261: * If the list has any non blanks strings, the element must exist and have
262: * all the non blank strings in it.
263: *
264: * @param elementId
265: * @param texts
266: */
267: public void assertTextInElement(String elementId, String[] texts) {
268: if (StringUtils.containsNotBlank(texts)) {
269:
270: assertElementPresent(elementId);
271:
272: for (int i = 0; i < texts.length; i++) {
273: String text = texts[i];
274: if (StringUtils.isNotBlank(text)) {
275: assertTextInElement(elementId, text);
276: }
277: }
278:
279: }
280: }
281:
282: /**
283: * Gets the LABEL of the selected option in a select box.
284: *
285: * @param selectName
286: * @return The label
287: */
288: public String getDefaultOption(String selectName) {
289: HttpUnitDialog dialog = getDialog();
290: WebForm form = dialog.getForm();
291:
292: String selected = dialog.getSelectedOption(selectName);
293: if (selected == null) {
294: // bug in httpunit
295: String options[] = form.getOptions(selectName);
296: selected = options[0];
297: }
298: return selected;
299: }
300:
301: /**
302: * Get all the option values for a select tag.
303: *
304: * @param selectId
305: * The ID of the select tag.
306: * @return Array of options.
307: */
308: public String[] getOptionValues(String selectId) {
309: HttpUnitDialog dialog = getDialog();
310: return dialog.getOptionValuesFor(selectId);
311: }
312:
313: /**
314: * Gets the LABEL of the selected option in a select box.
315: *
316: * @param selectName
317: * The NAME of the select tag.
318: * @return The label
319: */
320: public String getSelectedOptionValue(String selectName) {
321: HttpUnitDialog dialog = getDialog();
322: WebForm form = dialog.getForm();
323:
324: String[] labels = form.getOptions(selectName);
325:
326: String selected = dialog.getSelectedOption(selectName);
327: if (selected == null) {
328: // bug in httpunit
329: selected = labels[0];
330: }
331:
332: String[] values = dialog.getOptionValuesFor(selectName);
333:
334: for (int i = 0; i < labels.length; i++) {
335: if (StringUtils.equals(labels[i], selected))
336: return values[i];
337: }
338:
339: Assert.fail("BUG!");
340: return null;
341: }
342:
343: /**
344: * Select an option using the value, not the key.
345: *
346: * @param selectId
347: * The id of the select tag.
348: * @param value
349: * The value
350: */
351: public void selectOptionByValue(String selectId, String value) {
352:
353: WebForm form = getDialog().getForm();
354:
355: String[] labels = form.getOptions(selectId);
356: String[] values = form.getOptionValues(selectId);
357:
358: String label = null;
359:
360: // find label for value
361: for (int i = 0; i < values.length; i++) {
362:
363: if (StringUtils.equals(value, values[i])) {
364: label = labels[i];
365: }
366: }
367:
368: if (label == null) {
369: Assert.fail("Value '" + value + "' not found for select '"
370: + selectId + "'.");
371: } else {
372: selectOption(selectId, label);
373: }
374: }
375:
376: /**
377: * Overload to enable setting multiple form elements with the same name.
378: *
379: * @param formElementName
380: * name of the form element
381: * @param values
382: * the values to set
383: */
384: public void setFormElement(String formElementName, String[] values) {
385: assertFormPresent();
386: assertFormElementPresent(formElementName);
387: getDialog().getForm().setParameter(formElementName, values);
388: }
389:
390: /**
391: * Write the current page to a file, regardless of any current trail or if
392: * trailing is enabled or not.
393: * <p>
394: * If you want a full trail of everything the test sees, use the trail
395: * functionalit instead.
396: *
397: * @param filename
398: * Relative filename in the trail folder, or a full file name.
399: */
400: public void writePage(String filename) {
401:
402: }
403:
404: /**
405: * Gets a button by id and asserts that is was found
406: *
407: * @param buttonId
408: * @return The button, never null.
409: */
410: public Button getButton(String buttonId) {
411: Button button = getDialog().getButton(buttonId);
412: Assert.assertNotNull("Button [" + buttonId
413: + "] not found in form ["
414: + getDialog().getForm().getName() + "].", button);
415: return button;
416: }
417:
418: /**
419: * Finds the form with the specified field in, and sets that form as the
420: * working form. The form does not need to have a name or id.
421: * <p>
422: * This method does use a bit of evil reflection magic to force itself on
423: * HttpUnit, so you really should concider adding a name or id to your form.
424: * <p>
425: * Fails if there are more than one form with that parameter.
426: *
427: * @param fieldName
428: * The field name
429: */
430: public void setWorkingFormByFieldName(String fieldName) {
431:
432: WebForm theForm = null;
433:
434: try {
435: WebForm[] webForms = getDialog().getResponse().getForms();
436:
437: for (int i = 0; i < webForms.length; i++) {
438: WebForm form = webForms[i];
439:
440: String[] parameterNames = form.getParameterNames();
441:
442: if (ArrayUtils.contains(parameterNames, fieldName)) {
443:
444: Assert
445: .assertNull("More than one form was found with a field named '"
446: + fieldName + "'");
447:
448: // first found - ok
449: theForm = form;
450: }
451:
452: }
453:
454: // set working form
455: Assert.assertNotNull("No form with a field named '"
456: + fieldName + "' was found.", theForm);
457: try {
458: PrivateAccessor.invoke(getDialog(), "setWorkingForm",
459: new Class[] { WebForm.class },
460: new Object[] { theForm });
461: } catch (Throwable e) {
462: logger.error("Could not set form in HttpUnit dialog.",
463: e);
464: throw new RuntimeException(
465: "Check your HttpUnit version!\n"
466: + ExceptionUtility
467: .stackTraceToString(e));
468: }
469:
470: } catch (SAXException e) {
471: throw new RuntimeException(ExceptionUtility
472: .stackTraceToString(e));
473: }
474: }
475:
476: /**
477: * Finds the form with the specified field in with a specific value, and
478: * sets that form as the working form. The form does not need to have a name
479: * or id. Very useful for choosing between many different forms that differ
480: * only by the value of a hidden field.
481: * <p>
482: * This method does use a bit of evil reflection magic to force itself on
483: * HttpUnit, so you really should concider adding a name or id to your form.
484: * <p>
485: * It will use the FIRST form it finds with the requested combo.
486: *
487: * @param fieldName
488: * The field name
489: * @param value
490: * The field value
491: */
492: public void setWorkingFormByFieldNameAndValue(String fieldName,
493: String value) {
494:
495: WebForm[] webForms;
496: try {
497: webForms = getDialog().getResponse().getForms();
498: } catch (SAXException e) {
499: throw new RuntimeException(ExceptionUtility
500: .stackTraceToString(e));
501: }
502:
503: WebForm theForm = null;
504:
505: formloop: for (int i = 0; i < webForms.length; i++) {
506: WebForm form = webForms[i];
507:
508: String[] parameterNames = form.getParameterNames();
509:
510: if (ArrayUtils.contains(parameterNames, fieldName)) {
511:
512: String parameterValue = theForm
513: .getParameterValue(fieldName);
514:
515: if (StringUtils.equals(parameterValue, value)) {
516: theForm = form;
517: break formloop;
518: }
519: }
520: }
521:
522: // set working form
523: Assert.assertNotNull("No form with a field named '" + fieldName
524: + "' and value '" + value + "' was found.", theForm);
525: try {
526: PrivateAccessor.invoke(getDialog(), "setWorkingForm",
527: new Class[] { WebForm.class },
528: new Object[] { theForm });
529: } catch (Throwable e) {
530: logger.error("Could not set form in HttpUnit dialog.", e);
531: throw new RuntimeException("Check your HttpUnit version!\n"
532: + ExceptionUtility.stackTraceToString(e));
533: }
534:
535: }
536:
537: /**
538: * Push a submit button based on the name and value of it.
539: *
540: * @param buttonName
541: * @param value
542: */
543: public void submit(String buttonName, String value) {
544:
545: WebForm[] webForms;
546: try {
547: webForms = getDialog().getResponse().getForms();
548: } catch (SAXException e) {
549: throw new RuntimeException(ExceptionUtility
550: .stackTraceToString(e));
551: }
552:
553: formloop: for (int i = 0; i < webForms.length; i++) {
554: WebForm form = webForms[i];
555:
556: SubmitButton submitButton = form.getSubmitButton(
557: buttonName, value);
558:
559: if (submitButton != null) {
560: // Set form
561: try {
562: PrivateAccessor.invoke(getDialog(),
563: "setWorkingForm",
564: new Class[] { WebForm.class },
565: new Object[] { form });
566: } catch (Throwable e) {
567: logger
568: .error(
569: "Could not set form in HttpUnit dialog.",
570: e);
571: throw new RuntimeException(
572: "Check your HttpUnit version!\n"
573: + ExceptionUtility
574: .stackTraceToString(e));
575: }
576:
577: // Push button
578: try {
579: submitButton.click();
580: } catch (Exception e) {
581: throw new RuntimeException(ExceptionUtility
582: .stackTraceToString(e));
583: }
584:
585: // Update dialog
586: updateDialog();
587:
588: return;
589: }
590:
591: }
592:
593: // set working form
594: Assert.fail("No form with a submit button named '" + buttonName
595: + "' and value '" + value + "' was found.");
596: }
597:
598: protected WebClient updateDialog() {
599: WebClient wc;
600: try {
601: wc = (WebClient) PrivateAccessor
602: .getField(getDialog(), "wc");
603: } catch (Throwable e) {
604: logger.error("Could not get WebClient in HttpUnit dialog.",
605: e);
606: throw new RuntimeException("Check your HttpUnit version!\n"
607: + ExceptionUtility.stackTraceToString(e));
608: }
609:
610: WebResponse currentPage = wc.getCurrentPage();
611: try {
612: PrivateAccessor.setField(getDialog(), "resp", currentPage);
613: } catch (Throwable e) {
614: logger.error(
615: "Could not set currentPage in HttpUnit dialog.", e);
616: throw new RuntimeException("Check your HttpUnit version!\n"
617: + ExceptionUtility.stackTraceToString(e));
618: }
619: return wc;
620: }
621:
622: }
|