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

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