diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JSObjectBuilder.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JSObjectBuilder.java index 99a76b13e8..bb1560f252 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JSObjectBuilder.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JSObjectBuilder.java @@ -55,6 +55,10 @@ public class JSObjectBuilder { return this; } + public boolean contains(String key, Object value) { + return arguments.containsKey(key) && arguments.get(key).equals(value); + } + public JSObjectBuilder add(String key, Object value) { arguments.put(key, value); return this; diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java index 2194c3b47d..496c8af93f 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java @@ -130,13 +130,27 @@ public class JavascriptTestExecutor { String arguments = argumentsBuilder.build(); - Object output = jsExecutor.executeAsyncScript( - "var callback = arguments[arguments.length - 1];" + - " window.keycloak.init(" + arguments + ").success(function (authenticated) {" + - " callback(\"Init Success (\" + (authenticated ? \"Authenticated\" : \"Not Authenticated\") + \")\");" + - " }).error(function () {" + - " callback(\"Init Error\");" + - " });"); + String script; + + // phantomjs do not support Native promises + if (argumentsBuilder.contains("promiseType", "native") && !"phantomjs".equals(System.getProperty("js.browser"))) { + script = "var callback = arguments[arguments.length - 1];" + + " window.keycloak.init(" + arguments + ").then(function (authenticated) {" + + " callback(\"Init Success (\" + (authenticated ? \"Authenticated\" : \"Not Authenticated\") + \")\");" + + " }, function () {" + + " callback(\"Init Error\");" + + " });"; + } else { + script = "var callback = arguments[arguments.length - 1];" + + " window.keycloak.init(" + arguments + ").success(function (authenticated) {" + + " callback(\"Init Success (\" + (authenticated ? \"Authenticated\" : \"Not Authenticated\") + \")\");" + + " }).error(function () {" + + " callback(\"Init Error\");" + + " });"; + } + + + Object output = jsExecutor.executeAsyncScript(script); if (validator != null) { validator.validate(jsDriver, output, events); @@ -159,8 +173,20 @@ public class JavascriptTestExecutor { } public JavascriptTestExecutor refreshToken(int value, JavascriptStateValidator validator) { - Object output = jsExecutor.executeAsyncScript( - "var callback = arguments[arguments.length - 1];" + + String script; + if (useNativePromises()) { + script = "var callback = arguments[arguments.length - 1];" + + " window.keycloak.updateToken(" + Integer.toString(value) + ").then(function (refreshed) {" + + " if (refreshed) {" + + " callback(window.keycloak.tokenParsed);" + + " } else {" + + " callback('Token not refreshed, valid for ' + Math.round(window.keycloak.tokenParsed.exp + window.keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds');" + + " }" + + " }, function () {" + + " callback('Failed to refresh token');" + + " });"; + } else { + script = "var callback = arguments[arguments.length - 1];" + " window.keycloak.updateToken(" + Integer.toString(value) + ").success(function (refreshed) {" + " if (refreshed) {" + " callback(window.keycloak.tokenParsed);" + @@ -169,7 +195,10 @@ public class JavascriptTestExecutor { " }" + " }).error(function () {" + " callback('Failed to refresh token');" + - " });"); + " });"; + } + + Object output = jsExecutor.executeAsyncScript(script); if(validator != null) { validator.validate(jsDriver, output, events); @@ -178,6 +207,12 @@ public class JavascriptTestExecutor { return this; } + public boolean useNativePromises() { + return (boolean) jsExecutor.executeScript("if (typeof window.keycloak !== 'undefined') {" + + "return window.keycloak.useNativePromise" + + "} else { return false}"); + } + public JavascriptTestExecutor openAccountPage(JavascriptStateValidator validator) { jsExecutor.executeScript("window.keycloak.accountManagement()"); waitForPageToLoad(); @@ -198,13 +233,24 @@ public class JavascriptTestExecutor { public JavascriptTestExecutor getProfile(JavascriptStateValidator validator) { - Object output = jsExecutor.executeAsyncScript( - "var callback = arguments[arguments.length - 1];" + - " window.keycloak.loadUserProfile().success(function (profile) {" + - " callback(profile);" + - " }).error(function () {" + - " callback('Failed to load profile');" + - " });"); + String script; + if (useNativePromises()) { + script = "var callback = arguments[arguments.length - 1];" + + " window.keycloak.loadUserProfile().then(function (profile) {" + + " callback(profile);" + + " }, function () {" + + " callback('Failed to load profile');" + + " });"; + } else { + script = "var callback = arguments[arguments.length - 1];" + + " window.keycloak.loadUserProfile().success(function (profile) {" + + " callback(profile);" + + " }).error(function () {" + + " callback('Failed to load profile');" + + " });"; + } + + Object output = jsExecutor.executeAsyncScript(script); if(validator != null) { validator.validate(jsDriver, output, events); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/javascript/JavascriptAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/javascript/JavascriptAdapterTest.java index e4a05c1568..e344eea93d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/javascript/JavascriptAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/javascript/JavascriptAdapterTest.java @@ -58,7 +58,7 @@ import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement; public class JavascriptAdapterTest extends AbstractJavascriptTest { private String testAppUrl; - private JavascriptTestExecutor testExecutor; + protected JavascriptTestExecutor testExecutor; private static int TIME_SKEW_TOLERANCE = 3; @Rule @@ -96,7 +96,7 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest { setStandardFlowForClient(); } - private JSObjectBuilder defaultArguments() { + protected JSObjectBuilder defaultArguments() { return JSObjectBuilder.create().defaultSettings(); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/javascript/JavascriptAdapterWithNativePromisesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/javascript/JavascriptAdapterWithNativePromisesTest.java new file mode 100644 index 0000000000..0677e4dd6e --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/javascript/JavascriptAdapterWithNativePromisesTest.java @@ -0,0 +1,42 @@ +package org.keycloak.testsuite.adapter.javascript; + +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; +import org.keycloak.testsuite.util.javascript.JSObjectBuilder; + +import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement; + +public class JavascriptAdapterWithNativePromisesTest extends JavascriptAdapterTest { + @Override + protected JSObjectBuilder defaultArguments() { + return super.defaultArguments().add("promiseType", "native"); + } + + @Before + public void skipOnPhantomJS() { + Assume.assumeTrue("Native promises are not supported on PhantomJS", !"phantomjs".equals(System.getProperty("js.browser"))); + } + + @Test + @Override + public void reentrancyCallbackTest() { + testExecutor.logInAndInit(defaultArguments(), testUser, this::assertSuccessfullyLoggedIn) + .executeAsyncScript( + "var callback = arguments[arguments.length - 1];" + + "keycloak.updateToken(60).then(function () {" + + " event(\"First callback\");" + + " keycloak.updateToken(60).then(function () {" + + " event(\"Second callback\");" + + " callback(\"Success\");" + + " });" + + " }" + + ");" + , (driver1, output, events) -> { + waitUntilElement(events).text().contains("First callback"); + waitUntilElement(events).text().contains("Second callback"); + waitUntilElement(events).text().not().contains("Auth Logout"); + } + ); + } +}