Skip to content

Commit d7be336

Browse files
committed
test: move RPC support classes into a separate package
1 parent 93e6eec commit d7be336

File tree

9 files changed

+216
-191
lines changed

9 files changed

+216
-191
lines changed
Lines changed: 2 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,8 @@
11
package 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;
9-
import java.util.concurrent.TimeoutException;
10-
import java.util.stream.Collectors;
11-
import java.util.stream.Stream;
3+
import com.flowingcode.vaadin.addons.chipfield.integration.rpc.HasRpcSupport;
124

13-
import org.openqa.selenium.By;
14-
import org.openqa.selenium.JavascriptExecutor;
15-
import org.openqa.selenium.WebDriver;
16-
import org.openqa.selenium.WebElement;
17-
18-
import com.vaadin.flow.component.ClientCallable;
19-
20-
public class AbstractChipfieldTest extends AbstractViewTest {
5+
public abstract class AbstractChipfieldTest extends AbstractViewTest implements HasRpcSupport {
216

227
protected ChipFieldElement chipfield;
238

@@ -31,62 +16,4 @@ public void setup() throws Exception {
3116
chipfield = $(ChipFieldElement.class).waitForFirst();
3217
}
3318

34-
/**
35-
* Call a {@link ClientCallable} defined on the integration view.
36-
*
37-
* @param callable the client callable name
38-
* @param arguments arguments to be passed to the callable
39-
* @throws TimeoutException if the callable times out (see
40-
* {@link WebDriver.Timeouts#setScriptTimeout(long, java.util.concurrent.TimeUnit)
41-
* WebDriver.Timeouts}).
42-
* @throws RuntimeException if the callable fails.
43-
*/
44-
protected final Object call(String callable, Object... arguments) {
45-
WebElement view = getDriver().findElement(By.id("view"));
46-
arguments = Optional.ofNullable(arguments).orElse(new Object[0]);
47-
48-
StringBuilder script = new StringBuilder();
49-
script.append("var view = arguments[0];");
50-
script.append("var callable = arguments[1];");
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));");
55-
56-
@SuppressWarnings("unchecked")
57-
Map<String, Object> result = (Map<String, Object>) ((JavascriptExecutor) getDriver()).executeAsyncScript(script.toString(), view, callable, arguments);
58-
59-
if (!(Boolean) result.get("success")) {
60-
throw new RuntimeException(
61-
String.format("server call failed: %s(%s)", callable, Stream.of(arguments).map(Object::toString).collect(Collectors.joining(","))));
62-
}
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-
}));
90-
}
91-
9219
}

src/test/java/com/flowingcode/vaadin/addons/chipfield/integration/IntegrationView.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.Arrays;
44

55
import com.flowingcode.vaadin.addons.chipfield.ChipField;
6+
import com.flowingcode.vaadin.addons.chipfield.integration.rpc.JsonArrayList;
67
import com.vaadin.flow.component.ClientCallable;
78
import com.vaadin.flow.component.html.Div;
89
import com.vaadin.flow.router.Route;

src/test/java/com/flowingcode/vaadin/addons/chipfield/integration/IntegrationViewCallables.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.flowingcode.vaadin.addons.chipfield.integration;
22

