From: <rb...@us...> - 2017-10-08 13:21:39
|
Revision: 14866 http://sourceforge.net/p/htmlunit/code/14866 Author: rbri Date: 2017-10-08 13:21:36 +0000 (Sun, 08 Oct 2017) Log Message: ----------- first simple Promise.race cases are working Modified Paths: -------------- trunk/htmlunit/src/changes/changes.xml 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/changes/changes.xml =================================================================== --- trunk/htmlunit/src/changes/changes.xml 2017-10-08 13:07:28 UTC (rev 14865) +++ trunk/htmlunit/src/changes/changes.xml 2017-10-08 13:21:36 UTC (rev 14866) @@ -7,7 +7,7 @@ </properties> <body> - <release version="2.28" date="???" description="Bugfixes, Chrome 61"> + <release version="2.28" date="???" description="Bugfixes, Chrome 61, improved Promise impl"> <action type="fix" dev="rbri"> JavaScript: throw a type error if the url property is requested from the WebSocket prototype. </action> 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-08 13:07:28 UTC (rev 14865) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Promise.java 2017-10-08 13:21:36 UTC (rev 14866) @@ -53,7 +53,8 @@ private enum PromiseState { PENDING, FULFILLED, REJECTED } private PromiseState state_ = PromiseState.PENDING; private Object value_; - /** To be set only by {@link #all(Context, Scriptable, Object[], Function)}. */ + + private boolean race_; private Promise[] all_; private List<BasicJavaScriptJob> settledJobs_; @@ -213,6 +214,20 @@ } private void settleAll(final Window window) { + if (race_) { + for (Promise promise : all_) { + if (promise.state_ == PromiseState.REJECTED) { + settleThis(false, promise.value_, window); + return; + } + else if (promise.state_ == PromiseState.FULFILLED) { + settleThis(true, promise.value_, window); + return; + } + } + return; + } + final ArrayList<Object> values = new ArrayList<>(all_.length); for (Promise promise : all_) { if (promise.state_ == PromiseState.REJECTED) { @@ -243,6 +258,26 @@ @JsxStaticFunction public static Promise all(final Context context, final Scriptable thisObj, final Object[] args, final Function function) { + return all(false, thisObj, args); + } + + /** + * Returns a {@link Promise} that that resolves or rejects as soon as one of the promises + * in the iterable resolves or rejects, with the value or reason from that promise. + * + * @param context the context + * @param thisObj this object + * @param args the arguments + * @param function the function + * @return a {@link Promise} + */ + @JsxStaticFunction + public static Promise race(final Context context, final Scriptable thisObj, final Object[] args, + final Function function) { + return all(true, thisObj, args); + } + + private static Promise all(final boolean race, final Scriptable thisObj, final Object[] args) { final Window window = getWindow(thisObj); final Promise returnPromise = new Promise(window); @@ -267,6 +302,7 @@ else { // TODO } + returnPromise.race_ = race; returnPromise.settleAll(window); 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-08 13:07:28 UTC (rev 14865) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/PromiseTest.java 2017-10-08 13:21:36 UTC (rev 14866) @@ -853,8 +853,6 @@ } /** - * Test for Bug #1780. - * * @throws Exception if an error occurs */ @Test @@ -899,8 +897,6 @@ } /** - * Test for Bug #1780. - * * @throws Exception if an error occurs */ @Test @@ -944,4 +940,98 @@ 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", "Success 2"}, + IE = {}) + public void raceAsync() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <script>\n" + + " function test() {\n" + + " if (window.Promise) {\n" + + " var p1 = new Promise(function(resolve, reject) {\n" + + " window.setTimeout( function() {\n" + + " resolve('Success');\n" + + " }, 40);\n" + + " });\n" + + " var p2 = new Promise(function(resolve, reject) {\n" + + " window.setTimeout( function() {\n" + + " resolve('Success 2');\n" + + " }, 20);\n" + + " });\n" + + "\n" + + " Promise.race([p1, p2]).then(function(value) {\n" + + " log(value);\n" + + " }, function(value) {\n" + + " log('failure');\n" + + " });\n" + + " log('done');\n" + + " }\n" + + " }\n" + + "\n" + + " function log(x) {\n" + + " document.getElementById('log').value += x + '\\n';\n" + + " }\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + " <textarea id='log' cols='80' rows='40'></textarea>\n" + + "</body>\n" + + "</html>\n"; + + 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); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = {"done", "Failed"}, + IE = {}) + public void raceRejectAsync() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <script>\n" + + " function test() {\n" + + " if (window.Promise) {\n" + + " var p1 = new Promise(function(resolve, reject) {\n" + + " window.setTimeout( function() {\n" + + " resolve('Success');\n" + + " }, 40);\n" + + " });\n" + + " var p2 = new Promise(function(resolve, reject) {\n" + + " window.setTimeout( function() {\n" + + " reject('Failed');\n" + + " }, 20);\n" + + " });\n" + + "\n" + + " Promise.race([p1, p2]).then(function(value) {\n" + + " log('failure');\n" + + " }, function(value) {\n" + + " log(value);\n" + + " });\n" + + " log('done');\n" + + " }\n" + + " }\n" + + "\n" + + " function log(x) {\n" + + " document.getElementById('log').value += x + '\\n';\n" + + " }\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + " <textarea id='log' cols='80' rows='40'></textarea>\n" + + "</body>\n" + + "</html>\n"; + + 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); + } } |