// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.plugin.html.commands; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import de.ugoe.cs.autoquest.CommandHelpers; import de.ugoe.cs.autoquest.SequenceInstanceOf; import de.ugoe.cs.autoquest.eventcore.Event; import de.ugoe.cs.autoquest.eventcore.IEventTarget; import de.ugoe.cs.autoquest.eventcore.gui.KeyPressed; import de.ugoe.cs.autoquest.eventcore.gui.MouseButtonInteraction.Button; import de.ugoe.cs.autoquest.eventcore.gui.MouseClick; import de.ugoe.cs.autoquest.eventcore.gui.TextInput; import de.ugoe.cs.autoquest.keyboardmaps.VirtualKey; import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLDocument; import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLGUIElement; import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLPageElement; import de.ugoe.cs.util.console.Command; import de.ugoe.cs.util.console.Console; import de.ugoe.cs.util.console.GlobalDataContainer; /** * create XHTML files for Selenium from sequences * * @author Xiaowei Wang * @version 1.0 */ public class CMDgenerateSeleniumReplay implements Command { /* * (non-Javadoc) * * @see de.ugoe.cs.util.console.Command#run(java.util.List) */ @SuppressWarnings("unchecked") @Override public void run(List parameters) { String sequencesName = "sequences"; String folder = null; String baseURL = null; // default try { if (parameters.size() == 2) { folder = (String) parameters.get(0); baseURL = (String) parameters.get(1); } else if (parameters.size() == 3) { sequencesName = (String) parameters.get(0); folder = (String) parameters.get(1); baseURL = (String) parameters.get(2); } else { throw new IllegalArgumentException("The command needs two or three parameters."); } if (!(new File(folder).isDirectory())) { throw new IllegalArgumentException("HTML files folder path: " + folder + " is invalid."); } // validate the basic URL // HttpURLConnection.setFollowRedirects(false); HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(baseURL).openConnection(); httpURLConnection.setRequestMethod("HEAD"); if (!(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK)) { throw new IllegalArgumentException("Website basic URL: " + baseURL + " is invalid."); } } catch (SecurityException se) { throw new IllegalArgumentException("Parameters are invalid"); } catch (MalformedURLException mue) { throw new IllegalArgumentException("Website basic URL: " + baseURL + " is invalid."); } catch (IOException e) { throw new IllegalArgumentException(e); } try { List> sequences = null; Object dataObject = GlobalDataContainer.getInstance().getData(sequencesName); if (dataObject == null) { CommandHelpers.objectNotFoundMessage(sequencesName); return; } if (!SequenceInstanceOf.isCollectionOfSequences(dataObject)) { CommandHelpers.objectNotType(sequencesName, "Collection>>"); return; } sequences = (List>) dataObject; String command = null; String target = null; String value = null; for (int seqsIndex = 0; seqsIndex < sequences.size(); seqsIndex++) { LinkedList> attributeList = new LinkedList>(); List sequence = sequences.get(seqsIndex); Event firstEvent = sequence.get(0); HTMLGUIElement htmlGUIElement = (HTMLGUIElement) firstEvent.getTarget(); while (!(htmlGUIElement instanceof HTMLDocument)) { // the first target must be a // page htmlGUIElement = (HTMLGUIElement) (htmlGUIElement.getParent()); } command = "open"; target = ((HTMLDocument) htmlGUIElement).getPath(); value = ""; addToAttrList(attributeList, command, target, value); for (int seqIndex = 1; seqIndex < sequence.size(); seqIndex++) { Event event = sequence.get(seqIndex); target = getXpath(event.getTarget()); // Login button is global, must await the last page to load // otherwise, will lead to wrong page after logging in if (target.equals("//ul[@id='navlist2']/li[2]/a") && (attributeList.size() > 1) && !attributeList.getLast().get("command").endsWith("AndWait")) { attributeList.getLast().put("command", attributeList.getLast().get("command") + "AndWait"); } if (event.getType() instanceof MouseClick && (((MouseClick) event.getType()).getButton() == Button.LEFT || ((MouseClick) event .getType()).getButton() == Button.MIDDLE)) { command = "click"; String precedingCommand = "waitForElementPresent"; value = ""; addToAttrList(attributeList, precedingCommand, target, value); } else if (event.getType() instanceof TextInput) { command = "type"; value = ((TextInput) event.getType()).getEnteredText(); // if the session contains login process, // the session must log out at beginning if (target .equals("//form[@id='user-login']/div/div/input[@id='edit-name']") && !attributeList.get(0).get("target").equals("/user/logout")) { addToAttrList(attributeList, "open", "/user/logout", "", 0); } } else if (event.getType() instanceof KeyPressed) { command = "sendKeys"; VirtualKey pressedKey = ((KeyPressed) event.getType()).getKey(); switch (pressedKey) { case ENTER: value = "${KEY_ENTER}"; break; case TAB: value = "${KEY_TAB}"; } } else {// Scroll or KeyboardFocusChange or else continue; } addToAttrList(attributeList, command, target, value); } if (attributeList.size() > 0) { createHTML(folder, "session-" + seqsIndex + ".html", baseURL, attributeList, "UTF-8"); } else { // the sequence has no action continue; } } } catch (Exception e) { Console.printerrln("Error on running the command."); e.printStackTrace(); } } /** * create event files in HTML with Selenium IDE template * * @param HTMLFolder * @param fileName * @param attributeList */ private void createHTML(String HTMLFolder, String fileName, String baseURL, List> attributeList, String encoding) { String htmlStr = "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "${name}\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n"; htmlStr = htmlStr.replace("${encoding}", encoding); htmlStr = htmlStr.replace("${baseURL}", baseURL); htmlStr = htmlStr.replace("${name}", fileName.replace(".html", "")); for (Map commandMap : attributeList) { htmlStr = htmlStr + "\n" + "\t\n" + "\t\n" + "\t\n" + "\n"; } String fileEnding = "
${name}
" + commandMap.get("command") + "" + commandMap.get("target") + "" + commandMap.get("value") + "
\n\n"; htmlStr = htmlStr + fileEnding; try { File newHtmlFile = new File(HTMLFolder + System.getProperty("file.separator") + fileName); BufferedWriter bw = new BufferedWriter(new FileWriter(newHtmlFile)); bw.write(htmlStr); bw.flush(); bw.close(); } catch (Exception e) { Console.printerrln("Error on creating xhtml files."); e.printStackTrace(); } } /** * add an event to the event list * * @param attributeList * @param command * @param target * @param value * */ private void addToAttrList(LinkedList> attributeList, String command, String target, String value) { Map ctvMap = new HashMap(); ctvMap.put("command", command); ctvMap.put("target", target); ctvMap.put("value", value); attributeList.add(ctvMap); } private void addToAttrList(LinkedList> attributeList, String command, String target, String value, int position) { Map ctvMap = new HashMap(); ctvMap.put("command", command); ctvMap.put("target", target); ctvMap.put("value", value); attributeList.add(position, ctvMap); } /** * * @param iEventTarget * @return the relative xpath */ private String getXpath(IEventTarget iEventTarget) { HTMLGUIElement htmlGUIElement = (HTMLGUIElement) iEventTarget; List xpathElements = new LinkedList(); String htmlId = null; int htmlIndex = 0; // obtain the relative xpath of the element while (!(htmlGUIElement instanceof HTMLDocument)) { HTMLPageElement htmlPageElement = (HTMLPageElement) htmlGUIElement; StringBuffer xpathElement = new StringBuffer(); // the real tag is "input" without _* xpathElement.append(htmlPageElement.getTagName().replace("input_text", "input") .replace("input_password", "input").replace("input_submit", "input")); // better not use absolute xpath, // Selenium IDE specifies only the // 1st tag's id, if it's not the only tag if ((htmlId = htmlPageElement.getHtmlId()) != null) { xpathElement.append("[@id='"); xpathElement.append(htmlId); xpathElement.append("']"); xpathElements.add(0, xpathElement.toString()); // the xpath must have more then one tag with id // but the Selenium IDE uses only the 1st one // which is enough for finding out the element if (xpathElements.size() > 1) { break; } } else if ((htmlIndex = htmlPageElement.getIndex()) != 0) { xpathElement.append("["); // find element by xpath, index starts from 1, not 0 xpathElement.append(htmlIndex + 1); xpathElement.append("]"); xpathElements.add(0, xpathElement.toString()); } else { // if the index is 0, only add tag xpathElements.add(0, xpathElement.toString()); } htmlGUIElement = (HTMLGUIElement) (htmlGUIElement.getParent()); } StringBuffer xPathStatement = new StringBuffer(); xPathStatement.append("/"); for (String xpathElem : xpathElements) { xPathStatement.append("/"); xPathStatement.append(xpathElem); } return xPathStatement.toString(); } /* * (non-Javadoc) * * @see de.ugoe.cs.util.console.Command#help() */ @Override public String help() { return "generateSeleniumReplay [sequenceName] "; } }