|
21 | 21 | import java.util.Properties; |
22 | 22 | import java.util.Set; |
23 | 23 | import java.util.concurrent.ConcurrentHashMap; |
| 24 | +import java.util.concurrent.TimeUnit; |
24 | 25 | import java.util.stream.Collectors; |
25 | 26 | import java.util.stream.Stream; |
26 | 27 |
|
|
31 | 32 | import org.slf4j.Logger; |
32 | 33 | import org.slf4j.LoggerFactory; |
33 | 34 |
|
| 35 | +import com.vaadin.experimental.FeatureFlags; |
34 | 36 | import com.vaadin.flow.component.Component; |
35 | 37 | import com.vaadin.flow.component.HasElement; |
36 | 38 | import com.vaadin.flow.component.Key; |
37 | 39 | import com.vaadin.flow.component.KeyModifier; |
38 | 40 | import com.vaadin.flow.component.UI; |
39 | 41 | import com.vaadin.flow.router.HasUrlParameter; |
40 | 42 | import com.vaadin.flow.router.RouteParameters; |
| 43 | +import com.vaadin.flow.server.VaadinService; |
| 44 | +import com.vaadin.flow.server.VaadinSession; |
41 | 45 | import com.vaadin.pro.licensechecker.Capabilities; |
42 | 46 | import com.vaadin.pro.licensechecker.Capability; |
43 | 47 | import com.vaadin.pro.licensechecker.LicenseChecker; |
@@ -71,6 +75,8 @@ public abstract class BaseUIUnitTest { |
71 | 75 | protected static final Map<Class<?>, Class<? extends ComponentTester>> testers = new HashMap<>(); |
72 | 76 | protected static final Set<String> scanned = new HashSet<>(); |
73 | 77 |
|
| 78 | + private TestSignalEnvironment signalsTestEnvironment; |
| 79 | + |
74 | 80 | static { |
75 | 81 | testers.putAll(scanForTesters("com.vaadin.flow.component")); |
76 | 82 | Properties properties = new Properties(); |
@@ -180,6 +186,19 @@ protected static synchronized Routes discoverRoutes( |
180 | 186 | protected void initVaadinEnvironment() { |
181 | 187 | scanTesters(); |
182 | 188 | MockVaadin.setup(discoverRoutes(), MockedUI::new, lookupServices()); |
| 189 | + initSignalsSupport(); |
| 190 | + } |
| 191 | + |
| 192 | + protected void initSignalsSupport() { |
| 193 | + VaadinService service = VaadinService.getCurrent(); |
| 194 | + if (service == null) { |
| 195 | + throw new IllegalStateException( |
| 196 | + "Cannot initialize Signals support because VaadinService is not available"); |
| 197 | + } |
| 198 | + if (FeatureFlags.get(service.getContext()) |
| 199 | + .isEnabled(FeatureFlags.FLOW_FULLSTACK_SIGNALS.getId())) { |
| 200 | + signalsTestEnvironment = TestSignalEnvironment.register(); |
| 201 | + } |
183 | 202 | } |
184 | 203 |
|
185 | 204 | /** |
@@ -223,6 +242,10 @@ Set<String> scanPackages() { |
223 | 242 | * Tears down mocked Vaadin. |
224 | 243 | */ |
225 | 244 | protected void cleanVaadinEnvironment() { |
| 245 | + if (signalsTestEnvironment != null) { |
| 246 | + signalsTestEnvironment.unregister(); |
| 247 | + signalsTestEnvironment = null; |
| 248 | + } |
226 | 249 | MockVaadin.tearDown(); |
227 | 250 | } |
228 | 251 |
|
@@ -512,6 +535,70 @@ protected static void roundTrip() { |
512 | 535 | .runExecutionsBeforeClientResponse(); |
513 | 536 | } |
514 | 537 |
|
| 538 | + /** |
| 539 | + * Processes all pending Signals tasks with a default max wait time of 100 |
| 540 | + * milliseconds. This is a convenience method for tests that need to wait |
| 541 | + * for asynchronous Signal effects to complete. |
| 542 | + * |
| 543 | + * <p> |
| 544 | + * When Signals are triggered from background threads or non-UI contexts, |
| 545 | + * their effects are enqueued to simulate asynchronous processing. This |
| 546 | + * method allows tests to flush and execute all such pending tasks |
| 547 | + * synchronously, ensuring deterministic behavior in unit tests. |
| 548 | + * |
| 549 | + * <p> |
| 550 | + * If any {@link VaadinSession} lock is held by the current thread, it is |
| 551 | + * temporarily released during the wait to allow background threads to |
| 552 | + * acquire the lock and enqueue tasks. |
| 553 | + * |
| 554 | + * <p> |
| 555 | + * If Signals support is not enabled (via the {@code FLOW_FULLSTACK_SIGNALS} |
| 556 | + * feature flag), this method does nothing. |
| 557 | + * |
| 558 | + * @see #runPendingSignalsTasks(long, TimeUnit) |
| 559 | + * @see TestSignalEnvironment#runPendingTasks(long, TimeUnit) |
| 560 | + */ |
| 561 | + protected final void runPendingSignalsTasks() { |
| 562 | + runPendingSignalsTasks(100, TimeUnit.MILLISECONDS); |
| 563 | + } |
| 564 | + |
| 565 | + /** |
| 566 | + * Processes all pending Signals tasks, waiting up to the specified timeout |
| 567 | + * for tasks to arrive. This method is essential for testing asynchronous |
| 568 | + * Signal effects triggered from background threads or non-UI contexts. |
| 569 | + * |
| 570 | + * <p> |
| 571 | + * When Signals are triggered from background threads or non-UI contexts, |
| 572 | + * their effects are enqueued to simulate asynchronous processing. This |
| 573 | + * method allows tests to flush and execute all such pending tasks |
| 574 | + * synchronously, ensuring deterministic behavior in unit tests. |
| 575 | + * |
| 576 | + * <p> |
| 577 | + * The timeout applies only to waiting for the first task to arrive. Once |
| 578 | + * the first task is found, all remaining tasks in the queue are processed |
| 579 | + * immediately without additional waiting. If any {@link VaadinSession} lock |
| 580 | + * is held by the current thread, it is temporarily released during the wait |
| 581 | + * to allow background threads to acquire the lock and enqueue tasks. |
| 582 | + * |
| 583 | + * <p> |
| 584 | + * If Signals support is not enabled (via the {@code FLOW_FULLSTACK_SIGNALS} |
| 585 | + * feature flag), this method does nothing. |
| 586 | + * |
| 587 | + * @param maxWaitTime |
| 588 | + * the maximum time to wait for the first task to arrive in the |
| 589 | + * given time unit. If <= 0, returns immediately if no tasks |
| 590 | + * are available. |
| 591 | + * @param unit |
| 592 | + * the time unit of the timeout value |
| 593 | + * @see TestSignalEnvironment#runPendingTasks(long, TimeUnit) |
| 594 | + */ |
| 595 | + protected final void runPendingSignalsTasks(long maxWaitTime, |
| 596 | + TimeUnit unit) { |
| 597 | + if (this.signalsTestEnvironment != null) { |
| 598 | + this.signalsTestEnvironment.runPendingTasks(maxWaitTime, unit); |
| 599 | + } |
| 600 | + } |
| 601 | + |
515 | 602 | /** |
516 | 603 | * Detects the component type for the given tester from generic declaration, |
517 | 604 | * by inspecting class hierarchy to resolve the concrete type for |
|
0 commit comments