From: <rb...@us...> - 2017-10-07 11:02:13
|
Revision: 14860 http://sourceforge.net/p/htmlunit/code/14860 Author: rbri Date: 2017-10-07 11:02:10 +0000 (Sat, 07 Oct 2017) Log Message: ----------- make the promises working async Modified Paths: -------------- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Promise.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/PromiseTest.java Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Promise.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Promise.java 2017-10-06 17:16:32 UTC (rev 14859) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Promise.java 2017-10-07 11:02:10 UTC (rev 14860) @@ -18,9 +18,8 @@ import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.EDGE; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF; -import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine; -import com.gargoylesoftware.htmlunit.javascript.PostponedAction; import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable; +import com.gargoylesoftware.htmlunit.javascript.background.BasicJavaScriptJob; import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass; import com.gargoylesoftware.htmlunit.javascript.configuration.JsxConstructor; import com.gargoylesoftware.htmlunit.javascript.configuration.JsxFunction; @@ -53,8 +52,8 @@ /** To be set only by {@link #all(Context, Scriptable, Object[], Function)}. */ private Promise[] all_; - private PostponedAction thenAction_; - private Promise linkedPromise_; + private BasicJavaScriptJob settledAction_; + private Promise dependentPromise_; /** * Default constructor. @@ -92,7 +91,7 @@ @Override public Object call(final Context cx, final Scriptable scope, final Scriptable thisObj, final Object[] args) { - thisPromise.update(PromiseState.FULFILLED, args.length != 0 ? args[0] : Undefined.instance); + thisPromise.settle(true, args.length != 0 ? args[0] : Undefined.instance, window); return thisPromise; } }; @@ -101,7 +100,7 @@ @Override public Object call(final Context cx, final Scriptable scope, final Scriptable thisObj, final Object[] args) { - thisPromise.update(PromiseState.REJECTED, args.length != 0 ? args[0] : Undefined.instance); + thisPromise.settle(false, args.length != 0 ? args[0] : Undefined.instance, window); return thisPromise; } }; @@ -110,7 +109,7 @@ fun.call(Context.getCurrentContext(), window, window, new Object[] {resolve, reject}); } catch (final JavaScriptException e) { - thisPromise.update(PromiseState.REJECTED, e.getValue()); + thisPromise.settle(false, e.getValue(), window); } } @@ -145,6 +144,7 @@ } private static Promise create(final Scriptable thisObj, final Object[] args, final PromiseState state) { + // fulfilled promises are returend if (args.length != 0 && args[0] instanceof Promise && state == PromiseState.FULFILLED) { return (Promise) args[0]; } @@ -173,27 +173,27 @@ return promise; } - private void update(final PromiseState newState, final Object newValue) { - if (state_ == newState || state_ != PromiseState.PENDING) { + private void settle(final boolean fulfilled, final Object newValue, final Window window) { + if (state_ != PromiseState.PENDING) { return; } value_ = newValue; - state_ = newState; + if (fulfilled) { + state_ = PromiseState.FULFILLED; + } + else { + state_ = PromiseState.REJECTED; + } - if (thenAction_ != null) { - try { - thenAction_.execute(); - } - catch (final Exception e) { - // ignore for now - } - thenAction_ = null; + if (settledAction_ != null) { + window.getWebWindow().getJobManager().addJob(settledAction_, window.getDocument().getPage()); + settledAction_ = null; } - if (linkedPromise_ != null) { - linkedPromise_.update(newState, newValue); - linkedPromise_ = null; + if (dependentPromise_ != null) { + dependentPromise_.settle(fulfilled, newValue, window); + dependentPromise_ = null; } } @@ -244,13 +244,14 @@ @JsxFunction public Promise then(final Function onFulfilled, final Function onRejected) { final Window window = getWindow(); - final Promise promise = new Promise(window); + final Promise returnPromise = new Promise(window); + final Promise thisPromise = this; - thenAction_ = new PostponedAction(window.getDocument().getPage(), "Promise.then") { + settledAction_ = new BasicJavaScriptJob() { @Override - public void execute() throws Exception { + public void run() { Context.enter(); try { Function toExecute = null; @@ -263,26 +264,26 @@ if (toExecute != null) { try { - final Object newValue = toExecute.call(Context.getCurrentContext(), + final Object callbackResult = toExecute.call(Context.getCurrentContext(), window, thisPromise, new Object[] {value_}); - if (newValue instanceof Promise) { - final Promise callPromise = (Promise) newValue; - if (callPromise.state_ == PromiseState.FULFILLED) { - promise.update(PromiseState.FULFILLED, callPromise.value_); + if (callbackResult instanceof Promise) { + final Promise resultPromise = (Promise) callbackResult; + if (resultPromise.state_ == PromiseState.FULFILLED) { + returnPromise.settle(true, resultPromise.value_, window); } - else if (callPromise.state_ == PromiseState.REJECTED) { - promise.update(PromiseState.REJECTED, callPromise.value_); + else if (resultPromise.state_ == PromiseState.REJECTED) { + returnPromise.settle(false, resultPromise.value_, window); } else { - callPromise.linkedPromise_ = promise; + resultPromise.dependentPromise_ = returnPromise; } } else { - promise.update(PromiseState.FULFILLED, newValue); + returnPromise.settle(true, callbackResult, window); } } catch (final JavaScriptException e) { - promise.update(PromiseState.REJECTED, e.getValue()); + returnPromise.settle(false, e.getValue(), window); } } } @@ -290,19 +291,20 @@ Context.exit(); } } + + /** {@inheritDoc} */ + @Override + public String toString() { + return super.toString() + " Promise.then"; + } }; - if (state_ != PromiseState.PENDING) { - final JavaScriptEngine jsEngine - = (JavaScriptEngine) getWindow(this).getWebWindow().getWebClient().getJavaScriptEngine(); - jsEngine.addPostponedAction(thenAction_); - thenAction_ = null; + if (state_ == PromiseState.FULFILLED || state_ == PromiseState.REJECTED) { + window.getWebWindow().getJobManager().addJob(settledAction_, window.getDocument().getPage()); + settledAction_ = null; } - else { - thisPromise.linkedPromise_ = promise; - } - return promise; + return returnPromise; } /** Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/PromiseTest.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/PromiseTest.java 2017-10-06 17:16:32 UTC (rev 14859) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/PromiseTest.java 2017-10-07 11:02:10 UTC (rev 14860) @@ -75,6 +75,37 @@ * @throws Exception if an error occurs */ @Test + @Alerts(DEFAULT = "1", + IE = {}) + public void length() throws Exception { + final String html = + "<html>\n" + + "<head>\n" + + " <script>\n" + + " function test() {\n" + + " if (window.Promise) {\n" + + " log(Promise.length);\n" + + " }\n" + + " }\n" + + " function log(x) {\n" + + " document.getElementById('log').value += x + '\\n';\n" + + " }\n" + + " </script>\n" + + "</head>\n" + + "<body onload='test()'>\n" + + " <textarea id='log' cols='80' rows='40'></textarea>\n" + + "</body>\n" + + "</html>"; + + final WebDriver driver = loadPage2(html); + final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); + assertEquals(String.join("\n", getExpectedAlerts()), text); + } + + /** + * @throws Exception if an error occurs + */ + @Test @Alerts(DEFAULT = {"done", "Resolved"}, IE = {}) public void resolve() throws Exception { @@ -103,6 +134,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -139,6 +171,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -178,6 +211,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -214,6 +248,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -250,6 +285,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -286,6 +322,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -323,6 +360,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -392,6 +430,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -434,6 +473,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -469,6 +509,7 @@ + "</body>\n" + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -514,6 +555,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -550,7 +592,6 @@ + "</html>"; final WebDriver driver = loadPage2(html); driver.findElement(By.id("btn1")).click(); - Thread.sleep(200); assertEquals(getExpectedAlerts()[0], driver.getTitle()); } @@ -640,6 +681,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + Thread.sleep(200); final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } @@ -683,6 +725,7 @@ + "</html>"; final WebDriver driver = loadPage2(html); + final String text = driver.findElement(By.id("log")).getAttribute("value").trim().replaceAll("\r", ""); assertEquals(String.join("\n", getExpectedAlerts()), text); } |