Commit f76f0d3e4337dd31db68575d8b13f1f4062f511c
1 parent
5bc796f3
Implemented method for executing ajax re-rendered scripts.
Implemented several tests for ClassDetails.
Showing
8 changed files
with
211 additions
and
14 deletions
| ... | ... | @@ -43,6 +43,17 @@ | 
| 43 | 43 | <optimize>false</optimize> | 
| 44 | 44 | </configuration> | 
| 45 | 45 | </plugin> | 
| 46 | + <plugin> | |
| 47 | + <groupId>org.apache.maven.plugins</groupId> | |
| 48 | + <artifactId>maven-source-plugin</artifactId> | |
| 49 | + <executions> | |
| 50 | + <execution> | |
| 51 | + <goals> | |
| 52 | + <goal>jar</goal> | |
| 53 | + </goals> | |
| 54 | + </execution> | |
| 55 | + </executions> | |
| 56 | + </plugin> | |
| 46 | 57 | |
| 47 | 58 | </plugins> | 
| 48 | 59 | </build> | ... | ... | 
| ... | ... | @@ -7,9 +7,13 @@ import org.apache.commons.logging.Log; | 
| 7 | 7 | import org.apache.commons.logging.LogFactory; | 
| 8 | 8 | import org.w3c.dom.Node; | 
| 9 | 9 | |
| 10 | +import java.util.HashSet; | |
| 11 | +import java.util.Set; | |
| 12 | + | |
| 10 | 13 | public class DomChangeLogger implements DomChangeListener { | 
| 11 | 14 | |
| 12 | 15 | private static final Log LOG = LogFactory.getLog(DomChangeLogger.class); | 
| 16 | + private Set<String> detailIds = new HashSet<String>(); | |
| 13 | 17 | |
| 14 | 18 | public void nodeAdded(DomChangeEvent event) { | 
| 15 | 19 | logEvent(event, "added"); | 
| ... | ... | @@ -19,6 +23,14 @@ public class DomChangeLogger implements DomChangeListener { | 
| 19 | 23 | logEvent(event, "removed"); | 
| 20 | 24 | } | 
| 21 | 25 | |
| 26 | + public void showDetails(String id) { | |
| 27 | + detailIds.add(id); | |
| 28 | + } | |
| 29 | + | |
| 30 | + public void hideDetails(String id) { | |
| 31 | + detailIds.remove(id); | |
| 32 | + } | |
| 33 | + | |
| 22 | 34 | private void logEvent(DomChangeEvent event, String action) { | 
| 23 | 35 | String changed; | 
| 24 | 36 | final DomNode changedNode = event.getChangedNode(); | 
| ... | ... | @@ -36,7 +48,7 @@ public class DomChangeLogger implements DomChangeListener { | 
| 36 | 48 | } | 
| 37 | 49 | LOG.info("DomChangeEvent[action=" + action + ";changedElement=" + changed + ";source=" + event.getSource() + ";parent=" + parent + "]"); | 
| 38 | 50 | final Node id = event.getChangedNode().getAttributes().getNamedItem("id"); | 
| 39 | - if (id != null && "searchClass:searchStudent".equals(id.getTextContent())) { | |
| 51 | + if (id != null && detailIds.contains(id.getTextContent())) { | |
| 40 | 52 | LOG.info(event.getChangedNode().asXml()); | 
| 41 | 53 | } | 
| 42 | 54 | } | ... | ... | 
| 1 | 1 | package pl.labno.bernard.htmlunified; | 
| 2 | 2 | |
| 3 | 3 | import com.gargoylesoftware.htmlunit.WebClient; | 
| 4 | +import com.gargoylesoftware.htmlunit.html.DomNode; | |
| 4 | 5 | import com.gargoylesoftware.htmlunit.html.DomNodeList; | 
| 5 | 6 | import com.gargoylesoftware.htmlunit.html.HtmlElement; | 
| 7 | +import com.gargoylesoftware.htmlunit.html.HtmlPage; | |
| 6 | 8 | import com.gargoylesoftware.htmlunit.html.HtmlTableCell; | 
| 7 | 9 | |
| 10 | +import java.util.ArrayList; | |
| 8 | 11 | import java.util.HashMap; | 
| 12 | +import java.util.List; | |
| 9 | 13 | import java.util.Map; | 
| 10 | 14 | |
| 11 | 15 | public class WebClientUtils { | 
| ... | ... | @@ -29,19 +33,27 @@ public class WebClientUtils { | 
| 29 | 33 | WebClientUtils.defaultTimeout = defaultTimeout; | 
| 30 | 34 | } | 
| 31 | 35 | |
| 32 | - public static int waitForJSJob(WebClient webClient) { | |
| 33 | - return waitForJSJob(webClient, webClient.waitForBackgroundJavaScript(10) - 1); | |
| 36 | + public static int waitForJSJob(String message, WebClient webClient) { | |
| 37 | + return waitForJSJob(message, webClient, webClient.waitForBackgroundJavaScript(10) - 1); | |
| 34 | 38 | } | 
| 35 | 39 | |
| 36 | - public static int waitForJSJob(WebClient webClient, int initialJobCount) { | |
| 37 | - return waitForJSJob(webClient, initialJobCount, defaultTimeout); | |
| 40 | + public static int waitForJSJob(String message, WebClient webClient, int initialJobCount) { | |
| 41 | + return waitForJSJob(message, webClient, initialJobCount, defaultTimeout); | |
| 38 | 42 | } | 
| 39 | 43 | |
| 40 | - public static int waitForJSJob(WebClient webClient, int initialJobCount, long timeout) { | |
| 41 | - return waitForJSJob(webClient, initialJobCount, timeout, defaultCheckInterval); | |
| 44 | + public static int waitForJSJob(WebClient webClient, int initialJobCount, int timeout) { | |
| 45 | + return waitForJSJob(null, webClient, initialJobCount, timeout); | |
| 42 | 46 | } | 
| 43 | 47 | |
| 44 | - public static int waitForJSJob(WebClient webClient, int initialJobCount, long timeout, long checkInterval) { | |
| 48 | + public static int waitForJSJob(String message, WebClient webClient, int initialJobCount, long timeout) { | |
| 49 | + return waitForJSJob(message, webClient, initialJobCount, timeout, defaultCheckInterval); | |
| 50 | + } | |
| 51 | + | |
| 52 | + public static int waitForJSJob(String message, WebClient webClient, int initialJobCount, int timeout) { | |
| 53 | + return waitForJSJob(message, webClient, initialJobCount, timeout, defaultCheckInterval); | |
| 54 | + } | |
| 55 | + | |
| 56 | + public static int waitForJSJob(String message, WebClient webClient, int initialJobCount, long timeout, long checkInterval) { | |
| 45 | 57 | int jobs; | 
| 46 | 58 | long startTime = System.currentTimeMillis(); | 
| 47 | 59 | do { | 
| ... | ... | @@ -50,7 +62,7 @@ public class WebClientUtils { | 
| 50 | 62 | throw new RuntimeException("Number of JavaScript jobs doesn't drop to initial level for " + timeout + " seconds. It's memory leak in your JavaScript rather then request taking so long!"); | 
| 51 | 63 | } | 
| 52 | 64 | } while (jobs > initialJobCount); | 
| 53 | - System.out.println("Waiting took: " + (System.currentTimeMillis() - startTime) + "ms"); | |
| 65 | + System.out.println("Waiting" + (message == null ? "" : " for " + message) + " took: " + (System.currentTimeMillis() - startTime) + "ms"); | |
| 54 | 66 | return jobs; | 
| 55 | 67 | } | 
| 56 | 68 | |
| ... | ... | @@ -88,4 +100,32 @@ public class WebClientUtils { | 
| 88 | 100 | } | 
| 89 | 101 | } while (startTime + timeout > System.currentTimeMillis()); | 
| 90 | 102 | } | 
| 103 | + | |
| 104 | + public static void executeAjaxReRenderedScripts(HtmlPage page) { | |
| 105 | + final DomNodeList<HtmlElement> scripts = page.getElementsByTagName("script"); | |
| 106 | + /** | |
| 107 | + * We cannot iterate over html DomNodeList cause it depends on sibling relationship which we will modify. | |
| 108 | + */ | |
| 109 | + final List<HtmlElement> scriptsList = new ArrayList<HtmlElement>(); | |
| 110 | + for (HtmlElement element : scripts) { | |
| 111 | + scriptsList.add(element); | |
| 112 | + } | |
| 113 | + for (HtmlElement element : scriptsList) { | |
| 114 | + if (element.getChildNodes().size() > 1) { | |
| 115 | + element.removeChild(element.getFirstChild()); | |
| 116 | + final DomNode sibling = element.getNextSibling(); | |
| 117 | + final DomNode parentNode = element.getParentNode(); | |
| 118 | + /** | |
| 119 | + * Script will be executed upon inserting into DOM tree, so we removed and add it again. | |
| 120 | + */ | |
| 121 | + if (sibling != null) { | |
| 122 | + parentNode.removeChild(element); | |
| 123 | + sibling.insertBefore(element); | |
| 124 | + } else { | |
| 125 | + parentNode.removeChild(element); | |
| 126 | + parentNode.appendChild(element); | |
| 127 | + } | |
| 128 | + } | |
| 129 | + } | |
| 130 | + } | |
| 91 | 131 | } | ... | ... | 
| 1 | +package pl.labno.bernard.htmlunified; | |
| 2 | + | |
| 3 | +import com.gargoylesoftware.htmlunit.BrowserVersion; | |
| 4 | +import com.gargoylesoftware.htmlunit.WebClient; | |
| 5 | +import com.gargoylesoftware.htmlunit.html.HtmlElement; | |
| 6 | +import com.gargoylesoftware.htmlunit.html.HtmlInput; | |
| 7 | +import com.gargoylesoftware.htmlunit.html.HtmlPage; | |
| 8 | +import com.gargoylesoftware.htmlunit.html.HtmlSpan; | |
| 9 | +import org.junit.Assert; | |
| 10 | +import org.junit.Test; | |
| 11 | + | |
| 12 | +import java.io.IOException; | |
| 13 | +import java.util.List; | |
| 14 | + | |
| 15 | +public class ClassDetailsTest { | |
| 16 | + | |
| 17 | + @Test | |
| 18 | + public void openDetailsModalPanel() throws IOException { | |
| 19 | + WebClient client = new WebClient(BrowserVersion.FIREFOX_3_6); | |
| 20 | + HtmlPage page = login(client); | |
| 21 | + @SuppressWarnings("unchecked") | |
| 22 | + final List<HtmlSpan> titleElements = (List<HtmlSpan>) page.getElementById("results:schedule").getByXPath(".//span[@class='fc-event-title']"); | |
| 23 | + Assert.assertNotSame(0, titleElements.size()); | |
| 24 | + new RequestResponseLogger(client); | |
| 25 | + page.addDomChangeListener(new DomChangeLogger()); | |
| 26 | + WebClientUtils.waitForJSJob("initial javascript to finish", client, 0, 30000); | |
| 27 | + System.out.println("item:" + titleElements.get(0).asText()); | |
| 28 | + ((HtmlElement) titleElements.get(0).getParentNode()).mouseOver(); | |
| 29 | + ((HtmlElement) titleElements.get(0).getParentNode()).click(); | |
| 30 | + WebClientUtils.waitForJSJob("classDetailsModalPanel shown after schedule event clicked", client, 0, 30000); | |
| 31 | + Assert.assertNotNull(page.getElementById("classDetailsModalPanelContainer")); | |
| 32 | + } | |
| 33 | + | |
| 34 | + @Test | |
| 35 | + public void closeDetailsModalPanel() throws IOException { | |
| 36 | + WebClient client = new WebClient(BrowserVersion.FIREFOX_3_6); | |
| 37 | + HtmlPage page = login(client); | |
| 38 | + @SuppressWarnings("unchecked") | |
| 39 | + final List<HtmlSpan> titleElements = (List<HtmlSpan>) page.getElementById("results:schedule").getByXPath(".//span[@class='fc-event-title']"); | |
| 40 | + Assert.assertNotSame(0, titleElements.size()); | |
| 41 | +// new RequestResponseLogger(client); | |
| 42 | +// page.addDomChangeListener(new DomChangeLogger()); | |
| 43 | + WebClientUtils.waitForJSJob("initial javascript to finish", client, 0, 30000); | |
| 44 | + System.out.println("item:" + titleElements.get(0).asText()); | |
| 45 | + ((HtmlElement) titleElements.get(0).getParentNode()).mouseOver(); | |
| 46 | + ((HtmlElement) titleElements.get(0).getParentNode()).click(); | |
| 47 | + WebClientUtils.waitForJSJob("classDetailsModalPanel shown after schedule event clicked", client, 0, 30000); | |
| 48 | + Assert.assertNotNull(page.getElementById("classDetailsModalPanelContainer")); | |
| 49 | + ((HtmlElement) page.getElementById("classDetailsModalPanelContainer").getByXPath("//*[contains(@src,'close.png')]").get(0)).click(); | |
| 50 | + WebClientUtils.waitForJSJob("classDetailsModalPanel hidden after cancel button", client, 0, 30000); | |
| 51 | + Assert.assertNull(page.getElementById("classDetailsModalPanelContainer")); | |
| 52 | + } | |
| 53 | + | |
| 54 | + @Test | |
| 55 | + public void removeClass() throws IOException { | |
| 56 | + WebClient client = new WebClient(BrowserVersion.FIREFOX_2); | |
| 57 | + final RequestResponseLogger requestResponseLogger = new RequestResponseLogger(client); | |
| 58 | + requestResponseLogger.off(); | |
| 59 | + HtmlPage page = login(client); | |
| 60 | + @SuppressWarnings("unchecked") | |
| 61 | + final List<HtmlSpan> titleElements = (List<HtmlSpan>) page.getElementById("results:schedule").getByXPath(".//span[@class='fc-event-title']"); | |
| 62 | + Assert.assertEquals(6, titleElements.size()); | |
| 63 | + Assert.assertNotSame(0, titleElements.size()); | |
| 64 | + WebClientUtils.waitForJSJob("initial javascript to finish", client, 0, 30000); | |
| 65 | + | |
| 66 | + client.setAlertHandler(new AlertLogger()); | |
| 67 | + final DomChangeLogger domChangeLogger = new DomChangeLogger(); | |
| 68 | + domChangeLogger.showDetails("results:j_id2158"); | |
| 69 | +// page.addDomChangeListener(domChangeLogger); | |
| 70 | +// page.addHtmlAttsributeChangeListener(new HtmlAttributeChangeLogger()); | |
| 71 | +// requestResponseLogger.on(); | |
| 72 | + | |
| 73 | + ((HtmlElement) titleElements.get(0).getParentNode()).mouseOver(); | |
| 74 | + ((HtmlElement) titleElements.get(0).getParentNode()).click(); | |
| 75 | + WebClientUtils.waitForJSJob("classDetailsModalPanel shown after schedule event clicked", client, 0, 30000); | |
| 76 | + WebClientUtils.executeAjaxReRenderedScripts(page); | |
| 77 | + Assert.assertNotNull(page.getElementById("classDetailsModalPanelContainer")); | |
| 78 | + ((HtmlElement) page.getElementById("classDetailsModalPanelContainer").getByXPath("//*[contains(@src,'remove.png')]").get(0)).click(); | |
| 79 | + WebClientUtils.waitForJSJob("classDetailsModalPanel hidden after remove button", client, 0, 30000); | |
| 80 | + WebClientUtils.executeAjaxReRenderedScripts(page); | |
| 81 | + WebClientUtils.waitForJSJob("schedule refresh", client, 0, 30000); | |
| 82 | + Assert.assertNull(page.getElementById("classDetailsModalPanelContainer")); | |
| 83 | + Assert.assertEquals(5, page.getElementById("results:schedule").getByXPath(".//span[@class='fc-event-title']").size()); | |
| 84 | + } | |
| 85 | + | |
| 86 | + private HtmlPage login(WebClient client) throws IOException { | |
| 87 | + HtmlPage page = (HtmlPage) client.getPage("http://localhost:8080/schoolmanager/view/class/current.seam?networkId=salsafactory"); | |
| 88 | + ((HtmlInput) page.getElementById("loginForm:email")).setValueAttribute("it.crowd.test@gmail.com"); | |
| 89 | + ((HtmlInput) page.getElementById("loginForm:password")).setValueAttribute("aaaaa"); | |
| 90 | + HtmlPage oldPage = page; | |
| 91 | + page = page.getElementById("loginForm:submit").click(); | |
| 92 | +// This assert would fail (when page redidrects than you need to obtain new page) | |
| 93 | +// Assert.assertEquals(page,oldPage); | |
| 94 | + Assert.assertEquals(client.getCurrentWindow().getEnclosedPage(), page); | |
| 95 | + return page; | |
| 96 | + } | |
| 97 | +} | ... | ... | 
| 1 | 1 | package pl.labno.bernard.htmlunified; | 
| 2 | 2 | |
| 3 | 3 | import com.gargoylesoftware.htmlunit.BrowserVersion; | 
| 4 | +import com.gargoylesoftware.htmlunit.CollectingAlertHandler; | |
| 4 | 5 | import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController; | 
| 5 | 6 | import com.gargoylesoftware.htmlunit.WebClient; | 
| 6 | 7 | import com.gargoylesoftware.htmlunit.html.HtmlPage; | 
| ... | ... | @@ -8,11 +9,12 @@ import org.junit.Assert; | 
| 8 | 9 | import org.junit.Test; | 
| 9 | 10 | |
| 10 | 11 | import java.io.IOException; | 
| 12 | +import java.util.ArrayList; | |
| 11 | 13 | |
| 12 | 14 | public class SandboxTest { | 
| 13 | 15 | |
| 14 | 16 | @Test | 
| 15 | - public void test() throws IOException { | |
| 17 | + public void testClickImage() throws IOException { | |
| 16 | 18 | final WebClient client = new WebClient(BrowserVersion.FIREFOX_3_6); | 
| 17 | 19 | client.setAjaxController(new NicelyResynchronizingAjaxController()); | 
| 18 | 20 | HtmlPage page = (HtmlPage) client.getPage("file:./target/test-classes/sandbox.html"); | 
| ... | ... | @@ -20,4 +22,23 @@ public class SandboxTest { | 
| 20 | 22 | page.getElementById("close").click(); | 
| 21 | 23 | Assert.assertEquals("", page.getElementById("elementToHide").asText()); | 
| 22 | 24 | } | 
| 25 | + | |
| 26 | + @Test | |
| 27 | + public void testClickJQueryBoundElement() throws IOException { | |
| 28 | + final WebClient client = new WebClient(BrowserVersion.FIREFOX_3_6); | |
| 29 | + client.setAjaxController(new NicelyResynchronizingAjaxController()); | |
| 30 | + HtmlPage page = (HtmlPage) client.getPage("file:./target/test-classes/sandbox.html"); | |
| 31 | + final ArrayList<String> alerts = new ArrayList<String>(); | |
| 32 | + client.setAlertHandler(new CollectingAlertHandler(alerts)); | |
| 33 | + page.getElementById("clickable").click(); | |
| 34 | + System.out.println(alerts); | |
| 35 | + Assert.assertEquals(1, alerts.size()); | |
| 36 | + Assert.assertEquals("Clicked clickable", alerts.get(0)); | |
| 37 | + | |
| 38 | + alerts.clear(); | |
| 39 | + page.getElementById("clickable2child").click(); | |
| 40 | + System.out.println(alerts); | |
| 41 | + Assert.assertEquals(1, alerts.size()); | |
| 42 | + Assert.assertEquals("Clicked clickable2", alerts.get(0)); | |
| 43 | + } | |
| 23 | 44 | } | ... | ... | 
| ... | ... | @@ -30,7 +30,7 @@ public class ScheduleTest { | 
| 30 | 30 | for (HtmlSpan o : titleElements) { | 
| 31 | 31 | titles.add(o.asText()); | 
| 32 | 32 | } | 
| 33 | - Assert.assertEquals(4, titles.size()); | |
| 33 | + Assert.assertEquals(6, titles.size()); | |
| 34 | 34 | } | 
| 35 | 35 | |
| 36 | 36 | @Test | 
| ... | ... | @@ -58,7 +58,6 @@ public class ScheduleTest { | 
| 58 | 58 | System.out.println("Success!"); | 
| 59 | 59 | |
| 60 | 60 | |
| 61 | -// page = (HtmlPage) client.getPage("http://localhost:8080/schoolmanager/view/class/current.seam?networkId=salsafactory"); | |
| 62 | 61 | WebClientUtils.waitForJSJob(client, 0, 30000); | 
| 63 | 62 | Assert.assertEquals(client.getCurrentWindow().getEnclosedPage(), page); | 
| 64 | 63 | studentInput = (HtmlInput) page.getElementById("searchClass:student_i"); | 
| ... | ... | @@ -66,7 +65,6 @@ public class ScheduleTest { | 
| 66 | 65 | studentInput.type('l'); | 
| 67 | 66 | studentInput.type('i'); | 
| 68 | 67 | Assert.assertEquals(client.getCurrentWindow().getEnclosedPage(), page); | 
| 69 | -// WebClientUtils.forceWait(2000); | |
| 70 | 68 | // Here the suggestionBox is still hidden | 
| 71 | 69 | WebClientUtils.waitForJSJob(client, 0, 30000); | 
| 72 | 70 | // Here suggestionBox is visible | 
| ... | ... | @@ -138,7 +136,7 @@ public class ScheduleTest { | 
| 138 | 136 | |
| 139 | 137 | private HtmlPage login(WebClient client) throws IOException { | 
| 140 | 138 | HtmlPage page = (HtmlPage) client.getPage("http://localhost:8080/schoolmanager/view/class/current.seam?networkId=salsafactory"); | 
| 141 | - ((HtmlInput) page.getElementById("loginForm:email")).setValueAttribute("s4237@pjwstk.edu.pl"); | |
| 139 | + ((HtmlInput) page.getElementById("loginForm:email")).setValueAttribute("it.crowd.test@gmail.com"); | |
| 142 | 140 | ((HtmlInput) page.getElementById("loginForm:password")).setValueAttribute("aaaaa"); | 
| 143 | 141 | HtmlPage oldPage = page; | 
| 144 | 142 | page = page.getElementById("loginForm:submit").click(); | ... | ... | 
src/test/resources/jquery-1.3.2.js
0 → 100644
This diff could not be displayed because it is too large.
| ... | ... | @@ -3,10 +3,28 @@ | 
| 3 | 3 | <html> | 
| 4 | 4 | <head> | 
| 5 | 5 | <title></title> | 
| 6 | + <script type="text/javascript" src="jquery-1.3.2.js"></script> | |
| 7 | + <script type="text/javascript"> | |
| 8 | + jQuery(function() { | |
| 9 | + jQuery("#clickable").click(function() { | |
| 10 | + alert("Clicked " + this.id); | |
| 11 | + }); | |
| 12 | + jQuery("#clickable2").click(function() { | |
| 13 | + alert("Clicked " + this.id); | |
| 14 | + }); | |
| 15 | + }); | |
| 16 | + </script> | |
| 6 | 17 | </head> | 
| 7 | 18 | <body> | 
| 8 | 19 | <img id="close" onclick="var e = document.getElementById('elementToHide');e.removeChild(e.firstChild)" alt="close"/> | 
| 9 | 20 | |
| 10 | 21 | <div id="elementToHide">elementToHide</div> | 
| 22 | + | |
| 23 | +<div id="clickable">Click me</div> | |
| 24 | +<div id="clickable2"> | |
| 25 | + <a> | |
| 26 | + <span id="clickable2child">Clickable child</span> | |
| 27 | + </a> | |
| 28 | +</div> | |
| 11 | 29 | </body> | 
| 12 | 30 | </html> | 
| \ No newline at end of file | ... | ... | 
Please
register
or
login
to post a comment