From b091a90f36ed45de872dc23803519be34bac5ff3 Mon Sep 17 00:00:00 2001 From: mikhail Date: Mon, 21 Sep 2026 11:48:03 +0300 Subject: [PATCH 1/5] docs: describe per-test Vaadin configuration for browserless tests A browserless test can now set Vaadin application properties, feature flags, and Lookup services for a single test class or test method with @BrowserlessTestConfig, or build the same configuration in code. The settings are scoped to the environment created for that test, so a feature flag no longer needs development mode, a properties file in the project folder, or a @BeforeEach and @AfterEach pair to reset it. Adds a Test Configuration page covering the annotation, the merge rules for inherited and method-level declarations, and the programmatic surfaces, and links to it from the extension configuration table. Co-Authored-By: Claude Opus 5 (1M context) --- .../flow/testing/browserless/extensions.adoc | 11 ++ .../browserless/test-configuration.adoc | 121 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 articles/flow/testing/browserless/test-configuration.adoc diff --git a/articles/flow/testing/browserless/extensions.adoc b/articles/flow/testing/browserless/extensions.adoc index 797daf6dcd..4e83e360e5 100644 --- a/articles/flow/testing/browserless/extensions.adoc +++ b/articles/flow/testing/browserless/extensions.adoc @@ -102,8 +102,19 @@ Both extensions support a builder-style API for configuration, used as an altern | [methodname]`withComponentTesterPackages(String...)` | Adds packages to scan for custom [classname]`ComponentTester` implementations. Equivalent to [annotationname]`@ComponentTesterPackages`. + +| [since:com.vaadin:vaadin@V25.3]#[methodname]`withApplicationProperty(String, String)`# +| Sets a Vaadin application property for the environment the extension creates. [methodname]`withApplicationProperties(Map)` sets several at once. + +| [since:com.vaadin:vaadin@V25.3]#[methodname]`withFeatureFlags(String...)`# +| Enables the given feature flags. [methodname]`withFeatureFlag(String, boolean)` enables or disables a single flag. + +| [since:com.vaadin:vaadin@V25.3]#[methodname]`withConfiguration(BrowserlessConfiguration)`# +| Applies a configuration built elsewhere, so that several test classes can share it. |=== +Application properties, feature flags, and [classname]`Lookup` services can also be declared with the [annotationname]`@BrowserlessTestConfig` annotation, on a test class or on a single test method. See <>. + The [annotationname]`@ViewPackages` annotation still works when placed on the test class; programmatic configuration adds to what the annotation declares. .Extension with Programmatic Configuration diff --git a/articles/flow/testing/browserless/test-configuration.adoc b/articles/flow/testing/browserless/test-configuration.adoc new file mode 100644 index 0000000000..a8e70d4cb8 --- /dev/null +++ b/articles/flow/testing/browserless/test-configuration.adoc @@ -0,0 +1,121 @@ +--- +title: Test Configuration +page-title: How to configure the Vaadin environment of a browserless test +description: Set Vaadin application properties, feature flags, and Lookup services for a single test class or test method. +meta-description: Configure Vaadin application properties, feature flags, and Lookup services for a single browserless test with the BrowserlessTestConfig annotation. +order: 46 +--- + + += [since:com.vaadin:vaadin@V25.3]#Test Configuration# + +Some tests need a Vaadin environment configured differently from the rest of the suite: a view behind a feature flag, or a setting such as `devmode.sessionSerialization.enabled`. Annotate the test class, or a single test method, with [annotationname]`@BrowserlessTestConfig`: + +[source,java] +---- +@ViewPackages(classes = CartView.class) +@BrowserlessTestConfig( + applicationProperties = "devmode.sessionSerialization.enabled=true", + featureFlags = "myExperimentalFeature") +class CartViewTest extends BrowserlessTest { + + @Test + void experimentalCheckoutIsShown() { + // The feature flag is enabled for this test + } + + @Test + @BrowserlessTestConfig(featureFlags = "myExperimentalFeature=false") + void fallbackCheckoutIsShown() { + // The same class, with the flag off for this method only + } +} +---- + +Each setting applies to the Vaadin environment created for the annotated test, so there is nothing to reset afterwards, and nothing leaks into the next test. + + +== Settings + +[cols="1,2"] +|=== +| Attribute | Description + +| [propertyname]`applicationProperties` +| `name=value` pairs applied to the Vaadin deployment configuration, such as `"devmode.sessionSerialization.enabled=true"`. The value is everything after the first `=`, so a value can itself contain `=`. The properties are set before the servlet starts, so code that runs at startup, such as a [interfacename]`VaadinServiceInitListener`, already sees them. + +| [propertyname]`featureFlags` +| Either a feature identifier, to enable the feature, or an `id=true\|false` pair. These flags override the [filename]`vaadin-featureflags.properties` file and the `vaadin.experimental.*` system properties. Toggling a flag this way needs no development mode and writes nothing into the project folder. An unknown identifier fails with an error that lists the available flags. + +| [propertyname]`lookupServices` +| Implementation classes registered with the Vaadin [classname]`Lookup`, such as an [interfacename]`InstantiatorFactory` or a [interfacename]`ResourceProvider`. +|=== + +The `browserless` application property itself stays enforced and cannot be overridden. + + +== Merging Class and Method Configuration + +Every annotation a test inherits contributes to the configuration, rather than being shadowed by the nearest one. The closer a declaration is to the test method, the higher it ranks: the method first, then the test class, then superclasses from the nearest up, and then, for a [annotationname]`@Nested` test, enclosing classes from the innermost out. + +[source,java] +---- +@BrowserlessTestConfig(applicationProperties = "base.property=fromBase") +abstract class AbstractViewTest extends BrowserlessTest { +} + +@BrowserlessTestConfig(featureFlags = "myExperimentalFeature") +class CartViewTest extends AbstractViewTest { + // Both base.property and myExperimentalFeature apply +} +---- + +Lookup services are the exception: they accumulate instead of replacing each other, so a test method can add a service, but cannot remove one that its test class declares. The services that the Spring and Quarkus integrations need are always registered, and the test configuration never affects them. + +A method-level annotation needs an environment built for each test method. When one environment is shared by the whole class, as with [classname]`BrowserlessClassExtension`, the annotation is rejected with an error naming the methods that carry it. Move it to the test class in that case. + + +== Configuring Without Annotations + +The same settings can be built in code. On a JUnit 6 extension: + +[source,java] +---- +@RegisterExtension +BrowserlessExtension extension = new BrowserlessExtension() + .withApplicationProperty("devmode.sessionSerialization.enabled", "true") + .withFeatureFlags("myExperimentalFeature"); +---- + +On the application context builder of a multi-user test: + +[source,java] +---- +try (var app = BrowserlessApplicationContext.create(builder -> builder + .withViewPackages(CartView.class) + .withFeatureFlags("myExperimentalFeature"))) { + // ... +} +---- + +Or by overriding [methodname]`testConfiguration()` on a test that extends a base class: + +[source,java] +---- +@Override +protected BrowserlessConfiguration testConfiguration() { + return BrowserlessConfiguration.builder() + .withConfiguration(super.testConfiguration()) + .withFeatureFlags("myExperimentalFeature") + .build(); +} +---- + +A configuration built on an extension or on the application context builder wins over the class-level annotation, and loses against the method-level one. A [methodname]`testConfiguration()` override ranks differently: [methodname]`super.testConfiguration()` returns the configuration already resolved from the annotations, so whatever the override adds on top of it wins over all of them, the method-level annotation included. Build on [methodname]`super.testConfiguration()` to refine the declared configuration, and leave out the values that a test method needs to override. + +.Spring Properties Win +[NOTE] +With Spring, a Vaadin property defined in the Spring environment, such as `vaadin.devmode.sessionSerialization.enabled` in [filename]`application.properties`, is applied by [classname]`SpringServlet` on top of the test configuration, and therefore wins over [annotationname]`@BrowserlessTestConfig`. Use [annotationname]`@TestPropertySource` to override such a property for a test. Properties that are not Vaadin init parameters are unaffected. + + +[discussion-id]`CD70CAA5-6506-4810-BED5-0F54DCE2F0FA` From 6ec3a6271012e08375e74e5fbeb6b95ec8b9940f Mon Sep 17 00:00:00 2001 From: mikhail Date: Mon, 21 Sep 2026 11:51:24 +0300 Subject: [PATCH 2/5] docs: note the moved browserless lookup services in the upgrade guide The services of the Spring and Quarkus integrations moved to frameworkLookupServices() and are always registered, so an override of lookupServices() adds to them rather than replacing them, and the method is deprecated in favor of the test configuration. Co-Authored-By: Claude Opus 5 (1M context) --- articles/upgrading/index.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/articles/upgrading/index.adoc b/articles/upgrading/index.adoc index 2b377f12e6..5ba704209b 100644 --- a/articles/upgrading/index.adoc +++ b/articles/upgrading/index.adoc @@ -1138,6 +1138,10 @@ Because of the change, the [classname]`com.vaadin.flow.component.html.testbench. The [methodname]`getPropertyString`, [methodname]`getPropertyBoolean`, [methodname]`getPropertyDouble` and [methodname]`getPropertyInteger` methods of the [classname]`TestBenchElement` class have been changed to not convert property values to the respective result types anymore. For example, calling [methodname]`getPropertyString` on a property that contains a number value will now throw an exception instead of returning the string representation of the number. +=== Browserless Testing: Lookup Services of the Spring and Quarkus Integrations + +The services that the Spring and Quarkus integrations need have moved from [methodname]`lookupServices()` to [methodname]`frameworkLookupServices()`, and are registered in every case. An override of [methodname]`lookupServices()` therefore adds to them instead of replacing them, which is what keeps those integrations working, and the resulting [classname]`Lookup` holds more services than before. [methodname]`lookupServices()` itself is deprecated in favor of the test configuration, which declares the same services on a test class or a test method. See <<{articles}/flow/testing/browserless/test-configuration#,Test Configuration>>. + == Binder [methodname]`Binder.validate()` implementation has been changed to behave as its Javadoc states. In other words, [methodname]`Binder.validate()` no longer fails when bean level validators have been configured but no bean is currently set (i.e. [classname]`Binder` is used in buffered mode). From dba4527ee631800d8aa419d2d299bc21c02167cd Mon Sep 17 00:00:00 2001 From: "totally-not-ai[bot]" <290682512+totally-not-ai[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 07:41:44 +0000 Subject: [PATCH 3/5] docs: list the application context builder configuration methods The multi-user builder table is where a multi-user test looks for them, and they are the programmatic form of the test configuration annotation. --- articles/flow/testing/browserless/multi-user.adoc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/articles/flow/testing/browserless/multi-user.adoc b/articles/flow/testing/browserless/multi-user.adoc index 5d3b3ad2ad..805ea6ce05 100644 --- a/articles/flow/testing/browserless/multi-user.adoc +++ b/articles/flow/testing/browserless/multi-user.adoc @@ -346,8 +346,19 @@ For advanced setups, [classname]`BrowserlessApplicationContext.Builder` exposes | [methodname]`withCloseHook(Runnable)` | Registers a callback to run after the context tears down -- intended for releasing framework-specific state. + +| [since:com.vaadin:vaadin@V25.3]#[methodname]`withApplicationProperty(String, String)` / [methodname]`withApplicationProperties(String...)`# +| Sets Vaadin application properties for the environment the context creates. + +| [since:com.vaadin:vaadin@V25.3]#[methodname]`withFeatureFlags(String...)` / [methodname]`withFeatureFlags(Feature...)` / [methodname]`withFeatureFlag(String, boolean)` / [methodname]`withFeatureFlag(Feature, boolean)`# +| Enables or disables feature flags for the environment the context creates. + +| [since:com.vaadin:vaadin@V25.3]#[methodname]`withConfiguration(BrowserlessConfiguration)`# +| Applies a configuration built elsewhere as the baseline that the other methods add to -- the one resolved for the current test, for example. |=== +The property, feature flag, and configuration methods are the programmatic form of [annotationname]`@BrowserlessTestConfig`; see <>. [classname]`SecuredBrowserlessApplicationContext.Builder` exposes the same methods. + For one-off tweaks without holding on to a builder reference, [methodname]`BrowserlessApplicationContext.create(UnaryOperator)` and the corresponding [methodname]`createSecured(Function>)` accept a configurer: [source,java] From 57ba66b4a5a78bcab56277e2d9686b9f34ec3b53 Mon Sep 17 00:00:00 2001 From: "totally-not-ai[bot]" <290682512+totally-not-ai[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 11:43:55 +0000 Subject: [PATCH 4/5] docs: correct the configuration precedence of the application context A BrowserlessApplicationContext is built in code rather than by a JUnit extension, so it does not resolve @BrowserlessTestConfig at all: the precedence over the class-level annotation applies only to the extensions. Shows BrowserlessConfiguration.from(...) as the way to reuse the configuration a test class declares. Co-Authored-By: Claude Opus 5 (1M context) --- articles/flow/testing/browserless/multi-user.adoc | 4 ++-- .../testing/browserless/test-configuration.adoc | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/articles/flow/testing/browserless/multi-user.adoc b/articles/flow/testing/browserless/multi-user.adoc index 805ea6ce05..3e97e7b12c 100644 --- a/articles/flow/testing/browserless/multi-user.adoc +++ b/articles/flow/testing/browserless/multi-user.adoc @@ -354,10 +354,10 @@ For advanced setups, [classname]`BrowserlessApplicationContext.Builder` exposes | Enables or disables feature flags for the environment the context creates. | [since:com.vaadin:vaadin@V25.3]#[methodname]`withConfiguration(BrowserlessConfiguration)`# -| Applies a configuration built elsewhere as the baseline that the other methods add to -- the one resolved for the current test, for example. +| Applies a configuration built elsewhere as the baseline that the other methods add to, such as [methodname]`BrowserlessConfiguration.from(getClass())` to reuse what the test class declares with [annotationname]`@BrowserlessTestConfig`. |=== -The property, feature flag, and configuration methods are the programmatic form of [annotationname]`@BrowserlessTestConfig`; see <>. [classname]`SecuredBrowserlessApplicationContext.Builder` exposes the same methods. +The property, feature flag, and configuration methods are the programmatic form of [annotationname]`@BrowserlessTestConfig`, which the context itself does not read; see <>. [classname]`SecuredBrowserlessApplicationContext.Builder` exposes the same methods. For one-off tweaks without holding on to a builder reference, [methodname]`BrowserlessApplicationContext.create(UnaryOperator)` and the corresponding [methodname]`createSecured(Function>)` accept a configurer: diff --git a/articles/flow/testing/browserless/test-configuration.adoc b/articles/flow/testing/browserless/test-configuration.adoc index a8e70d4cb8..e262159f29 100644 --- a/articles/flow/testing/browserless/test-configuration.adoc +++ b/articles/flow/testing/browserless/test-configuration.adoc @@ -98,6 +98,19 @@ try (var app = BrowserlessApplicationContext.create(builder -> builder } ---- +A [classname]`BrowserlessApplicationContext` is created in plain code rather than by a JUnit extension, so it never looks at [annotationname]`@BrowserlessTestConfig`: only what its own builder declares applies. To reuse the configuration declared by a test class, pass it explicitly with [methodname]`BrowserlessConfiguration.from(...)`: + +[source,java] +---- +try (var app = BrowserlessApplicationContext.create(builder -> builder + .withViewPackages(CartView.class) + .withConfiguration(BrowserlessConfiguration.from(getClass())))) { + // ... +} +---- + +[methodname]`from(...)` reads a single annotation -- the one declared on the given class, or the one inherited from its nearest annotated superclass -- rather than merging the whole hierarchy the way an extension does. + Or by overriding [methodname]`testConfiguration()` on a test that extends a base class: [source,java] @@ -111,7 +124,7 @@ protected BrowserlessConfiguration testConfiguration() { } ---- -A configuration built on an extension or on the application context builder wins over the class-level annotation, and loses against the method-level one. A [methodname]`testConfiguration()` override ranks differently: [methodname]`super.testConfiguration()` returns the configuration already resolved from the annotations, so whatever the override adds on top of it wins over all of them, the method-level annotation included. Build on [methodname]`super.testConfiguration()` to refine the declared configuration, and leave out the values that a test method needs to override. +On an extension, a configuration built in code wins over the class-level annotation, and loses against the method-level one. A [methodname]`testConfiguration()` override ranks differently: [methodname]`super.testConfiguration()` returns the configuration already resolved from the annotations, so whatever the override adds on top of it wins over all of them, the method-level annotation included. Build on [methodname]`super.testConfiguration()` to refine the declared configuration, and leave out the values that a test method needs to override. .Spring Properties Win [NOTE] From 7d2161a8a688038ca04d9223c2b0ecffa76f21d2 Mon Sep 17 00:00:00 2001 From: "totally-not-ai[bot]" <290682512+totally-not-ai[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 11:49:21 +0000 Subject: [PATCH 5/5] docs: correct the browserless test configuration reference details Aligns the extension and application context builder tables with the actual signatures: withApplicationProperties() takes a Map in both, and both the String and Feature overloads exist on either side. Notes that a method level annotation needs BrowserlessExtension, since the class extension rejects it, and spells out that the merge resolves each property name or feature id to the nearest declaration while lookup services only accumulate. Names BaseBrowserlessTest and the version in the upgrade guide entry, and cross-links the feature flag page both ways, so that the test-scoped way to toggle a flag is discoverable from where flags are managed. Co-Authored-By: Claude Opus 5 (1M context) --- articles/flow/configuration/feature-flags.adoc | 2 ++ articles/flow/testing/browserless/extensions.adoc | 6 +++--- articles/flow/testing/browserless/multi-user.adoc | 6 +++--- articles/flow/testing/browserless/test-configuration.adoc | 6 +++--- articles/upgrading/index.adoc | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/articles/flow/configuration/feature-flags.adoc b/articles/flow/configuration/feature-flags.adoc index 90c0bc2202..40ba1ceecf 100644 --- a/articles/flow/configuration/feature-flags.adoc +++ b/articles/flow/configuration/feature-flags.adoc @@ -77,6 +77,8 @@ Enables <<{articles}/hilla/guides/full-stack-signals#, Hilla Full-stack Signals> Feature flags can be managed in different ways: by using Vaadin Copilot; by editing the feature flags properties file; or by setting Java system properties. Each of these methods is described in the sub-sections that follow. As you read, keep in mind that system properties always have the highest priority. Since they're not written into the feature flags properties file, they're valid only for a single execution. +A <<{articles}/flow/testing/browserless/test-configuration#, browserless test>> is the exception: it can enable a flag for a single test class or test method, overriding all of the sources below. + === Vaadin Copilot diff --git a/articles/flow/testing/browserless/extensions.adoc b/articles/flow/testing/browserless/extensions.adoc index 4e83e360e5..93a64d0e2a 100644 --- a/articles/flow/testing/browserless/extensions.adoc +++ b/articles/flow/testing/browserless/extensions.adoc @@ -107,13 +107,13 @@ Both extensions support a builder-style API for configuration, used as an altern | Sets a Vaadin application property for the environment the extension creates. [methodname]`withApplicationProperties(Map)` sets several at once. | [since:com.vaadin:vaadin@V25.3]#[methodname]`withFeatureFlags(String...)`# -| Enables the given feature flags. [methodname]`withFeatureFlag(String, boolean)` enables or disables a single flag. +| Enables the given feature flags. [methodname]`withFeatureFlag(String, boolean)` enables or disables a single flag. Both methods also have a [classname]`Feature` overload. | [since:com.vaadin:vaadin@V25.3]#[methodname]`withConfiguration(BrowserlessConfiguration)`# -| Applies a configuration built elsewhere, so that several test classes can share it. +| Applies a configuration built elsewhere as the baseline that the other methods add to, so that several test classes can share it. |=== -Application properties, feature flags, and [classname]`Lookup` services can also be declared with the [annotationname]`@BrowserlessTestConfig` annotation, on a test class or on a single test method. See <>. +Application properties, feature flags, and [classname]`Lookup` services can also be declared with the [annotationname]`@BrowserlessTestConfig` annotation. On [classname]`BrowserlessExtension` it works both on the test class and on a single test method; [classname]`BrowserlessClassExtension` creates one environment for the whole class, so there the annotation belongs on the test class. See <>. The [annotationname]`@ViewPackages` annotation still works when placed on the test class; programmatic configuration adds to what the annotation declares. diff --git a/articles/flow/testing/browserless/multi-user.adoc b/articles/flow/testing/browserless/multi-user.adoc index 3e97e7b12c..d4ff290c6d 100644 --- a/articles/flow/testing/browserless/multi-user.adoc +++ b/articles/flow/testing/browserless/multi-user.adoc @@ -347,11 +347,11 @@ For advanced setups, [classname]`BrowserlessApplicationContext.Builder` exposes | [methodname]`withCloseHook(Runnable)` | Registers a callback to run after the context tears down -- intended for releasing framework-specific state. -| [since:com.vaadin:vaadin@V25.3]#[methodname]`withApplicationProperty(String, String)` / [methodname]`withApplicationProperties(String...)`# +| [since:com.vaadin:vaadin@V25.3]#[methodname]`withApplicationProperty(String, String)` / [methodname]`withApplicationProperties(Map)`# | Sets Vaadin application properties for the environment the context creates. -| [since:com.vaadin:vaadin@V25.3]#[methodname]`withFeatureFlags(String...)` / [methodname]`withFeatureFlags(Feature...)` / [methodname]`withFeatureFlag(String, boolean)` / [methodname]`withFeatureFlag(Feature, boolean)`# -| Enables or disables feature flags for the environment the context creates. +| [since:com.vaadin:vaadin@V25.3]#[methodname]`withFeatureFlags(String...)` / [methodname]`withFeatureFlag(String, boolean)`# +| Enables or disables feature flags for the environment the context creates. Both methods also have a [classname]`Feature` overload. | [since:com.vaadin:vaadin@V25.3]#[methodname]`withConfiguration(BrowserlessConfiguration)`# | Applies a configuration built elsewhere as the baseline that the other methods add to, such as [methodname]`BrowserlessConfiguration.from(getClass())` to reuse what the test class declares with [annotationname]`@BrowserlessTestConfig`. diff --git a/articles/flow/testing/browserless/test-configuration.adoc b/articles/flow/testing/browserless/test-configuration.adoc index e262159f29..b90b9f91d7 100644 --- a/articles/flow/testing/browserless/test-configuration.adoc +++ b/articles/flow/testing/browserless/test-configuration.adoc @@ -45,7 +45,7 @@ Each setting applies to the Vaadin environment created for the annotated test, s | `name=value` pairs applied to the Vaadin deployment configuration, such as `"devmode.sessionSerialization.enabled=true"`. The value is everything after the first `=`, so a value can itself contain `=`. The properties are set before the servlet starts, so code that runs at startup, such as a [interfacename]`VaadinServiceInitListener`, already sees them. | [propertyname]`featureFlags` -| Either a feature identifier, to enable the feature, or an `id=true\|false` pair. These flags override the [filename]`vaadin-featureflags.properties` file and the `vaadin.experimental.*` system properties. Toggling a flag this way needs no development mode and writes nothing into the project folder. An unknown identifier fails with an error that lists the available flags. +| Either a feature identifier, to enable the feature, or an `id=true\|false` pair. These flags override the <<{articles}/flow/configuration/feature-flags#, feature flag>> sources that apply outside a test -- the [filename]`vaadin-featureflags.properties` file and the `vaadin.experimental.*` system properties. Toggling a flag this way needs no development mode and writes nothing into the project folder. An unknown identifier fails with an error that lists the available flags. | [propertyname]`lookupServices` | Implementation classes registered with the Vaadin [classname]`Lookup`, such as an [interfacename]`InstantiatorFactory` or a [interfacename]`ResourceProvider`. @@ -56,7 +56,7 @@ The `browserless` application property itself stays enforced and cannot be overr == Merging Class and Method Configuration -Every annotation a test inherits contributes to the configuration, rather than being shadowed by the nearest one. The closer a declaration is to the test method, the higher it ranks: the method first, then the test class, then superclasses from the nearest up, and then, for a [annotationname]`@Nested` test, enclosing classes from the innermost out. +Every annotation a test inherits contributes to the configuration, rather than being shadowed by the nearest one. The merge works entry by entry: a property name or feature identifier declared in more than one place takes the value of the highest-ranking declaration, while the names declared only once all apply. The closer a declaration is to the test method, the higher it ranks: the method first, then the test class, then superclasses from the nearest up, and then, for a [annotationname]`@Nested` test, enclosing classes from the innermost out. In the example at the top of this page, the method-level `myExperimentalFeature=false` therefore replaces the value the test class declares for that flag, and leaves `devmode.sessionSerialization.enabled` untouched. [source,java] ---- @@ -70,7 +70,7 @@ class CartViewTest extends AbstractViewTest { } ---- -Lookup services are the exception: they accumulate instead of replacing each other, so a test method can add a service, but cannot remove one that its test class declares. The services that the Spring and Quarkus integrations need are always registered, and the test configuration never affects them. +Lookup services are the exception to the ranking: they have no name to resolve, so every declared service is registered. A test method can add a service, but cannot remove one that its test class declares. The services that the Spring and Quarkus integrations need are always registered, and the test configuration never affects them. A method-level annotation needs an environment built for each test method. When one environment is shared by the whole class, as with [classname]`BrowserlessClassExtension`, the annotation is rejected with an error naming the methods that carry it. Move it to the test class in that case. diff --git a/articles/upgrading/index.adoc b/articles/upgrading/index.adoc index 5ba704209b..8eaaf1d16c 100644 --- a/articles/upgrading/index.adoc +++ b/articles/upgrading/index.adoc @@ -1140,7 +1140,7 @@ The [methodname]`getPropertyString`, [methodname]`getPropertyBoolean`, [methodna === Browserless Testing: Lookup Services of the Spring and Quarkus Integrations -The services that the Spring and Quarkus integrations need have moved from [methodname]`lookupServices()` to [methodname]`frameworkLookupServices()`, and are registered in every case. An override of [methodname]`lookupServices()` therefore adds to them instead of replacing them, which is what keeps those integrations working, and the resulting [classname]`Lookup` holds more services than before. [methodname]`lookupServices()` itself is deprecated in favor of the test configuration, which declares the same services on a test class or a test method. See <<{articles}/flow/testing/browserless/test-configuration#,Test Configuration>>. +Starting with Vaadin 25.3, the services that the Spring and Quarkus integrations need have moved from [methodname]`lookupServices()` to the new [methodname]`frameworkLookupServices()` method -- both declared by [classname]`BaseBrowserlessTest`, the base class of [classname]`BrowserlessTest`, [classname]`SpringBrowserlessTest`, and [classname]`QuarkusBrowserlessTest` -- and are registered in every case. An override of [methodname]`lookupServices()` therefore adds to them instead of replacing them, which is what keeps those integrations working, and the resulting [classname]`Lookup` holds more services than before. Override [methodname]`frameworkLookupServices()` instead to replace one of the framework services, such as the Spring [classname]`SpringSecurityRequestCustomizer`. [methodname]`lookupServices()` itself is deprecated in favor of the test configuration, which declares the same services on a test class or a test method; existing overrides are still honored. See <<{articles}/flow/testing/browserless/test-configuration#,Test Configuration>>. == Binder [methodname]`Binder.validate()` implementation has been changed to behave as its Javadoc states. In other words, [methodname]`Binder.validate()` no longer fails when bean level validators have been configured but no bean is currently set (i.e. [classname]`Binder` is used in buffered mode).