View Javadoc

1   /**
2    * Copyright 2004-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.hr.util;
17  
18  import java.io.File;
19  import java.io.FileOutputStream;
20  import java.io.StringReader;
21  import java.net.URL;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.apache.log4j.Logger;
30  import org.junit.Assert;
31  import org.kuali.kpme.core.util.HrTestConstants;
32  import org.kuali.rice.core.api.config.property.ConfigContext;
33  import org.w3c.dom.NamedNodeMap;
34  import org.w3c.dom.Node;
35  
36  import com.gargoylesoftware.htmlunit.WebClient;
37  import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
38  import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
39  import com.gargoylesoftware.htmlunit.html.HtmlElement;
40  import com.gargoylesoftware.htmlunit.html.HtmlFileInput;
41  import com.gargoylesoftware.htmlunit.html.HtmlForm;
42  import com.gargoylesoftware.htmlunit.html.HtmlHiddenInput;
43  import com.gargoylesoftware.htmlunit.html.HtmlInput;
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.HtmlSubmitInput;
48  import com.gargoylesoftware.htmlunit.html.HtmlTextArea;
49  import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
50  
51  public class HtmlUnitUtil {
52      private static final Logger LOG = Logger.getLogger(HtmlUnitUtil.class);
53  
54      /**
55       * 
56       * @param url
57       * @return htmlpage without js enabled
58       * @throws Exception
59       */
60      public static HtmlPage gotoPageAndLogin(WebClient webClient, String url) throws Exception {
61      	return gotoPageAndLogin(webClient, url, false);
62      }
63      
64      /**
65       * 
66       * @param url
67       * @param enableJavascript
68       * @return htmlpage with js enabled
69       * @throws Exception
70       */
71      public static HtmlPage gotoPageAndLogin(WebClient webClient, String url, boolean enableJavascript) throws Exception {
72      	LOG.debug("URL: " + url);
73  
74      	// this is required and needs to set to true, otherwise the values set by the onClick event won't be triggered, e.g. methodToCall
75          webClient.getOptions().setJavaScriptEnabled(enableJavascript);
76      	return (HtmlPage) webClient.getPage(new URL(url));
77      }
78  
79      public static boolean pageContainsText(HtmlPage page, String text) {
80  	return page.asText().indexOf(text) >= 0;
81      }
82  
83  	/**
84  	 *
85  	 * @param page: current html page
86  	 * @param criteria: The key is the field name and the value is a string array which contains the field value and the field type which can be chosen from TkTestConstants
87  	 * @return HtmlPage resultPage
88  	 * @throws Exception
89  	 */
90  	public static HtmlPage fillOutForm(HtmlPage page, Map<String, Object> criteria) throws Exception {
91  		HtmlForm lookupForm = HtmlUnitUtil.getDefaultForm(page);
92  		String formFieldPrefix = "";
93  		HtmlPage resultPage = null;
94  		HtmlSelect select = null;
95  		HtmlInput input = null;
96  		HtmlCheckBoxInput checkBox = null;
97  		HtmlTextArea textArea = null;
98  
99  
100 		// Common class of both HtmlInput and HtmlTextArea -- since either of these can appear
101 		// on a web-form.
102 		HtmlElement htmlBasicInput = null;
103 
104 		Set<Map.Entry<String, Object>> entries = criteria.entrySet();
105 		Iterator<Map.Entry<String, Object>> it = entries.iterator();
106 
107 		while (it.hasNext()) {
108 			Map.Entry<String,Object> entry = it.next();
109 
110 			// if the field type is not <input>
111 			if(entry.getValue() instanceof String[]) {
112 				String key = Arrays.asList((String[])entry.getValue()).get(0).toString();
113 				String value = Arrays.asList((String[])entry.getValue()).get(1).toString();
114 
115 				// drop-down
116 				if(key.equals(HrTestConstants.FormElementTypes.DROPDOWN)) {
117 
118 					try {
119 						select = (HtmlSelect) lookupForm.getSelectByName(formFieldPrefix  + entry.getKey());
120 					} catch (Exception e) {
121 						select = (HtmlSelect) lookupForm.getElementById(formFieldPrefix  + entry.getKey());
122 					}
123                    //  try to get a useful option, other than the typical blank default, by getting the last option
124                    //  if the size of the options list is zero, then there is a problem. might as well error here with an array out of bounds.
125                    resultPage = (HtmlPage) select.getOption(select.getOptionSize()-1).setSelected(true);
126                    HtmlUnitUtil.createTempFile(resultPage);
127                }
128 				// check box
129 				else if(key.equals(HrTestConstants.FormElementTypes.CHECKBOX)) {
130 					try {
131 					  checkBox = page.getHtmlElementById(formFieldPrefix  + entry.getKey());
132 					}
133 					catch(Exception e) {
134 						checkBox = page.getElementByName(formFieldPrefix  + entry.getKey());
135 					}
136 					resultPage = (HtmlPage) checkBox.setChecked(Boolean.parseBoolean(value));
137 				}
138 				// text area
139 				else if(key.equals(HrTestConstants.FormElementTypes.TEXTAREA)) {
140 					try {
141 					   textArea = page.getHtmlElementById(formFieldPrefix  + entry.getKey());
142 					} catch (Exception e){
143 						textArea = page.getElementByName(formFieldPrefix  + entry.getKey());
144 					}
145 					textArea.setText(Arrays.asList((String[])entry.getValue()).get(1).toString());
146 				}
147 			} else {
148 				try {
149 					htmlBasicInput = page.getHtmlElementById(formFieldPrefix + entry.getKey());
150 					if (htmlBasicInput instanceof HtmlTextArea) {
151 						textArea = (HtmlTextArea)htmlBasicInput;
152 						textArea.setText(entry.getValue().toString());
153 						resultPage = (HtmlPage) textArea.getPage();
154 					} else if (htmlBasicInput instanceof HtmlInput) {
155 						input = (HtmlInput)htmlBasicInput;
156 						resultPage = (HtmlPage) input.setValueAttribute(entry.getValue().toString());
157 					} else {
158 						LOG.error("Request to populate a non-input html form field.");
159 					}
160 				} catch (Exception e) {
161 					htmlBasicInput = page.getElementByName(formFieldPrefix + entry.getKey());
162 
163 					if (htmlBasicInput instanceof HtmlTextArea) {
164 						textArea = (HtmlTextArea)htmlBasicInput;
165 						textArea.setText(entry.getValue().toString());
166 						resultPage = (HtmlPage) textArea.getPage();
167 					} else if (htmlBasicInput instanceof HtmlInput) {
168 						input = (HtmlInput)htmlBasicInput;
169 						resultPage = (HtmlPage) input.setValueAttribute(entry.getValue().toString());
170 					} else {
171 						LOG.error("Request to populate a non-input html form field.");
172 					}
173 				}
174 			}
175 		}
176 		HtmlUnitUtil.createTempFile(resultPage);
177 		return resultPage;
178 	}
179 	
180    /**
181     * Method to obtain the HREF onclick='' value from the button when
182     * the client side typically processes the request.
183     * @param button
184     */
185    public static String getOnClickHref(HtmlElement button) {
186        NamedNodeMap attributes = button.getAttributes();
187        Node node = attributes.getNamedItem("onclick");
188 
189        //location.href='TimesheetSubmit.do?action=R&documentId=2000&methodToCall=approveTimesheet'
190        String hrefRaw = node.getNodeValue();
191        int sidx = hrefRaw.indexOf("='");
192 
193        return hrefRaw.substring(sidx+2, hrefRaw.length() - 1);
194    }
195 	/**
196 	 *
197 	 * @param page: current html page //NOTE doesnt seem to work currently for js setting of form variables
198 	 * @param name: the button name
199 	 * @return
200 	 * @throws Exception
201 	 */
202 	public static HtmlPage clickButton(HtmlPage page, String name) throws Exception {
203 		HtmlForm form = HtmlUnitUtil.getDefaultForm(page);
204 		HtmlSubmitInput input = form.getInputByName(name);
205 		return (HtmlPage) input.click();
206 	}
207 	
208 	public static HtmlPage clickClockInOrOutButton(HtmlPage page) throws Exception {
209 		HtmlForm form = HtmlUnitUtil.getDefaultForm(page);
210 		
211 		HtmlSubmitInput input = form.getInputByName("clockAction");
212 		form.getInputByName("methodToCall").setValueAttribute("clockAction");
213 		return (HtmlPage) input.click();
214 	}
215 	
216 	public static HtmlPage clickLunchInOrOutButton(HtmlPage page, String lunchAction) throws Exception {
217 		HtmlForm form = HtmlUnitUtil.getDefaultForm(page);
218 		
219 		HtmlSubmitInput input = null;
220 		if(lunchAction.equals("LO")) {
221 			input = form.getInputByName("lunchOut");
222 		}
223 		else if(lunchAction.equals("LI")) {
224 			input = form.getInputByName("lunchIn");
225 		}
226 		form.getInputByName("methodToCall").setValueAttribute("clockAction");
227 		form.getInputByName("currentClockAction").setValueAttribute(lunchAction);
228 		return (HtmlPage) input.click();
229 	}
230     
231 	public static HtmlPage clickInputContainingText(HtmlPage page, String...values) throws Exception {
232 		page = (HtmlPage)getInputContainingText(page, values).click();
233 		return page;
234 	}
235 
236     public static HtmlInput getInputContainingText(HtmlPage page, String... values) throws Exception {
237 		List<HtmlForm> forms = page.getForms();
238 		for (HtmlForm form : forms){
239 			for(HtmlElement element : form.getHtmlElementDescendants()) {
240 				if (element instanceof HtmlInput) {
241 					if (elementContainsValues(element, values)) {
242 						return (HtmlInput)element;
243 					}
244 				}
245 			}
246 		}
247 		return null;
248 	}
249 
250 	public final static void setFieldValue(HtmlPage page, String fieldId, String fieldValue) {
251 	    HtmlElement element = page.getHtmlElementById(fieldId);
252 	    Assert.assertTrue("element " + fieldId + " is null, page: " + page.asText(), element != null);
253 	
254 	    if (element instanceof HtmlTextInput) {
255 	        HtmlTextInput textField = (HtmlTextInput) element;
256 	        textField.setValueAttribute(fieldValue);
257 	    } else if (element instanceof HtmlTextArea) {
258 	        HtmlTextArea textAreaField = (HtmlTextArea) element;
259 	        textAreaField.setText(fieldValue);
260 	    } else if (element instanceof HtmlHiddenInput) {
261 	        HtmlHiddenInput hiddenField = (HtmlHiddenInput) element;
262 	        hiddenField.setValueAttribute(fieldValue);
263 	    } else if (element instanceof HtmlSelect) {
264 	        HtmlSelect selectField = (HtmlSelect) element;
265 	        try {
266 	            selectField.setSelectedAttribute(fieldValue, true);
267 	        } catch (IllegalArgumentException e) {
268 	            Assert.fail("select element [" + element.asText() + "] " + e.getMessage());
269 	        }
270 	    } else if (element instanceof HtmlCheckBoxInput) {
271 	        HtmlCheckBoxInput checkboxField = (HtmlCheckBoxInput) element;
272 	        if (fieldValue.equals("on")) {
273 	            checkboxField.setChecked(true);
274 	        } else if (fieldValue.equals("off")) {
275 	            checkboxField.setChecked(false);
276 	        } else {
277 	        	Assert.assertTrue("Invalid checkbox value", false);
278 	        }
279 	    } else if (element instanceof HtmlFileInput) {
280 	        HtmlFileInput fileInputField = (HtmlFileInput) element;
281 	        fileInputField.setValueAttribute(fieldValue);
282 	    } else if (element instanceof HtmlRadioButtonInput) {
283 	    	HtmlRadioButtonInput radioButton = (HtmlRadioButtonInput) element;
284 	    	if (fieldValue.equals("on")) {
285 	    		radioButton.setChecked(true);
286 	    	} else if (fieldValue.equals("off")) {
287 	    		radioButton.setChecked(false);
288 	    	}
289 	    } else {
290 	    	Assert.fail("Unknown control field: " + fieldId);
291 	    }
292 	}
293     
294     
295     public static List<HtmlInput> getInputsContainingText(HtmlPage page, String... values) throws Exception {
296 		List<HtmlInput> inputs = new ArrayList<HtmlInput>();
297 		List<HtmlForm> forms = page.getForms();
298 		for (HtmlForm form : forms){
299 
300 			for(HtmlElement element : form.getHtmlElementDescendants()) {
301 				if (element instanceof HtmlInput) {
302 					if (elementContainsValues(element, values)) {
303 						inputs.add((HtmlInput)element);
304 					}
305 				}
306 			}
307 		}
308 		return inputs;
309 	}
310 
311 	protected static boolean elementContainsValues(HtmlElement element, String... values) {
312 		for (String value : values) {
313 			if (element.toString().indexOf(value) == -1) {
314 				return false;
315 			}
316         }
317 		return true;
318 	}
319 
320 	public static HtmlPage clickAnchorContainingText(HtmlPage page, String... values) throws Exception {
321 		return (HtmlPage) getAnchorContainingText(page, values).click();
322 	}
323 
324 	@SuppressWarnings("unchecked")
325 	public static HtmlAnchor getAnchorContainingText(HtmlPage page, String... values) throws Exception {
326 		for (Iterator iterator = page.getAnchors().iterator(); iterator.hasNext();) {
327 			HtmlAnchor anchor = (HtmlAnchor) iterator.next();
328 			if (elementContainsValues(anchor, values)) {
329 				return anchor;
330 			}
331 		}
332 		return null;
333 	}
334 
335     public static void createTempFile(HtmlPage page) throws Exception {
336 	createTempFile(page, null);
337     }
338 
339     public static void createTempFile(HtmlPage page, String name) throws Exception {
340 	name = name == null ? "TestOutput" : name;
341 	File temp = File.createTempFile(name, ".html", new File(ConfigContext.getCurrentContextConfig().getProperty("temp.dir")));
342 	FileOutputStream fos = new FileOutputStream(temp);
343 	String xml = page.asXml();
344 	StringReader xmlReader = new StringReader(xml);
345 	int i;
346 	while ((i = xmlReader.read()) != -1) {
347 	    fos.write(i);
348 	}
349 	try {
350 	    fos.close();
351 	} catch (Exception e) {
352 	}
353 	try {
354 	    xmlReader.close();
355 	} catch (Exception e) {
356 	}
357     }
358 
359     public static HtmlInput getInputContainingText(HtmlForm form, String text) throws Exception {
360 
361 		for (HtmlElement element : form.getHtmlElementDescendants()) {
362 			if (element instanceof HtmlInput) {
363 				HtmlInput i = (HtmlInput) element;
364 				if (element.toString().contains(text)) {
365 					return i;
366 				}
367 			}
368 
369 		}
370 		return null;
371     }
372     
373 	public static HtmlForm getDefaultForm(HtmlPage htmlPage) {
374 		if (htmlPage.getForms().size() == 1) {
375 			return (HtmlForm)htmlPage.getForms().get(0);
376 		}
377 		return (HtmlForm)htmlPage.getForms().get(1);
378 	}
379 
380 }