source: trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDgenerateSeleniumReplay.java @ 2029

Last change on this file since 2029 was 2029, checked in by xwang, 9 years ago
File size: 14.8 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.plugin.html.commands;
16
17import java.io.BufferedWriter;
18import java.io.File;
19import java.io.FileWriter;
20import java.io.IOException;
21import java.net.HttpURLConnection;
22import java.net.MalformedURLException;
23import java.net.URL;
24import java.util.HashMap;
25import java.util.LinkedList;
26import java.util.List;
27import java.util.Map;
28import de.ugoe.cs.autoquest.CommandHelpers;
29import de.ugoe.cs.autoquest.SequenceInstanceOf;
30import de.ugoe.cs.autoquest.eventcore.Event;
31import de.ugoe.cs.autoquest.eventcore.IEventTarget;
32import de.ugoe.cs.autoquest.eventcore.gui.KeyPressed;
33import de.ugoe.cs.autoquest.eventcore.gui.MouseButtonInteraction.Button;
34import de.ugoe.cs.autoquest.eventcore.gui.MouseClick;
35import de.ugoe.cs.autoquest.eventcore.gui.TextInput;
36import de.ugoe.cs.autoquest.keyboardmaps.VirtualKey;
37import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLDocument;
38import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLGUIElement;
39import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLPageElement;
40import de.ugoe.cs.util.console.Command;
41import de.ugoe.cs.util.console.Console;
42import de.ugoe.cs.util.console.GlobalDataContainer;
43
44/**
45 * create XHTML files for Selenium from sequences
46 *
47 * @author Xiaowei Wang
48 * @version 1.0
49 */
50public class CMDgenerateSeleniumReplay implements Command {
51    /*
52     * (non-Javadoc)
53     *
54     * @see de.ugoe.cs.util.console.Command#run(java.util.List)
55     */
56    @SuppressWarnings("unchecked")
57    @Override
58    public void run(List<Object> parameters) {
59        String sequencesName = "sequences";
60        String folder = null;
61        String baseURL = null; // default
62        try {
63            if (parameters.size() == 2) {
64                folder = (String) parameters.get(0);
65                baseURL = (String) parameters.get(1);
66            }
67            else if (parameters.size() == 3) {
68                sequencesName = (String) parameters.get(0);
69                folder = (String) parameters.get(1);
70                baseURL = (String) parameters.get(2);
71            }
72            else {
73                throw new IllegalArgumentException("The command needs two or three parameters.");
74            }
75
76            if (!(new File(folder).isDirectory())) {
77                throw new IllegalArgumentException("HTML files folder path: " + folder +
78                    " is invalid.");
79            }
80            // validate the basic URL
81            // HttpURLConnection.setFollowRedirects(false);
82            HttpURLConnection httpURLConnection =
83                (HttpURLConnection) new URL(baseURL).openConnection();
84            httpURLConnection.setRequestMethod("HEAD");
85            if (!(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK)) {
86                throw new IllegalArgumentException("Website basic URL: " + baseURL + " is invalid.");
87            }
88        }
89        catch (SecurityException se) {
90            throw new IllegalArgumentException("Parameters are invalid");
91        }
92        catch (MalformedURLException mue) {
93            throw new IllegalArgumentException("Website basic URL: " + baseURL + " is invalid.");
94        }
95        catch (IOException e) {
96            throw new IllegalArgumentException(e);
97        }
98
99        try {
100            List<List<Event>> sequences = null;
101            Object dataObject = GlobalDataContainer.getInstance().getData(sequencesName);
102            if (dataObject == null) {
103                CommandHelpers.objectNotFoundMessage(sequencesName);
104                return;
105            }
106            if (!SequenceInstanceOf.isCollectionOfSequences(dataObject)) {
107                CommandHelpers.objectNotType(sequencesName, "Collection<List<Event<?>>>");
108                return;
109            }
110            sequences = (List<List<Event>>) dataObject;
111
112            String command = null;
113            String target = null;
114            String value = null;
115            for (int seqsIndex = 0; seqsIndex < sequences.size(); seqsIndex++) {
116                LinkedList<Map<String, String>> attributeList =
117                    new LinkedList<Map<String, String>>();
118                List<Event> sequence = sequences.get(seqsIndex);
119                Event firstEvent = sequence.get(0);
120                HTMLGUIElement htmlGUIElement = (HTMLGUIElement) firstEvent.getTarget();
121                while (!(htmlGUIElement instanceof HTMLDocument)) { // the first target must be a
122                                                                    // page
123                    htmlGUIElement = (HTMLGUIElement) (htmlGUIElement.getParent());
124                }
125                command = "open";
126                target = ((HTMLDocument) htmlGUIElement).getPath();
127                value = "";
128                addToAttrList(attributeList, command, target, value);
129
130                for (int seqIndex = 1; seqIndex < sequence.size(); seqIndex++) {
131                    Event event = sequence.get(seqIndex);
132                    target = getXpath(event.getTarget());
133                    // Login button is global, must await the last page to load
134                    // otherwise, will lead to wrong page after logging in
135                    if (target.equals("//ul[@id='navlist2']/li[2]/a") &&
136                        (attributeList.size() > 1) &&
137                        !attributeList.getLast().get("command").endsWith("AndWait"))
138                    {
139                        attributeList.getLast().put("command",
140                                                    attributeList.getLast().get("command") +
141                                                        "AndWait");
142                    }
143
144                    if (event.getType() instanceof MouseClick &&
145                        (((MouseClick) event.getType()).getButton() == Button.LEFT || ((MouseClick) event
146                            .getType()).getButton() == Button.MIDDLE))
147                    {
148                        command = "click";
149                        String precedingCommand = "waitForElementPresent";
150                        value = "";
151                        addToAttrList(attributeList, precedingCommand, target, value);
152                    }
153                    else if (event.getType() instanceof TextInput) {
154                        command = "type";
155                        value = ((TextInput) event.getType()).getEnteredText();
156                        // if the session contains login process,
157                        // the session must log out at beginning
158                        if (target
159                            .equals("//form[@id='user-login']/div/div/input[@id='edit-name']") &&
160                            !attributeList.get(0).get("target").equals("/user/logout"))
161                        {
162                            addToAttrList(attributeList, "open", "/user/logout", "", 0);
163                        }
164                    }
165                    else if (event.getType() instanceof KeyPressed) {
166                        command = "sendKeys";
167                        VirtualKey pressedKey = ((KeyPressed) event.getType()).getKey();
168                        switch (pressedKey)
169                        {
170                            case ENTER:
171                                value = "${KEY_ENTER}";
172                                break;
173                            case TAB:
174                                value = "${KEY_TAB}";
175                        }
176                    }
177                    else {// Scroll or KeyboardFocusChange or else
178                        continue;
179                    }
180                    addToAttrList(attributeList, command, target, value);
181                }
182
183                if (attributeList.size() > 0) {
184                    createHTML(folder, "session-" + seqsIndex + ".html", baseURL, attributeList,
185                               "UTF-8");
186                }
187                else { // the sequence has no action
188                    continue;
189                }
190            }
191        }
192        catch (Exception e) {
193            Console.printerrln("Error on running the command.");
194            e.printStackTrace();
195        }
196    }
197
198    /**
199     * create event files in HTML with Selenium IDE template
200     *
201     * @param HTMLFolder
202     * @param fileName
203     * @param attributeList
204     */
205    private void createHTML(String HTMLFolder,
206                            String fileName,
207                            String baseURL,
208                            List<Map<String, String>> attributeList,
209                            String encoding)
210    {
211
212        String htmlStr =
213            "<?xml version=\"1.0\" encoding=\"${encoding}\"?>\n"
214                + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
215                + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
216                + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
217                + "<head profile=\"http://selenium-ide.openqa.org/profiles/test-case\">\n"
218                + "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=${encoding}\" />\n"
219                + "<link rel=\"selenium.base\" href=\"${baseURL}\" />\n"
220                + "<title>${name}</title>\n" + "</head>\n" + "<body>\n"
221                + "<table cellpadding=\"1\" cellspacing=\"1\" border=\"1\">\n" + "<thead>\n"
222                + "<tr><td rowspan=\"1\" colspan=\"3\">${name}</td></tr>\n" + "</thead><tbody>\n";
223        htmlStr = htmlStr.replace("${encoding}", encoding);
224        htmlStr = htmlStr.replace("${baseURL}", baseURL);
225        htmlStr = htmlStr.replace("${name}", fileName.replace(".html", ""));
226        for (Map<String, String> commandMap : attributeList) {
227            htmlStr =
228                htmlStr + "<tr>\n" + "\t<td>" + commandMap.get("command") + "</td>\n" + "\t<td>" +
229                    commandMap.get("target") + "</td>\n" + "\t<td>" + commandMap.get("value") +
230                    "</td>\n" + "</tr>\n";
231        }
232
233        String fileEnding = "</tbody></table>\n</body>\n</html>";
234        htmlStr = htmlStr + fileEnding;
235        try {
236            File newHtmlFile =
237                new File(HTMLFolder + System.getProperty("file.separator") + fileName);
238            BufferedWriter bw = new BufferedWriter(new FileWriter(newHtmlFile));
239            bw.write(htmlStr);
240            bw.flush();
241            bw.close();
242        }
243        catch (Exception e) {
244            Console.printerrln("Error on creating xhtml files.");
245            e.printStackTrace();
246        }
247    }
248
249    /**
250     * add an event to the event list
251     *
252     * @param attributeList
253     * @param command
254     * @param target
255     * @param value
256     *
257     */
258    private void addToAttrList(LinkedList<Map<String, String>> attributeList,
259                               String command,
260                               String target,
261                               String value)
262    {
263        Map<String, String> ctvMap = new HashMap<String, String>();
264        ctvMap.put("command", command);
265        ctvMap.put("target", target);
266        ctvMap.put("value", value);
267        attributeList.add(ctvMap);
268    }
269
270    private void addToAttrList(LinkedList<Map<String, String>> attributeList,
271                               String command,
272                               String target,
273                               String value,
274                               int position)
275    {
276        Map<String, String> ctvMap = new HashMap<String, String>();
277        ctvMap.put("command", command);
278        ctvMap.put("target", target);
279        ctvMap.put("value", value);
280        attributeList.add(position, ctvMap);
281    }
282
283    /**
284     *
285     * @param iEventTarget
286     * @return the relative xpath
287     */
288    private String getXpath(IEventTarget iEventTarget) {
289        HTMLGUIElement htmlGUIElement = (HTMLGUIElement) iEventTarget;
290        List<String> xpathElements = new LinkedList<String>();
291        String htmlId = null;
292        int htmlIndex = 0;
293
294        // obtain the relative xpath of the element
295        while (!(htmlGUIElement instanceof HTMLDocument)) {
296            HTMLPageElement htmlPageElement = (HTMLPageElement) htmlGUIElement;
297            StringBuffer xpathElement = new StringBuffer();
298            // the real tag is "input" without _*
299            xpathElement.append(htmlPageElement.getTagName().replace("input_text", "input")
300                .replace("input_password", "input").replace("input_submit", "input"));
301            // better not use absolute xpath,
302            // Selenium IDE specifies only the
303            // 1st tag's id, if it's not the only tag
304            if ((htmlId = htmlPageElement.getHtmlId()) != null) {
305                xpathElement.append("[@id='");
306                xpathElement.append(htmlId);
307                xpathElement.append("']");
308                xpathElements.add(0, xpathElement.toString());
309                // the xpath must have more then one tag with id
310                // but the Selenium IDE uses only the 1st one
311                // which is enough for finding out the element
312                if (xpathElements.size() > 1) {
313                    break;
314                }
315            }
316            else if ((htmlIndex = htmlPageElement.getIndex()) != 0) {
317                xpathElement.append("[");
318                // find element by xpath, index starts from 1, not 0
319                xpathElement.append(htmlIndex + 1);
320                xpathElement.append("]");
321                xpathElements.add(0, xpathElement.toString());
322            }
323            else {
324                // if the index is 0, only add tag
325                xpathElements.add(0, xpathElement.toString());
326            }
327            htmlGUIElement = (HTMLGUIElement) (htmlGUIElement.getParent());
328        }
329
330        StringBuffer xPathStatement = new StringBuffer();
331        xPathStatement.append("/");
332        for (String xpathElem : xpathElements) {
333            xPathStatement.append("/");
334            xPathStatement.append(xpathElem);
335        }
336
337        return xPathStatement.toString();
338    }
339
340    /*
341     * (non-Javadoc)
342     *
343     * @see de.ugoe.cs.util.console.Command#help()
344     */
345    @Override
346    public String help() {
347
348        return "generateSeleniumReplay [sequenceName] <HTMLFilesFolder> <websiteBaseURL>";
349    }
350
351}
Note: See TracBrowser for help on using the repository browser.