3+
import com.flowingcode.vaadin.addons.chipfield.integration.rpc.JsonArrayList;
4+
35
public interface IntegrationViewCallables {
46

57
void testCallable(boolean arg);

src/test/java/com/flowingcode/vaadin/addons/chipfield/integration/JsonArrayList.java

Lines changed: 0 additions & 115 deletions
This file was deleted.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.flowingcode.vaadin.addons.chipfield.integration.rpc;
2+
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;
9+
import java.util.concurrent.TimeoutException;
10+
import java.util.stream.Collectors;
11+
import java.util.stream.Stream;
12+
13+
import org.openqa.selenium.By;
14+
import org.openqa.selenium.JavascriptExecutor;
15+
import org.openqa.selenium.WebDriver;
16+
import org.openqa.selenium.WebElement;
17+
18+
import com.vaadin.flow.component.ClientCallable;
19+
import com.vaadin.testbench.HasDriver;
20+
21+
public interface HasRpcSupport extends HasDriver {
22+
23+
/**
24+
* Call a {@link ClientCallable} defined on the integration view.
25+
*
26+
* @param callable the client callable name
27+
* @param arguments arguments to be passed to the callable
28+
* @throws TimeoutException if the callable times out (see
29+
* {@link WebDriver.Timeouts#setScriptTimeout(long, java.util.concurrent.TimeUnit)
30+
* WebDriver.Timeouts}).
31+
* @throws RuntimeException if the callable fails.
32+
*/
33+
default Object call(String callable, Object... arguments) {
34+
WebElement view = getDriver().findElement(By.id("view"));
35+
arguments = Optional.ofNullable(arguments).orElse(new Object[0]);
36+
37+
StringBuilder script = new StringBuilder();
38+
script.append("var view = arguments[0];");
39+
script.append("var callable = arguments[1];");
40+
script.append("var callback = (result,success) => arguments[3]({result, success});");
41+
script.append("view.$server[callable](...arguments[2])");
42+
script.append(" .then(result=>callback(result, true))");
43+
script.append(" .catch(()=>callback(undefined, false));");
44+
45+
@SuppressWarnings("unchecked")
46+
Map<String, Object> result = (Map<String, Object>) ((JavascriptExecutor) getDriver()).executeAsyncScript(script.toString(), view, callable, arguments);
47+
48+
if (!(Boolean) result.get("success")) {
49+
throw new RuntimeException(
50+
String.format("server call failed: %s(%s)", callable, Stream.of(arguments).map(Object::toString).collect(Collectors.joining(","))));
51+
}
52+
53+
return result.get("result");
54+
}
55+
56+
/**
57+
* Create a TestBench proxy that invokes methods from the interface through a client {@link #call}.
58+
*/
59+
default <T> T createCallableProxy(Class<T> intf) {
60+
return intf.cast(Proxy.newProxyInstance(intf.getClassLoader(), new Class<?>[] { intf }, new InvocationHandler() {
61+
@Override
62+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
63+
Object result = call(method.getName(), args);
64+
65+
if (result == null || method.getReturnType() == Void.TYPE) {
66+
return null;
67+
}
68+
69+
if (method.getReturnType() == JsonArrayList.class) {
70+
return JsonArrayList.wrapForTestbench((List<?>) result);
71+
}
72+
73+
// this implementation is incomplete.
74+
// other types that should be supported are: Double, Integer, Boolean, String, JsonValue
75+
throw new ClassCastException(String.format("%s as %s", result.getClass().getName(), method.getReturnType().getName()));
76+
}
77+
}));
78+
}
79+
80+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.flowingcode.vaadin.addons.chipfield.integration.rpc;
2+
3+
import java.util.AbstractCollection;
4+
import java.util.Collection;
5+
import java.util.Iterator;
6+
import java.util.List;
7+
import java.util.Optional;
8+
import java.util.function.Function;
9+
10+
import elemental.json.Json;
11+
import elemental.json.JsonValue;
12+
import elemental.json.impl.JreJsonArray;
13+
import lombok.experimental.Delegate;
14+
15+
/** Server-side flavor of {@code JsonArrayList} */
16+
@SuppressWarnings("serial")
17+
class JreJsonArrayList<T> extends JreJsonArray implements JsonArrayList<T> {
18+
19+
@Delegate(excludes = JreJsonArray.class)
20+
private Collection<T> list = new AbstractCollection<T>() {
21+
// the delegate is only for the purpose of implementing Collection,
22+
// but the Collection interface is unsupported on instances of JreJsonArrayList
23+
@Override
24+
public Iterator<T> iterator() {
25+
throw new UnsupportedOperationException();
26+
}
27+
28+
@Override
29+
public int size() {
30+
throw new UnsupportedOperationException();
31+
}
32+
};
33+
34+
public JreJsonArrayList(List<T> list, Function<? super T, JsonValue> mapper) {
35+
super(Json.instance());
36+
for (T t : list) {
37+
set(length(), Optional.ofNullable(t).map(mapper).orElseGet(Json::createNull));
38+
}
39+
}
40+
41+
@Override
42+
public List<T> asList() {
43+
// JsonArrayList#asList is unsupported
44+
throw new UnsupportedOperationException();
45+
}
46+
}

0 commit comments

Comments
 (0)