11package com .flowingcode .vaadin .addons .chipfield .integration ;
22
3+ import java .lang .reflect .InvocationHandler ;
4+ import java .lang .reflect .Method ;
5+ import java .lang .reflect .Proxy ;
6+ import java .util .List ;
7+ import java .util .Map ;
8+ import java .util .Optional ;
39import java .util .concurrent .TimeoutException ;
410import java .util .stream .Collectors ;
511import java .util .stream .Stream ;
612
7- import org .junit .Before ;
813import org .openqa .selenium .By ;
914import org .openqa .selenium .JavascriptExecutor ;
15+ import org .openqa .selenium .WebDriver ;
1016import org .openqa .selenium .WebElement ;
11- import org .openqa .selenium .support .ui .ExpectedConditions ;
12- import org .openqa .selenium .support .ui .WebDriverWait ;
1317
1418import com .vaadin .flow .component .ClientCallable ;
1519
@@ -21,38 +25,68 @@ protected AbstractChipfieldTest() {
2125 super ("it" );
2226 }
2327
24- @ Before
25- public void before () {
26- chipfield = $ (ChipFieldElement .class ).first ();
28+ @ Override
29+ public void setup () throws Exception {
30+ super .setup ();
31+ chipfield = $ (ChipFieldElement .class ).waitForFirst ();
2732 }
33+
2834 /**
2935 * Call a {@link ClientCallable} defined on the integration view.
3036 *
3137 * @param callable the client callable name
3238 * @param arguments arguments to be passed to the callable
33- * @throws TimeoutException if the callable doesn't complete in 2 seconds.
39+ * @throws TimeoutException if the callable times out (see
40+ * {@link WebDriver.Timeouts#setScriptTimeout(long, java.util.concurrent.TimeUnit)
41+ * WebDriver.Timeouts}).
3442 * @throws RuntimeException if the callable fails.
3543 */
36- protected final void call (String callable , Object ... arguments ) {
44+ protected final Object call (String callable , Object ... arguments ) {
3745 WebElement view = getDriver ().findElement (By .id ("view" ));
38- String result = "data-callable-result" ;
46+ arguments = Optional . ofNullable ( arguments ). orElse ( new Object [ 0 ]) ;
3947
4048 StringBuilder script = new StringBuilder ();
4149 script .append ("var view = arguments[0];" );
4250 script .append ("var callable = arguments[1];" );
43- script .append ("var result = arguments[2];" );
44- script .append ("view.removeAttribute(result);" );
45- script .append ("view.$server[callable](...arguments[3])" );
46- script .append (" .then(()=>view.setAttribute(result,true))" );
47- script .append (" .catch(()=>view.setAttribute(result,false));" );
51+ script .append ("var callback = (result,success) => arguments[3]({result, success});" );
52+ script .append ("view.$server[callable](...arguments[2])" );
53+ script .append (" .then(result=>callback(result, true))" );
54+ script .append (" .catch(()=>callback(undefined, false));" );
4855
49- ((JavascriptExecutor ) getDriver ()).executeScript (script .toString (), view , callable , result , arguments );
56+ @ SuppressWarnings ("unchecked" )
57+ Map <String , Object > result = (Map <String , Object >) ((JavascriptExecutor ) getDriver ()).executeAsyncScript (script .toString (), view , callable , arguments );
5058
51- new WebDriverWait (getDriver (), 2 , 100 ).until (ExpectedConditions .attributeToBeNotEmpty (view , result ));
52- if (!Boolean .parseBoolean (view .getAttribute (result ))) {
59+ if (!(Boolean ) result .get ("success" )) {
5360 throw new RuntimeException (
5461 String .format ("server call failed: %s(%s)" , callable , Stream .of (arguments ).map (Object ::toString ).collect (Collectors .joining ("," ))));
5562 }
63+
64+ return result .get ("result" );
65+ }
66+
67+ /**
68+ * Create a TestBench proxy that invokes methods from the interface through a
69+ * client {@link #call}.
70+ */
71+ protected final <T > T createCallableProxy (Class <T > intf ) {
72+ return intf .cast (Proxy .newProxyInstance (intf .getClassLoader (), new Class <?>[] { intf }, new InvocationHandler () {
73+ @ Override
74+ public Object invoke (Object proxy , Method method , Object [] args ) throws Throwable {
75+ Object result = call (method .getName (), args );
76+
77+ if (result == null || method .getReturnType () == Void .TYPE ) {
78+ return null ;
79+ }
80+
81+ if (method .getReturnType () == JsonArrayList .class ) {
82+ return JsonArrayList .wrapForTestbench ((List <?>) result );
83+ }
84+
85+ // this implementation is incomplete.
86+ // other types that should be supported are: Double, Integer, Boolean, String, JsonValue
87+ throw new ClassCastException (String .format ("%s as %s" , result .getClass ().getName (), method .getReturnType ().getName ()));
88+ }
89+ }));
5690 }
5791
5892}
0 commit comments