wrapper_ = test(container);
+
+ Assertions.assertThrows(IllegalArgumentException.class,
+ () -> wrapper_.findByQuery(Span.class,
+ query -> query.withTextContaining("Span")));
+ }
+
+ @Test
+ void findAllByQuery_matchingComponent_getsComponents() {
+ Span one = new Span("Span One");
+ Span two = new Span("Span Two");
+ Span three = new Span("Span Two bis");
+ Div container = new Div(new Div(new Div(one)), new Div(two),
+ new Div(three));
+
+ ComponentTester
wrapper_ = test(container);
+
+ List
result = wrapper_.findAllByQuery(Span.class,
+ query -> query.withTextContaining("One"));
+ Assertions.assertIterableEquals(List.of(one), result);
+
+ result = wrapper_.findAllByQuery(Span.class,
+ query -> query.withTextContaining("Two"));
+ Assertions.assertIterableEquals(List.of(two, three), result);
+
+ result = wrapper_.findAllByQuery(Span.class,
+ query -> query.withTextContaining("Span"));
+ Assertions.assertIterableEquals(List.of(one, two, three), result);
+ }
+
+ @Test
+ void findAllByQuery_notMatchingComponent_empty() {
+ Span one = new Span("Span One");
+ Span two = new Span("Span Two");
+ Span three = new Span("Span Two bis");
+ Div container = new Div(new Div(new Div(one)), new Div(two),
+ new Div(three));
+
+ ComponentTester wrapper_ = test(container);
+
+ List
result = wrapper_.findAllByQuery(Span.class,
+ query -> query.withTextContaining("Three"));
+ Assertions.assertTrue(result.isEmpty());
+ }
+
+ private WelcomeView getHome() {
+ final HasElement view = getCurrentView();
+ Assertions.assertTrue(view instanceof WelcomeView,
+ "Home should be navigated to by default");
+ return (WelcomeView) view;
+ }
+
+ @Tag("span")
+ public static class Span extends Component implements HasText {
+ public Span() {
+ }
+
+ public Span(String text) {
+ setText(text);
+ }
+ }
+
+ @Tag("div")
+ public static class Div extends Component implements HasComponents {
+ public Div(Component... components) {
+ add(components);
+ }
+ }
+
+}
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/ElementConditionsTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/ElementConditionsTest.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/ElementConditionsTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/ElementConditionsTest.java
index 76acd1639..ff2f158d8 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/ElementConditionsTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/ElementConditionsTest.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
@@ -7,7 +7,6 @@
*
* For the full License, see .
*/
-
package com.vaadin.testbench.unit;
import org.junit.jupiter.api.Assertions;
@@ -18,7 +17,6 @@
import com.vaadin.flow.component.HasText;
import com.vaadin.flow.component.Html;
import com.vaadin.flow.component.HtmlComponent;
-import com.vaadin.flow.component.HtmlContainer;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.dom.Element;
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/NonGenericTestTester.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/NonGenericTestTester.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/NonGenericTestTester.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/NonGenericTestTester.java
index 247c3ce8e..5e8bfcadd 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/NonGenericTestTester.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/NonGenericTestTester.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
diff --git a/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/SecurityTestConfig.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/SecurityTestConfig.java
new file mode 100644
index 000000000..ba40e8414
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/SecurityTestConfig.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+package com.vaadin.testbench.unit;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.testapp.security.LoginView;
+import com.testapp.security.ProtectedView;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+import com.vaadin.flow.router.RouteConfiguration;
+import com.vaadin.flow.server.VaadinServiceInitListener;
+import com.vaadin.flow.server.auth.ViewAccessChecker;
+
+// Empty configuration class used only to be able to bootstrap spring
+// ApplicationContext
+@Configuration
+class SecurityTestConfig {
+
+ // Registers test views and view access checker for testing purpose
+ @Bean
+ VaadinServiceInitListener setupViewSecurityScenario() {
+ return event -> {
+ RouteConfiguration routeConfiguration = RouteConfiguration
+ .forApplicationScope();
+ routeConfiguration.setAnnotatedRoute(LoginView.class);
+ routeConfiguration.setAnnotatedRoute(ProtectedView.class);
+ event.getSource().addUIInitListener(uiEvent -> {
+ ViewAccessChecker viewAccessChecker = new ViewAccessChecker();
+ viewAccessChecker.setLoginView(LoginView.class);
+ uiEvent.getUI().addBeforeEnterListener(viewAccessChecker);
+ });
+ };
+ }
+
+ @Bean
+ UserDetailsService mockUserDetailsService() {
+
+ return new UserDetailsService() {
+ @Override
+ public UserDetails loadUserByUsername(String username)
+ throws UsernameNotFoundException {
+ if ("user".equals(username)) {
+ return new User(username, UUID.randomUUID().toString(),
+ List.of(new SimpleGrantedAuthority(
+ "ROLE_SUPERUSER"),
+ new SimpleGrantedAuthority("ROLE_DEV")));
+ }
+ throw new UsernameNotFoundException(
+ "User " + username + " not exists");
+ }
+ };
+ }
+}
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/SpringUIUnitBaseClassTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/SpringUIUnitBaseClassTest.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/SpringUIUnitBaseClassTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/SpringUIUnitBaseClassTest.java
index 9fbe66b4b..af497923e 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/SpringUIUnitBaseClassTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/SpringUIUnitBaseClassTest.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
@@ -7,7 +7,6 @@
*
* For the full License, see .
*/
-
package com.vaadin.testbench.unit;
import org.junit.jupiter.api.Assertions;
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/SpringUnitSecurityTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/SpringUnitSecurityTest.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/SpringUnitSecurityTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/SpringUnitSecurityTest.java
index d5ddc95ed..7370c92c0 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/SpringUnitSecurityTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/SpringUnitSecurityTest.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
@@ -7,7 +7,6 @@
*
* For the full License, see .
*/
-
package com.vaadin.testbench.unit;
import java.security.Principal;
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TestComponent.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestComponent.java
similarity index 98%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TestComponent.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestComponent.java
index 0233707d6..b145d0883 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TestComponent.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestComponent.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TestComponentForConcreteTester.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestComponentForConcreteTester.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TestComponentForConcreteTester.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestComponentForConcreteTester.java
index 6454922e3..f0c2833ca 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TestComponentForConcreteTester.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestComponentForConcreteTester.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
diff --git a/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestCustomInstantiatorFactory.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestCustomInstantiatorFactory.java
new file mode 100644
index 000000000..5924a1e7c
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestCustomInstantiatorFactory.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+package com.vaadin.testbench.unit;
+
+import com.vaadin.flow.di.DefaultInstantiator;
+import com.vaadin.flow.di.Instantiator;
+import com.vaadin.flow.di.InstantiatorFactory;
+import com.vaadin.flow.server.VaadinService;
+
+/**
+ * A custom {@link InstantiatorFactory} to test
+ * {@link com.vaadin.flow.di.Lookup} initialization.
+ */
+public class TestCustomInstantiatorFactory implements InstantiatorFactory {
+
+ @Override
+ public Instantiator createInstantitor(VaadinService vaadinService) {
+ return new DefaultInstantiator(vaadinService);
+ }
+}
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TestTester.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestTester.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TestTester.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestTester.java
index fe74928fb..db60767a7 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TestTester.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TestTester.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TesterResolutionTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TesterResolutionTest.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TesterResolutionTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TesterResolutionTest.java
index 6487bd591..568a65953 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/TesterResolutionTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/TesterResolutionTest.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/UIUnitBaseClassTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/UIUnitBaseClassTest.java
similarity index 70%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/UIUnitBaseClassTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/UIUnitBaseClassTest.java
index 0fa9610d8..a4b0a216b 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/UIUnitBaseClassTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/UIUnitBaseClassTest.java
@@ -10,21 +10,17 @@
package com.vaadin.testbench.unit;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.example.SingleParam;
import com.example.TemplatedParam;
-import com.example.base.ParametrizedView;
import com.example.base.WelcomeView;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.function.Executable;
import com.vaadin.flow.component.Component;
-import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.di.InstantiatorFactory;
import com.vaadin.flow.di.Lookup;
@@ -106,48 +102,48 @@ void customService_availableInLookup() {
}
}
- @Nested
- class WrongBaseClassTest extends UIUnit4Test {
-
- @Test
- void navigate_fails() {
- assertExecutionFails(() -> navigate(WelcomeView.class));
- assertExecutionFails(() -> navigate("welcome", WelcomeView.class));
- assertExecutionFails(() -> navigate(ParametrizedView.class, 12));
- assertExecutionFails(
- () -> navigate(ParametrizedView.class, Map.of()));
- }
-
- @Test
- void getCurrentView_fails() {
- assertExecutionFails(this::getCurrentView);
- }
-
- @Test
- void fireShortcut_fails() {
- assertExecutionFails(() -> fireShortcut(Key.ENTER));
- }
-
- @Test
- void wrap_fails() {
- assertExecutionFails(() -> test(new ComponentTesterTest.Span()));
- assertExecutionFails(() -> test(ComponentTester.class,
- new ComponentTesterTest.Span()));
- }
-
- @Test
- void query_fails() {
- assertExecutionFails(() -> $(Component.class));
- assertExecutionFails(
- () -> $(Component.class, new ComponentTesterTest.Span()));
- assertExecutionFails(() -> $view(Component.class));
- }
-
- private void assertExecutionFails(Executable executable) {
- UIUnitTestSetupException exception = Assertions
- .assertThrows(UIUnitTestSetupException.class, executable);
- Assertions.assertTrue(exception.getMessage().contains("JUnit 4"));
- }
- }
+ // @Nested
+ // class WrongBaseClassTest extends UIUnit4Test {
+ //
+ // @Test
+ // void navigate_fails() {
+ // assertExecutionFails(() -> navigate(WelcomeView.class));
+ // assertExecutionFails(() -> navigate("welcome", WelcomeView.class));
+ // assertExecutionFails(() -> navigate(ParametrizedView.class, 12));
+ // assertExecutionFails(
+ // () -> navigate(ParametrizedView.class, Map.of()));
+ // }
+ //
+ // @Test
+ // void getCurrentView_fails() {
+ // assertExecutionFails(this::getCurrentView);
+ // }
+ //
+ // @Test
+ // void fireShortcut_fails() {
+ // assertExecutionFails(() -> fireShortcut(Key.ENTER));
+ // }
+ //
+ // @Test
+ // void wrap_fails() {
+ // assertExecutionFails(() -> test(new ComponentTesterTest.Span()));
+ // assertExecutionFails(() -> test(ComponentTester.class,
+ // new ComponentTesterTest.Span()));
+ // }
+ //
+ // @Test
+ // void query_fails() {
+ // assertExecutionFails(() -> $(Component.class));
+ // assertExecutionFails(
+ // () -> $(Component.class, new ComponentTesterTest.Span()));
+ // assertExecutionFails(() -> $view(Component.class));
+ // }
+ //
+ // private void assertExecutionFails(Executable executable) {
+ // UIUnitTestSetupException exception = Assertions
+ // .assertThrows(UIUnitTestSetupException.class, executable);
+ // Assertions.assertTrue(exception.getMessage().contains("JUnit 4"));
+ // }
+ // }
}
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/UIUnitNavigationTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/UIUnitNavigationTest.java
similarity index 92%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/UIUnitNavigationTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/UIUnitNavigationTest.java
index d6e723806..8ac96a015 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/UIUnitNavigationTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/UIUnitNavigationTest.java
@@ -1,3 +1,12 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
package com.vaadin.testbench.unit;
import java.util.Collections;
@@ -9,7 +18,6 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-import com.vaadin.flow.router.NotFoundException;
import com.vaadin.testbench.unit.internal.MockRouteNotFoundError;
@ViewPackages(packages = "com.example")
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/UIUnitShortcutTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/UIUnitShortcutTest.java
similarity index 98%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/UIUnitShortcutTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/UIUnitShortcutTest.java
index dd14806ae..341713430 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/UIUnitShortcutTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/UIUnitShortcutTest.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
@@ -7,7 +7,6 @@
*
* For the full License, see .
*/
-
package com.vaadin.testbench.unit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -15,7 +14,6 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
-import org.junit.jupiter.api.extension.Extensions;
import com.vaadin.flow.component.ClickNotifier;
import com.vaadin.flow.component.Component;
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/DiscoverRoutesInAnnotatedClassPackageTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/DiscoverRoutesInAnnotatedClassPackageTest.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/DiscoverRoutesInAnnotatedClassPackageTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/DiscoverRoutesInAnnotatedClassPackageTest.java
index e7a67f56e..13b46b53a 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/DiscoverRoutesInAnnotatedClassPackageTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/DiscoverRoutesInAnnotatedClassPackageTest.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
@@ -7,7 +7,6 @@
*
* For the full License, see .
*/
-
package com.vaadin.testbench.unit.viewscan.byannotatedclass;
import java.util.Set;
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/ViewPackagesTestView.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/ViewPackagesTestView.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/ViewPackagesTestView.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/ViewPackagesTestView.java
index 479977632..58413b0ac 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/ViewPackagesTestView.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/byannotatedclass/ViewPackagesTestView.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
@@ -7,7 +7,6 @@
*
* For the full License, see .
*/
-
package com.vaadin.testbench.unit.viewscan.byannotatedclass;
import com.vaadin.flow.component.Component;
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/byclasses/DiscoverRoutesInPackageByClassTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/byclasses/DiscoverRoutesInPackageByClassTest.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/byclasses/DiscoverRoutesInPackageByClassTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/byclasses/DiscoverRoutesInPackageByClassTest.java
index 55fe92dfc..05ff0cbf8 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/byclasses/DiscoverRoutesInPackageByClassTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/byclasses/DiscoverRoutesInPackageByClassTest.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
@@ -7,7 +7,6 @@
*
* For the full License, see .
*/
-
package com.vaadin.testbench.unit.viewscan.byclasses;
import java.util.Set;
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagename/DiscoverRoutesInPackageByNameTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagename/DiscoverRoutesInPackageByNameTest.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagename/DiscoverRoutesInPackageByNameTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagename/DiscoverRoutesInPackageByNameTest.java
index 6a5d71c1d..8f37cb023 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagename/DiscoverRoutesInPackageByNameTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagename/DiscoverRoutesInPackageByNameTest.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
@@ -7,7 +7,6 @@
*
* For the full License, see .
*/
-
package com.vaadin.testbench.unit.viewscan.bypackagename;
import java.util.Set;
diff --git a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagenameandclass/DiscoverRoutesInPackageByClassAndNameTest.java b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagenameandclass/DiscoverRoutesInPackageByClassAndNameTest.java
similarity index 99%
rename from vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagenameandclass/DiscoverRoutesInPackageByClassAndNameTest.java
rename to vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagenameandclass/DiscoverRoutesInPackageByClassAndNameTest.java
index faad8f3d5..cd8d1666c 100644
--- a/vaadin-testbench-unit/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagenameandclass/DiscoverRoutesInPackageByClassAndNameTest.java
+++ b/vaadin-testbench-unit-junit5/src/test/java/com/vaadin/testbench/unit/viewscan/bypackagenameandclass/DiscoverRoutesInPackageByClassAndNameTest.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 Vaadin Ltd
*
* This program is available under Commercial Vaadin Developer License
@@ -7,7 +7,6 @@
*
* For the full License, see .
*/
-
package com.vaadin.testbench.unit.viewscan.bypackagenameandclass;
import java.util.Set;
diff --git a/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/TestInitListener.kt b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/TestInitListener.kt
new file mode 100644
index 000000000..b87490542
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/TestInitListener.kt
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+package com.vaadin.testbench.unit
+
+import com.vaadin.flow.server.ServiceInitEvent
+import com.vaadin.flow.server.VaadinServiceInitListener
+
+/**
+ * This class is picked up automatically by Vaadin (since it's registered via META-INF/services). We then test elsewhere
+ * that MockVaadin-mocked env indeed picked up this init listener and executed it.
+ */
+class TestInitListener : VaadinServiceInitListener {
+ override fun serviceInit(event: ServiceInitEvent) {
+ serviceInitCalled = true
+ event.source.addUIInitListener { e ->
+ uiInitCalled = true
+ e.ui.addBeforeEnterListener { uiBeforeEnterCalled = true }
+ }
+ }
+
+ companion object {
+ var serviceInitCalled: Boolean = false
+ var uiInitCalled = false
+ var uiBeforeEnterCalled = false
+ fun clearInitFlags() {
+ serviceInitCalled = false
+ uiInitCalled = false
+ uiBeforeEnterCalled = false
+ }
+ }
+}
diff --git a/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/TestUtils.kt b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/TestUtils.kt
new file mode 100644
index 000000000..6e93ead42
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/TestUtils.kt
@@ -0,0 +1,24 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+package com.vaadin.testbench.unit
+
+import com.vaadin.testbench.unit.internal.allViews
+import kotlin.test.expect
+
+/**
+ * Expects that [actual] list of objects matches [expected] list of objects. Fails otherwise.
+ */
+fun expectList(vararg expected: T, actual: ()->List) {
+ expect(expected.toList(), actual)
+}
+
+object TestRoutes {
+ val views = allViews;
+}
diff --git a/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/AllTests.kt b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/AllTests.kt
new file mode 100644
index 000000000..a22dcbe9a
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/AllTests.kt
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+package com.vaadin.testbench.unit.internal
+
+import com.github.mvysny.dynatest.DynaTest
+import java.net.URL
+import java.util.*
+import kotlin.test.expect
+
+class AllTests : DynaTest({
+
+ beforeEach {
+ // make sure that Validator produces messages in English
+ Locale.setDefault(Locale.ENGLISH)
+ }
+
+ test("flow-build-info.json doesn't exist") {
+ val res: URL? = Thread.currentThread().contextClassLoader.getResource("META-INF/VAADIN/config/flow-build-info.json")
+ expect(null, "flow-build-info.json exists on the classpath!") { res }
+ }
+
+ group("Depth First Tree Iterator") {
+ depthFirstTreeIteratorTests()
+ }
+
+ group("basic utils") {
+ basicUtilsTestbatch()
+ }
+
+ group("Element Utils") {
+ elementUtilsTests()
+ }
+
+ group("Component Utils") {
+ componentUtilsTests()
+ }
+
+ group("routes test") {
+ routesTestBatch()
+ }
+
+ group("mock vaadin") {
+ mockVaadinTest()
+ }
+
+ group("pretty print tree") {
+ prettyPrintTreeTest()
+ }
+
+ group("locator") {
+ group("with lifecycle hook testing") {
+ locatorTest()
+ }
+ group("no lifecycle hook testing") {
+ locatorTest2()
+ }
+ }
+
+ group("search spec") {
+ searchSpecTest()
+ }
+ group("shortcuts") {
+ shortcutsTestBatch()
+ }
+
+
+})
diff --git a/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/AsyncTest.kt b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/AsyncTest.kt
new file mode 100644
index 000000000..3101f3ea5
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/AsyncTest.kt
@@ -0,0 +1,152 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+package com.vaadin.testbench.unit.internal
+
+import com.github.mvysny.dynatest.DynaNodeGroup
+import com.github.mvysny.dynatest.expectThrows
+import com.vaadin.flow.component.UI
+import com.vaadin.flow.server.*
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+import kotlin.test.expect
+import kotlin.test.fail
+
+internal fun DynaNodeGroup.asyncTestbatch() {
+ group("from UI thread") {
+ test("calling access() won't throw exception but the block won't be called immediately") {
+ var checkAccess = true
+ UI.getCurrent().access { if (checkAccess) fail("Shouldn't be called now") }
+ checkAccess = false
+ }
+
+ test("calling accessSynchronously() calls the block immediately because the tests hold UI lock") {
+ var called = false
+ UI.getCurrent().accessSynchronously { called = true }
+ expect(true) { called }
+ }
+
+ /* TODO: uncomment after importing Locator APIs
+ test("_get() processes access()") {
+ var called = false
+ UI.getCurrent().access { called = true }
+ expect(false) { called }
+ _get()
+ expect(true) { called }
+ }
+ */
+
+ test("clientRoundtrip() processes all access() calls") {
+ var calledCount = 0
+ UI.getCurrent().access(object : Command {
+ override fun execute() {
+ if (calledCount < 4) {
+ calledCount++
+ UI.getCurrent().access(this)
+ }
+ }
+ })
+ expect(0) { calledCount }
+ MockVaadin.clientRoundtrip()
+ expect(4) { calledCount }
+ }
+
+ test("clientRoundtrip() propagates failures") {
+ UI.getCurrent().access { throw RuntimeException("simulated") }
+ expectThrows(ExecutionException::class, "simulated") {
+ MockVaadin.clientRoundtrip()
+ }
+ }
+
+ test("access() has properly mocked instances") {
+ UI.getCurrent().access {
+ expect(true) { VaadinSession.getCurrent() != null }
+ expect(true) { VaadinService.getCurrent() != null }
+ expect(true) { VaadinRequest.getCurrent() != null }
+ expect(true) { UI.getCurrent() != null }
+ expect(true) { VaadinResponse.getCurrent() != null }
+ }
+ MockVaadin.clientRoundtrip()
+ }
+
+ // https://github.com/mvysny/karibu-testing/issues/80
+ test("push() does nothing but can be called") {
+ UI.getCurrent().push()
+ UI.getCurrent().access {
+ UI.getCurrent().push()
+ }
+ MockVaadin.clientRoundtrip()
+ UI.getCurrent().accessSynchronously {
+ UI.getCurrent().push()
+ }
+ }
+ }
+ group("from bg thread") {
+ lateinit var executor: ExecutorService
+ beforeEach { executor = Executors.newCachedThreadPool() }
+ afterEach {
+ executor.shutdown()
+ executor.awaitTermination(4, TimeUnit.SECONDS)
+ }
+ fun asyncAwait(block: (UI) -> Unit) {
+ val ui = UI.getCurrent()
+ executor.submit { block(ui) } .get()
+ }
+
+ test("calling access() won't throw exception but the block won't be called immediately because the tests hold UI lock") {
+ asyncAwait { ui ->
+ var checkAccess = true
+ ui.access { if (checkAccess) fail("Shouldn't be called now") }
+ checkAccess = false
+ }
+ }
+
+ test("clientRoundtrip() processes all access() calls") {
+ var calledCount = 0
+ asyncAwait { ui ->
+ ui.access(object : Command {
+ override fun execute() {
+ if (calledCount < 4) {
+ calledCount++
+ UI.getCurrent().access(this)
+ }
+ }
+ })
+ }
+ expect(0) { calledCount }
+ MockVaadin.clientRoundtrip()
+ expect(4) { calledCount }
+ }
+
+ test("access() has properly mocked instances") {
+ asyncAwait { ui ->
+ ui.access {
+ expect(true) { VaadinSession.getCurrent() != null }
+ expect(true) { VaadinService.getCurrent() != null }
+ expect(true) { VaadinRequest.getCurrent() != null }
+ expect(true) { UI.getCurrent() != null }
+ expect(true) { VaadinResponse.getCurrent() != null }
+ }
+ }
+ MockVaadin.clientRoundtrip()
+ }
+
+ // https://github.com/mvysny/karibu-testing/issues/80
+ test("push() does nothing but can be called") {
+ asyncAwait { ui ->
+ ui.access {
+ UI.getCurrent().push()
+ }
+ }
+ MockVaadin.clientRoundtrip()
+ }
+ }
+}
diff --git a/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/AttachedTextField.kt b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/AttachedTextField.kt
new file mode 100644
index 000000000..c6cc2c6c8
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/AttachedTextField.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+
+package com.vaadin.testbench.unit.internal
+
+import com.vaadin.flow.component.textfield.TextField
+
+/**
+ * TextField for testing which returns that it is attached.
+ */
+class AttachedTextField : TextField() {
+ override fun isAttached(): Boolean {
+ return true
+ }
+}
diff --git a/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/BasicUtilsTest.kt b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/BasicUtilsTest.kt
new file mode 100644
index 000000000..499de8ee4
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/BasicUtilsTest.kt
@@ -0,0 +1,117 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+package com.vaadin.testbench.unit.internal
+
+import com.github.mvysny.dynatest.DynaNodeGroup
+import com.github.mvysny.dynatest.DynaTestDsl
+import com.github.mvysny.dynatest.expectThrows
+import com.github.mvysny.karibudsl.v10.textField
+import com.vaadin.flow.component.ClickEvent
+import com.vaadin.flow.component.html.Div
+import com.vaadin.flow.component.orderedlayout.VerticalLayout
+import com.vaadin.flow.component.textfield.TextField
+import com.vaadin.flow.dom.DomEvent
+import elemental.json.Json
+import kotlin.test.expect
+
+@DynaTestDsl
+internal fun DynaNodeGroup.basicUtilsTestbatch() {
+
+ group("checkEditableByUser") {
+ test("disabled textfield fails") {
+ expectThrows(java.lang.IllegalStateException::class, "The AttachedTextField[DISABLED, value=''] is not enabled") {
+ AttachedTextField().apply { isEnabled = false }.checkEditableByUser()
+ }
+ }
+ test("invisible textfield fails") {
+ expectThrows(
+ java.lang.IllegalStateException::class,
+ "The AttachedTextField[INVIS, value=''] is not effectively visible"
+ ) {
+ AttachedTextField().apply { isVisible = false }.checkEditableByUser()
+ }
+ }
+ test("non attached textfield fails") {
+ expectThrows(
+ java.lang.IllegalStateException::class,
+ "The TextField[value=''] is not attached"
+ ) {
+ TextField().checkEditableByUser()
+ }
+ }
+ test("textfield in invisible layout fails") {
+ expectThrows(java.lang.IllegalStateException::class, "The TextField[value=''] is not effectively visible") {
+ VerticalLayout().apply {
+ isVisible = false
+ textField().also { it.checkEditableByUser() }
+ }
+ }
+ }
+ test("textfield succeeds") {
+ AttachedTextField().checkEditableByUser()
+ }
+ }
+
+ group("expectNotEditableByUser") {
+ test("disabled textfield fails") {
+ AttachedTextField().apply { isEnabled = false }.expectNotEditableByUser()
+ }
+ test("invisible textfield fails") {
+ AttachedTextField().apply { isVisible = false }.expectNotEditableByUser()
+ }
+ test("textfield in invisible layout fails") {
+ VerticalLayout().apply {
+ isVisible = false
+ textField().also { it.expectNotEditableByUser() }
+ }
+ }
+ test("textfield succeeds") {
+ expectThrows(AssertionError::class, "The AttachedTextField[value=''] is editable") {
+ AttachedTextField().expectNotEditableByUser()
+ }
+ }
+ }
+
+ group("fireDomEvent()") {
+ test("smoke") {
+ Div()._fireDomEvent("click")
+ }
+ test("listeners are called") {
+ val div = Div()
+ lateinit var event: DomEvent
+ div.element.addEventListener("click") { e -> event = e }
+ div._fireDomEvent("click")
+ expect("click") { event.type }
+ }
+ test("higher-level listeners are called") {
+ val div = Div()
+ lateinit var event: ClickEvent
+ div.addClickListener { e -> event = e }
+ div._fireDomEvent("click", Json.createObject().apply { put("event.screenX", 20.0) })
+ expect(20) { event.screenX }
+ }
+ }
+
+ test("_focus") {
+ val f = AttachedTextField()
+ var called = false
+ f.addFocusListener { called = true }
+ f._focus()
+ expect(true) { called }
+ }
+
+ test("_blur") {
+ val f = AttachedTextField()
+ var called = false
+ f.addBlurListener { called = true }
+ f._blur()
+ expect(true) { called }
+ }
+}
diff --git a/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/ComponentUtilsTest.kt b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/ComponentUtilsTest.kt
new file mode 100644
index 000000000..dd3505f24
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/ComponentUtilsTest.kt
@@ -0,0 +1,275 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see
.
+ */
+package com.vaadin.testbench.unit.internal
+
+import com.github.mvysny.dynatest.DynaNodeGroup
+import com.github.mvysny.dynatest.expectThrows
+import com.vaadin.flow.component.Component
+import com.vaadin.flow.component.Text
+import com.vaadin.flow.component.UI
+import com.vaadin.flow.component.button.Button
+import com.vaadin.flow.component.checkbox.Checkbox
+import com.vaadin.flow.component.formlayout.FormLayout
+import com.vaadin.flow.component.html.Div
+import com.vaadin.flow.component.html.Label
+import com.vaadin.flow.component.html.Span
+import com.vaadin.flow.component.orderedlayout.FlexLayout
+import com.vaadin.flow.component.orderedlayout.HorizontalLayout
+import com.vaadin.flow.component.textfield.TextArea
+import com.vaadin.flow.component.textfield.TextField
+import kotlin.test.expect
+
+fun DynaNodeGroup.componentUtilsTests() {
+ beforeEach { MockVaadin.setup() }
+ afterEach { MockVaadin.tearDown() }
+
+ group("removeFromParent()") {
+ test("component with no parent") {
+ val t = Text("foo")
+ t.removeFromParent()
+ expect(null) { t.parent.orElse(null) }
+ }
+ test("nested component") {
+ val fl = FlexLayout().apply { add(Label("foo")) }
+ val label = fl.getComponentAt(0)
+ expect(fl) { label.parent.get() }
+ label.removeFromParent()
+ expect(null) { label.parent.orElse(null) }
+ expect(0) { fl.componentCount }
+ }
+ test("reattach") {
+ val fl = FlexLayout().apply { add(Label("foo")) }
+ val label = fl.getComponentAt(0)
+ label.removeFromParent()
+ fl.add(label)
+ expect(fl) { label.parent.orElse(null) }
+ expect(1) { fl.componentCount }
+ }
+ }
+
+ test("serverClick()") {
+ val b = Button()
+ var clicked = 0
+ b.addClickListener { clicked++ }
+ b.serverClick()
+ expect(1) { clicked }
+ }
+
+ test("tooltip") {
+ val b = Button()
+ expect(null) { b.tooltip.text }
+ b.setTooltipText("")
+ expect("") { b.tooltip.text } // https://youtrack.jetbrains.com/issue/KT-32501
+ b.setTooltipText("foo")
+ expect("foo") { b.tooltip.text } // https://youtrack.jetbrains.com/issue/KT-32501
+ b.setTooltipText(null)
+ expect(null) { b.tooltip.text }
+ }
+
+ test("addContextMenuListener smoke") {
+ Button().addContextMenuListener({})
+ }
+
+ group("findAncestor") {
+ test("null on no parent") {
+ expect(null) { Button().findAncestor { false } }
+ }
+ test("null on no acceptance") {
+ val button = Button()
+ UI.getCurrent().add(button)
+ expect(null) { button.findAncestor { false } }
+ }
+ test("finds UI") {
+ val button = Button()
+ UI.getCurrent().add(button)
+ expect(UI.getCurrent()) { button.findAncestor { it is UI } }
+ }
+ test("doesn't find self") {
+ val button = Button()
+ UI.getCurrent().add(button)
+ expect(UI.getCurrent()) { button.findAncestor { true } }
+ }
+ }
+
+ group("findAncestorOrSelf") {
+ test("null on no parent") {
+ expect(null) { Button().findAncestorOrSelf { false } }
+ }
+ test("null on no acceptance") {
+ val button = Button()
+ UI.getCurrent().add(button)
+ expect(null) { button.findAncestorOrSelf { false } }
+ }
+ test("finds self") {
+ val button = Button()
+ UI.getCurrent().add(button)
+ expect(button) { button.findAncestorOrSelf { true } }
+ }
+ }
+
+ test("isNestedIn") {
+ expect(false) { Button().isNestedIn(UI.getCurrent()) }
+ val button = Button()
+ UI.getCurrent().add(button)
+ expect(true) { button.isNestedIn(UI.getCurrent()) }
+ }
+
+ test("isAttached") {
+ expect(true) { UI.getCurrent().isAttached() }
+ expect(false) { Button("foo").isAttached() }
+ expect(true) {
+ val button = Button()
+ UI.getCurrent().add(button)
+ button.isAttached()
+ }
+ UI.getCurrent().close()
+ expect(true) { UI.getCurrent().isAttached() }
+ }
+
+ test("insertBefore") {
+ val l = HorizontalLayout()
+ val first = Span("first")
+ l.addComponentAsFirst(first)
+ val second = Span("second")
+ l.insertBefore(second, first)
+ expect("second, first") { l.children.toList().map { it._text } .joinToString() }
+ l.insertBefore(Span("third"), first)
+ expect("second, third, first") { l.children.toList().map { it._text } .joinToString() }
+ }
+
+ test("hasChildren") {
+ val l = HorizontalLayout()
+ expect(false) { l.hasChildren }
+ l.addComponentAsFirst(Span("first"))
+ expect(true) { l.hasChildren }
+ l.removeAll()
+ expect(false) { l.hasChildren }
+ }
+
+ /*
+ test("isNotEmpty") {
+ val l = HorizontalLayout()
+ expect(false) { l.isNotEmpty }
+ l.addComponentAsFirst(Span("first"))
+ expect(true) { l.isNotEmpty }
+ l.removeAll()
+ expect(false) { l.isNotEmpty }
+ }
+
+ test("isEmpty") {
+ val l = HorizontalLayout()
+ expect(true) { l.isEmpty }
+ l.addComponentAsFirst(Span("first"))
+ expect(false) { l.isEmpty }
+ l.removeAll()
+ expect(true) { l.isEmpty }
+ }
+ */
+
+ group("classnames2") {
+ test("addClassNames2") {
+ val div = Div().apply { addClassNames2("foo bar baz") }
+ expect(true) {
+ div.classNames.containsAll(listOf("foo", "bar", "baz"))
+ }
+ }
+ test("addClassNames2(vararg)") {
+ val div = Div().apply { addClassNames2("foo bar baz", " one two") }
+ expect(true) {
+ div.classNames.containsAll(listOf("foo", "bar", "baz", "one", "two"))
+ }
+ }
+ test("setClassNames2") {
+ val div = Div().apply { addClassNames2("foo bar baz", " one two") }
+ div.setClassNames2(" three four ")
+ expect(true) {
+ div.classNames.containsAll(listOf("three", "four"))
+ }
+ }
+ test("setClassNames2(vararg)") {
+ val div = Div().apply { addClassNames2("foo bar baz", " one two") }
+ div.setClassNames2(" three ", "four ")
+ expect(true) {
+ div.classNames.containsAll(listOf("three", "four"))
+ }
+ }
+ test("removeClassNames2") {
+ val div = Div().apply { addClassNames2("foo bar baz", " one two") }
+ div.removeClassNames2(" bar baz ")
+ expect(true) {
+ div.classNames.containsAll(listOf("foo", "one", "two"))
+ }
+ }
+ test("removeClassNames2(vararg)") {
+ val div = Div().apply { addClassNames2("foo bar baz", " one two") }
+ div.removeClassNames2(" bar ", "baz ")
+ expect(true) {
+ div.classNames.containsAll(listOf("foo", "one", "two"))
+ }
+ }
+ }
+
+ test("placeholder") {
+ var c: Component = TextField().apply { placeholder = "foo" }
+ expect("foo") { c.placeholder }
+ c.placeholder = ""
+ expect("") { c.placeholder }
+ c = TextArea().apply { placeholder = "foo" }
+ expect("foo") { c.placeholder }
+ c.placeholder = ""
+ expect("") { c.placeholder }
+ c = Button() // doesn't support placeholder
+ expect(null) { c.placeholder }
+ expectThrows(IllegalStateException::class, "Button doesn't support setting placeholder") {
+ c.placeholder = "foo"
+ }
+ }
+
+ group("label") {
+ test("TextField") {
+ val c: Component = TextField()
+ expect("") { c.label }
+ c.label = "foo"
+ expect("foo") { c.label }
+ c.label = ""
+ expect("") { c.label }
+ }
+ test("Checkbox") {
+ val c: Component = Checkbox()
+ expect("") { c.label }
+ c.label = "foo"
+ expect("foo") { c.label }
+ c.label = ""
+ expect("") { c.label }
+ }
+ }
+
+ test("caption") {
+ var c: Component = Button("foo")
+ expect("foo") { c.caption }
+ c.caption = ""
+ expect("") { c.caption }
+ c = Checkbox().apply { caption = "foo" }
+ expect("foo") { c.caption }
+ c.caption = ""
+ expect("") { c.caption }
+ expect("") { FormLayout.FormItem().label }
+ val fl = FormLayout()
+ c = fl.addFormItem(Button(), "foo")
+ expect("foo") { c.caption }
+ }
+
+ test("Button.caption") {
+ val c = Button("foo")
+ expect("foo") { c.caption }
+ c.caption = ""
+ expect("") { c.caption }
+ }
+}
diff --git a/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/DepthFirstTreeIteratorTest.kt b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/DepthFirstTreeIteratorTest.kt
new file mode 100644
index 000000000..8210b291f
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/DepthFirstTreeIteratorTest.kt
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+package com.vaadin.testbench.unit.internal
+
+import com.github.mvysny.dynatest.DynaNodeGroup
+import com.github.mvysny.dynatest.expectList
+import com.vaadin.flow.component.Component
+import com.vaadin.flow.component.button.Button
+import com.vaadin.flow.component.html.Label
+import com.vaadin.flow.component.orderedlayout.HorizontalLayout
+import com.vaadin.flow.component.orderedlayout.VerticalLayout
+import kotlin.test.expect
+
+fun DynaNodeGroup.depthFirstTreeIteratorTests() {
+ test("DepthFirstTreeIterator") {
+ val i = DepthFirstTreeIterator("0") { if (it.length > 2) listOf() else listOf("${it}0", "${it}1", "${it}2")}
+ expectList("0", "00", "000", "001", "002", "01", "010", "011", "012", "02", "020", "021", "022") { i.asSequence().toList() }
+ }
+
+ test("walk") {
+ val expected = mutableListOf()
+ val root = VerticalLayout().apply {
+ expected.add(this)
+ add(Button("Foo").apply { expected.add(this) })
+ add(HorizontalLayout().apply {
+ expected.add(this)
+ add(Label().apply { expected.add(this) })
+ })
+ add(VerticalLayout().apply { expected.add(this) })
+ }
+ expect(expected) { root.walk().toList() }
+ expect(root) { root.walk().toList()[0] }
+ }
+}
diff --git a/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/ElementUtilsTest.kt b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/ElementUtilsTest.kt
new file mode 100644
index 000000000..168cab6ea
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/ElementUtilsTest.kt
@@ -0,0 +1,111 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+package com.vaadin.testbench.unit.internal
+
+import com.github.mvysny.dynatest.DynaNodeGroup
+import com.vaadin.flow.component.Text
+import com.vaadin.flow.component.UI
+import com.vaadin.flow.component.button.Button
+import com.vaadin.flow.component.html.Div
+import com.vaadin.flow.component.html.Paragraph
+import com.vaadin.flow.component.html.Span
+import com.vaadin.flow.component.textfield.TextField
+import com.vaadin.flow.dom.DomEvent
+import com.vaadin.flow.dom.Element
+import com.vaadin.testbench.unit.expectList
+import elemental.json.Json
+import kotlin.test.expect
+
+fun DynaNodeGroup.elementUtilsTests() {
+ beforeEach { MockVaadin.setup() }
+ afterEach { MockVaadin.tearDown() }
+
+ test("setOrRemoveAttribute") {
+ val t = Div().element
+ expect(null) { t.getAttribute("foo") }
+ t.setOrRemoveAttribute("foo", "bar")
+ expect("bar") { t.getAttribute("foo") }
+ t.setOrRemoveAttribute("foo", null)
+ expect(null) { t.getAttribute("foo") }
+ }
+
+ group("toggle class name") {
+ test("add") {
+ val t = Div()
+ t.classNames.toggle("test")
+ expect(setOf("test")) { t.classNames }
+ }
+ test("remove") {
+ val t = Div()
+ t.classNames.add("test")
+ t.classNames.toggle("test")
+ expect(setOf()) { t.classNames }
+ }
+ }
+
+ test("insertBefore") {
+ val l = Div().element
+ val first: Element = Span("first").element
+ l.appendChild(first)
+ val second: Element = Span("second").element
+ l.insertBefore(second, first)
+ expect("second, first") { l.children.toList().joinToString { it.text } }
+ l.insertBefore(Span("third").element, first)
+ expect("second, third, first") { l.children.toList().joinToString { it.text } }
+ }
+
+ test("textRecursively2") {
+ expect("foo") { Span("foo").element.textRecursively2 }
+ expect("foobarbaz") {
+ val div = Div()
+ div.add(Span("foo"), Text("bar"), Paragraph("baz"))
+ div.element.textRecursively2
+ }
+ expect("foo") { Element("div").apply { setProperty("innerHTML", "foo") }.textRecursively2 }
+ }
+
+ group("getVirtualChildren()") {
+ test("initially empty") {
+ expectList() { Div().element.getVirtualChildren() }
+ expectList() { Span().element.getVirtualChildren() }
+ expectList() {
+ val b = Button()
+ UI.getCurrent().add(b)
+ b.element.getVirtualChildren()
+ }
+ }
+ test("add virtual child") {
+ val span = Span().element
+ val parent = Div()
+ parent.element.appendVirtualChild(span)
+ expectList(span) { parent.element.getVirtualChildren() }
+ }
+ }
+
+ test("getChildrenInSlot") {
+ expectList() { TextField().element.getChildrenInSlot("prefix") }
+ val div = Div()
+ expectList(div.element) { TextField().apply { prefixComponent = div } .element.getChildrenInSlot("prefix") }
+ }
+
+ test("clearSlot") {
+ val tf = TextField()
+ tf.prefixComponent = Div()
+ tf.element.clearSlot("prefix")
+ expectList() { tf.element.getChildrenInSlot("prefix") }
+ expect(null) { tf.prefixComponent }
+ }
+
+ test("fireDomEvent() smoke") {
+ val element = Div().element
+ element._fireDomEvent(DomEvent(element, "click", Json.createObject()))
+ }
+
+}
diff --git a/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/LocatorTest.kt b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/LocatorTest.kt
new file mode 100644
index 000000000..834618ef7
--- /dev/null
+++ b/vaadin-testbench-unit-junit5/src/test/kotlin/com/vaadin/testbench/unit/internal/LocatorTest.kt
@@ -0,0 +1,413 @@
+/**
+ * Copyright (C) 2022 Vaadin Ltd
+ *
+ * This program is available under Commercial Vaadin Developer License
+ * 4.0 (CVDLv4).
+ *
+ *
+ * For the full License, see .
+ */
+package com.vaadin.testbench.unit.internal
+
+import com.github.mvysny.dynatest.DynaNodeGroup
+import com.github.mvysny.dynatest.DynaTestDsl
+import com.github.mvysny.dynatest.expectThrows
+import com.github.mvysny.karibudsl.v10.button
+import com.github.mvysny.karibudsl.v10.text
+import com.github.mvysny.karibudsl.v10.textField
+import com.github.mvysny.karibudsl.v10.verticalLayout
+import com.vaadin.flow.component.Text
+import com.vaadin.flow.component.UI
+import com.vaadin.flow.component.button.Button
+import com.vaadin.flow.component.combobox.ComboBox
+import com.vaadin.flow.component.dialog.Dialog
+import com.vaadin.flow.component.html.Label
+import com.vaadin.flow.component.orderedlayout.VerticalLayout
+import com.vaadin.flow.component.textfield.PasswordField
+import com.vaadin.flow.component.textfield.TextField
+import com.vaadin.testbench.unit.expectList
+import java.util.function.Predicate
+import kotlin.streams.asSequence
+import kotlin.test.expect
+
+@DynaTestDsl
+internal fun DynaNodeGroup.locatorTest2() {
+ beforeEach { MockVaadin.setup() }
+ afterEach { MockVaadin.tearDown() }
+
+ test("_expectNoDialogs()") {
+ _expectNoDialogs() // should succeed on no dialogs
+ val dlg = Dialog()
+ dlg.open()
+ expectThrows(AssertionError::class,
+ """Too many visible Dialogs (1) in MockedUI[] matching Dialog and count=0..0: [Dialog[opened='true']]. Component tree:
+└── MockedUI[]
+ └── Dialog[opened='true']
+""") {
+ _expectNoDialogs()
+ }
+ dlg.close()
+ _expectNoDialogs()
+ }
+
+ group("InternalServerError handling") {
+ test("component lookup fails on navigation error") {
+ // Vaadin shows InternalServerError when an exception occurs during the navigation phase.
+ // the _expect*() functions should detect this and fail fast.
+ currentUI.addBeforeEnterListener { event -> event.rerouteToError(RuntimeException("Simulated"), "Simulated") }
+ UI.getCurrent().navigate("")
+ expectThrows("An internal server error occurred; please check log for the actual stack-trace. Error text: There was an exception while trying to navigate to") {
+ _expectOne()
+ }
+ }
+ group("_expectInternalServerError") {
+ test("fails on no error") {
+ expectThrows(
+ """Expected an internal server error but none happened. Component tree:
+└── MockedUI[]"""
+ ) { _expectInternalServerError() }
+ }
+ test("succeeds on error") {
+ currentUI.addBeforeEnterListener { event -> event.rerouteToError(RuntimeException("Simulated"), "Simulated") }
+ UI.getCurrent().navigate("")
+ _expectInternalServerError()
+ }
+ test("matches error message correctly") {
+ currentUI.addBeforeEnterListener { event -> event.rerouteToError(RuntimeException("Simulated"), "Simulated") }
+ UI.getCurrent().navigate("")
+ _expectInternalServerError("Simulated")
+ }
+ }
+ }
+}
+
+@DynaTestDsl
+internal fun DynaNodeGroup.locatorTest() {
+
+ beforeEach { MockVaadin.setup() }
+ beforeEach { testingLifecycleHook = MyLifecycleHook() }
+ afterEach { testingLifecycleHook = TestingLifecycleHook.default }
+ afterEach { MockVaadin.tearDown() }
+
+ group("_get") {
+ test("fails when no component match") {
+ expectThrows(AssertionError::class) {
+ Button()._get(TextField::class.java)
+ }
+ expectAfterLookupCalled()
+ }
+
+ test("fail when multiple component match") {
+ expectThrows(AssertionError::class) {
+ UI.getCurrent().verticalLayout {
+ verticalLayout { }
+ }._get(VerticalLayout::class.java)
+ }
+ expectAfterLookupCalled()
+ }
+
+ test("ReturnsSelf") {
+ val button = Button()
+ expect(button) { button._get(Button::class.java) }
+ expectAfterLookupCalled()
+ }
+
+ test("ReturnsNested") {
+ val button = Button()
+ expect(button) { VerticalLayout(button)._get(Button::class.java) }
+ expectAfterLookupCalled()
+ }
+
+ test("fails on invisible") {
+ val button = Button().apply { isVisible = false }
+ expectThrows(java.lang.AssertionError::class) { button._get(Button::class.java) }
+ expectAfterLookupCalled()
+ }
+ }
+
+ group("_find") {
+ test("findMatchingId") {
+ val button = Button().apply { id_ = "foo" }
+ expectList(button) { VerticalLayout(button, Button())._find