From: <mgu...@us...> - 2013-02-19 08:25:13
|
Revision: 8122 http://sourceforge.net/p/htmlunit/code/8122 Author: mguillem Date: 2013-02-19 08:25:09 +0000 (Tue, 19 Feb 2013) Log Message: ----------- Fixed synchronization problem causing a task triggered by setTimeout to be executed to early, before event handlers. Modified Paths: -------------- trunk/htmlunit/src/changes/changes.xml trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElement.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/Window2Test.java Modified: trunk/htmlunit/src/changes/changes.xml =================================================================== --- trunk/htmlunit/src/changes/changes.xml 2013-02-18 23:17:16 UTC (rev 8121) +++ trunk/htmlunit/src/changes/changes.xml 2013-02-19 08:25:09 UTC (rev 8122) @@ -8,6 +8,9 @@ <body> <release version="2.12" date="???" description="Bugfixes, CSS3 Selectors"> + <action type="fix"> + Fixed synchronization problem causing a task triggered by setTimeout to be executed to early, before event handlers. + </action> <action type="fix" dev="mguillem"> CookieManager: changed getCookies to return a copy of the current set of cookies to avoid ConcurrentModificationException. </action> Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElement.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElement.java 2013-02-18 23:17:16 UTC (rev 8121) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElement.java 2013-02-19 08:25:09 UTC (rev 8122) @@ -1176,24 +1176,27 @@ throws IOException { // make enclosing window the current one - getPage().getWebClient().setCurrentWindow(getPage().getEnclosingWindow()); + final SgmlPage page = getPage(); + page.getWebClient().setCurrentWindow(page.getEnclosingWindow()); if (this instanceof DisabledElement && ((DisabledElement) this).isDisabled()) { - return (P) getPage(); + return (P) page; } - mouseDown(shiftKey, ctrlKey, altKey, MouseEvent.BUTTON_LEFT); + synchronized (page) { + mouseDown(shiftKey, ctrlKey, altKey, MouseEvent.BUTTON_LEFT); - // give focus to current element (if possible) or only remove it from previous one - final HtmlElement elementToFocus = (this instanceof SubmittableElement || this instanceof HtmlAnchor) - ? this : null; - ((HtmlPage) getPage()).setFocusedElement(elementToFocus); + // give focus to current element (if possible) or only remove it from previous one + final HtmlElement elementToFocus = (this instanceof SubmittableElement || this instanceof HtmlAnchor) + ? this : null; + ((HtmlPage) page).setFocusedElement(elementToFocus); - mouseUp(shiftKey, ctrlKey, altKey, MouseEvent.BUTTON_LEFT); + mouseUp(shiftKey, ctrlKey, altKey, MouseEvent.BUTTON_LEFT); - final Event event = new MouseEvent(getEventTargetElement(), MouseEvent.TYPE_CLICK, shiftKey, ctrlKey, altKey, - MouseEvent.BUTTON_LEFT); - return (P) click(event); + final Event event = new MouseEvent(getEventTargetElement(), MouseEvent.TYPE_CLICK, shiftKey, + ctrlKey, altKey, MouseEvent.BUTTON_LEFT); + return (P) click(event); + } } /** Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/Window2Test.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/Window2Test.java 2013-02-18 23:17:16 UTC (rev 8121) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/Window2Test.java 2013-02-19 08:25:09 UTC (rev 8122) @@ -21,6 +21,8 @@ import org.apache.commons.lang3.StringUtils; import org.junit.Test; import org.junit.runner.RunWith; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; import org.openqa.selenium.htmlunit.HtmlUnitDriver; import com.gargoylesoftware.htmlunit.BrowserRunner; @@ -1085,4 +1087,39 @@ loadPageWithAlerts2(html); } + + /** + * As of 2.12-SNAPSHOT on 19.02.2013, a task started by setTimeout in an event handler could be executed before + * all events handlers have been executed due to a missing synchronization. + * @throws Exception if the test fails + */ + @Test + public void setTimeoutShouldNotBeExecutedBeforeHandlers() throws Exception { + final String html + = "<html><body><script>\n" + + "function stop() {\n" + + " window.stopIt = true;\n" + + "}\n" + + "for (var i=0; i<1000; ++i) {\n" + + " var handler = function(e) {\n" + + " if (window.stopIt) {\n" + + " e.preventDefault ? e.preventDefault() : e.returnValue = false;\n" + + " }\n" + + " }\n" + + " if (window.addEventListener)\n" + + " window.addEventListener('click', handler, false);\n" + + " else\n" + + " window.attachEvent('onclick', handler);\n" + + "}\n" + + "</script>\n" + + "<form action='page2' method='post'>\n" + + "<input id='it' type='submit' onclick='setTimeout(stop, 0)'>\n" + + "</form>" + + "</body></html>"; + + final WebDriver driver = loadPage2(html); + driver.findElement(By.id("it")).click(); + + assertEquals(getDefaultUrl() + "page2", driver.getCurrentUrl()); + } } |