From: <rb...@us...> - 2017-11-03 18:00:14
|
Revision: 14902 http://sourceforge.net/p/htmlunit/code/14902 Author: rbri Date: 2017-11-03 18:00:11 +0000 (Fri, 03 Nov 2017) Log Message: ----------- more Promise fixes and test 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-11-03 16:55:04 UTC (rev 14901) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Promise.java 2017-11-03 18:00:11 UTC (rev 14902) @@ -321,7 +321,7 @@ * @return {@link Promise} */ @JsxFunction - public Promise then(final Function onFulfilled, final Function onRejected) { + public Promise then(final Object onFulfilled, final Object onRejected) { final Window window = getWindow(); final Promise returnPromise = new Promise(window); @@ -334,40 +334,47 @@ Context.enter(); try { Function toExecute = null; - if (thisPromise.state_ == PromiseState.FULFILLED) { - toExecute = onFulfilled; + if (thisPromise.state_ == PromiseState.FULFILLED && onFulfilled instanceof Function) { + toExecute = (Function) onFulfilled; } - else if (thisPromise.state_ == PromiseState.REJECTED) { - toExecute = onRejected; + else if (thisPromise.state_ == PromiseState.REJECTED && onRejected instanceof Function) { + toExecute = (Function) onRejected; } - if (toExecute != null) { - try { - final Object callbackResult = toExecute.call(Context.getCurrentContext(), + try { + final Object callbackResult; + if (toExecute == null) { + final Promise dummy = new Promise(); + dummy.state_ = thisPromise.state_; + dummy.value_ = thisPromise.value_; + callbackResult = dummy; + } + else { + callbackResult = toExecute.call(Context.getCurrentContext(), window, thisPromise, new Object[] {value_}); - if (callbackResult instanceof Promise) { - final Promise resultPromise = (Promise) callbackResult; - if (resultPromise.state_ == PromiseState.FULFILLED) { - returnPromise.settle(true, resultPromise.value_, window); - } - else if (resultPromise.state_ == PromiseState.REJECTED) { - returnPromise.settle(false, resultPromise.value_, window); - } - else { - if (resultPromise.dependentPromises_ == null) { - resultPromise.dependentPromises_ = new ArrayList<Promise>(2); - } - resultPromise.dependentPromises_.add(returnPromise); - } + } + if (callbackResult instanceof Promise) { + final Promise resultPromise = (Promise) callbackResult; + if (resultPromise.state_ == PromiseState.FULFILLED) { + returnPromise.settle(true, resultPromise.value_, window); } + else if (resultPromise.state_ == PromiseState.REJECTED) { + returnPromise.settle(false, resultPromise.value_, window); + } else { - returnPromise.settle(true, callbackResult, window); + if (resultPromise.dependentPromises_ == null) { + resultPromise.dependentPromises_ = new ArrayList<Promise>(2); + } + resultPromise.dependentPromises_.add(returnPromise); } } - catch (final JavaScriptException e) { - returnPromise.settle(false, e.getValue(), window); + else { + returnPromise.settle(true, callbackResult, window); } } + catch (final JavaScriptException e) { + returnPromise.settle(false, e.getValue(), window); + } } finally { Context.exit(); @@ -401,7 +408,7 @@ * @return {@link Promise} */ @JsxFunction(functionName = "catch") - public Promise catch_js(final Function onRejected) { + public Promise catch_js(final Object onRejected) { return then(null, onRejected); } } 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-11-03 16:55:04 UTC (rev 14901) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/PromiseTest.java 2017-11-03 18:00:11 UTC (rev 14902) @@ -910,6 +910,140 @@ * @throws Exception if an error occurs */ @Test + @Alerts(DEFAULT = {"done", "Success first"}, + IE = {}) + public void thenTestAsyncChainedResolve() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <script>\n" + + " function test() {\n" + + " if (window.Promise) {\n" + + " var p = new Promise(function(resolve, reject) {\n" + + " window.setTimeout( function() {\n" + + " resolve('first');\n" + + " }, 20);\n" + + " })\n" + + " var p2 = p.then(undefined, function(value) {\n" + + " log(value);\n" + + " })\n" + + " p2.then(function(value) {\n" + + " log('Success ' + value);\n" + + " }," + + " function(value) {\n" + + " log('Failure ' + value);\n" + + " })\n" + + " log('done');\n" + + " }\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); + 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", "Failure first"}, + IE = {}) + public void thenTestAsyncChainedReject() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <script>\n" + + " function test() {\n" + + " if (window.Promise) {\n" + + " var p = new Promise(function(resolve, reject) {\n" + + " window.setTimeout( function() {\n" + + " reject('first');\n" + + " }, 20);\n" + + " })\n" + + " var p2 = p.then(function(value) {\n" + + " log(value);\n" + + " }, undefined)\n" + + " p2.then(function(value) {\n" + + " log('Success ' + value);\n" + + " }," + + " function(value) {\n" + + " log('Failure ' + value);\n" + + " })\n" + + " log('done');\n" + + " }\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); + 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", "Success first"}, + IE = {}) + public void thenTestAsyncChainedNotAFunction() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <script>\n" + + " function test() {\n" + + " if (window.Promise) {\n" + + " var p = new Promise(function(resolve, reject) {\n" + + " window.setTimeout( function() {\n" + + " resolve('first');\n" + + " }, 20);\n" + + " })\n" + + " var p2 = p.then(7);\n" + + " var p3 = p2.then('test');\n" + + " p3.then(function(value) {\n" + + " log('Success ' + value);\n" + + " }," + + " function(value) {\n" + + " log('Failure ' + value);\n" + + " })\n" + + " log('done');\n" + + " }\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); + 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 = {"Success", "string", "oh, no!", "after catch"}, IE = {}) public void catchTest() throws Exception { @@ -1003,6 +1137,51 @@ * @throws Exception if an error occurs */ @Test + @Alerts(DEFAULT = {"done", "Success first"}, + IE = {}) + public void catchTestAsyncChained() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <script>\n" + + " function test() {\n" + + " if (window.Promise) {\n" + + " var p = new Promise(function(resolve, reject) {\n" + + " window.setTimeout( function() {\n" + + " resolve('first');\n" + + " }, 20);\n" + + " })\n" + + " var p2 = p.catch(function(value) {\n" + + " log(value);\n" + + " })\n" + + " p2.then(function(value) {\n" + + " log('Success ' + value);\n" + + " }," + + " function(value) {\n" + + " log('Failure ' + value);\n" + + " })\n" + + " log('done');\n" + + " }\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); + 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", "Success"}, IE = "") public void thenInsideEventHandler() throws Exception { |