> Markdown version of [Test Configuration](https://vaadin.com/docs/next/flow/testing/browserless/test-configuration). Section index: [llms.txt](https://vaadin.com/docs/next/flow/llms.txt)

# Test Configuration (since V25.3)

`@BrowserlessTestConfig` declares Vaadin application properties, feature flags, and Lookup services for the standard browserless environment. Each configuration belongs to the environment created for its test and is discarded with that environment. This is Vaadin test configuration, not a replacement for Spring, Quarkus, or CDI bean configuration.

A custom environment initialization, such as the [CDI initialization](https://vaadin.com/docs/next/flow/testing/browserless/cdi.md) in this documentation, applies these settings only if it passes `testConfiguration()` to `MockVaadin.setup()`.

For a step-by-step example, see [Configure a Browserless Test](https://vaadin.com/docs/next/building-apps/testing/browserless/configure-tests.md).

## <a id="settings"></a>Settings

| Attribute               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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 `VaadinServiceInitListener`, already sees them.                                                                                                                                                  |
| `featureFlags`          | Either a feature identifier, to enable the feature, or an `id=true\|false` pair. These flags override the [feature flag](https://vaadin.com/docs/next/flow/configuration/feature-flags.md) sources that apply outside a test — the `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. |
| `lookupServices`        | Implementation classes registered with the Vaadin `Lookup`, such as an `InstantiatorFactory` or a `ResourceProvider`.                                                                                                                                                                                                                                                                                                                                                                                |

The `browserless` application property itself stays enforced and cannot be overridden.

## <a id="copilot"></a>Copilot (V25.4 pre-release)

Copilot is disabled by default in the browserless environment. Copilot is a development tool that works on top of an application running in a browser, so it has little use in a browserless test. The default is set before the test configuration is applied, so a test that needs Copilot can enable it again with the `copilot.enable` application property:

```java
@BrowserlessTestConfig(applicationProperties = "copilot.enable=true")
```

With Spring, Copilot first looks for `vaadin.copilot.enable` in the Spring environment, and falls back to the browserless default only if the property isn’t defined there. If the application sets `vaadin.copilot.enable` explicitly, for example in `application.properties`, that value also applies to the tests. To disable Copilot in such a project, override the property for the tests, for example with `@TestPropertySource(properties = "vaadin.copilot.enable=false")`.

## <a id="merging-class-and-method-configuration"></a>Merging Class and Method Configuration

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 `@Nested` test, enclosing classes from the innermost out. A method-level feature setting replaces the class-level value for that identifier without removing unrelated application properties.

```java
@BrowserlessTestConfig(applicationProperties = "base.property=fromBase")
abstract class AbstractViewTest extends BrowserlessTest {
}

@BrowserlessTestConfig(featureFlags = "defaultAutoResponsiveFormLayout")
class ResponsiveFormLayoutTest extends AbstractViewTest {
    // Both base.property and defaultAutoResponsiveFormLayout apply
}
```

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 `BrowserlessClassExtension`, the annotation is rejected with an error naming the methods that carry it. Move it to the test class in that case.

## <a id="configuring-without-annotations"></a>Configuring without Annotations

The same settings can be built in code. On a JUnit 6 extension:

```java
@RegisterExtension
BrowserlessExtension extension = new BrowserlessExtension()
        .withApplicationProperty("devmode.sessionSerialization.enabled", "true")
        .withFeatureFlags("defaultAutoResponsiveFormLayout");
```

On the application context builder of a multi-user test:

```java
try (var app = BrowserlessApplicationContext.create(builder -> builder
        .withViewPackages(CartView.class)
        .withFeatureFlags("defaultAutoResponsiveFormLayout"))) {
    // ...
}
```

A `BrowserlessApplicationContext` is created in plain code rather than by a JUnit extension, so it never looks at `@BrowserlessTestConfig`: only what its own builder declares applies. To reuse the configuration declared by a test class, pass it explicitly with `BrowserlessConfiguration.from(…​)`:

```java
try (var app = BrowserlessApplicationContext.create(builder -> builder
        .withViewPackages(CartView.class)
        .withConfiguration(BrowserlessConfiguration.from(getClass())))) {
    // ...
}
```

`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 `testConfiguration()` on a test that extends a base class:

```java
@Override
protected BrowserlessConfiguration testConfiguration() {
    return BrowserlessConfiguration.builder()
            .withConfiguration(super.testConfiguration())
            .withFeatureFlags("defaultAutoResponsiveFormLayout")
            .build();
}
```

On an extension, a configuration built in code wins over the class-level annotation, and loses against the method-level one. A `testConfiguration()` override ranks differently: `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 `super.testConfiguration()` to refine the declared configuration, and leave out the values that a test method needs to override.

> **Note: Spring Properties Win**
>
> With Spring, a Vaadin property defined in the Spring environment, such as `vaadin.devmode.sessionSerialization.enabled` in `application.properties`, is applied by `SpringServlet` on top of the test configuration, and therefore wins over `@BrowserlessTestConfig`. Use `@TestPropertySource` to override such a property for a test. Properties that are not Vaadin init parameters are unaffected.

`CD70CAA5-6506-4810-BED5-0F54DCE2F0FA`
