Set Up Browserless Tests with Quarkus
- Add Dependencies
- Create a Test
- Run the Test
- Replace a Service with a Test Profile
- Extend a Base Class Instead
- Next Steps
Use this guide for a Quarkus application with Flow views.
Tests run with @QuarkusTest, and create the Vaadin environment with QuarkusBrowserlessApplicationContext.
For a Java EE application that uses Vaadin CDI and Weld, use the separate CDI setup.
Add Dependencies
With the Vaadin BOM imported, add these test dependencies to your pom.xml file:
Source code
pom.xml
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>browserless-test-junit6</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>browserless-test-quarkus</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit</artifactId>
<scope>test</scope>
</dependency>Create a Test
Create this view:
Source code
HelloWorldView.java
HelloWorldView.javaimport com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
@Route("")
public class HelloWorldView extends HorizontalLayout {
TextField name;
Button sayHello;
public HelloWorldView() {
name = new TextField("Your name");
sayHello = new Button("Say hello");
sayHello.addClickListener(e -> {
Notification.show("Hello " + name.getValue());
});
add(name, sayHello);
}
}Create a test class in the same Java package as the view under src/test/java:
Source code
HelloWorldViewTest.java
HelloWorldViewTest.javaimport org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.vaadin.browserless.BrowserlessApplicationContext;
import com.vaadin.browserless.BrowserlessUIContext;
import com.vaadin.browserless.quarkus.QuarkusBrowserlessApplicationContext;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest
class HelloWorldViewTest {
private BrowserlessApplicationContext app;
private BrowserlessUIContext window;
@BeforeEach
void setUp() {
app = QuarkusBrowserlessApplicationContext.create(
HelloWorldView.class); 1
window = app.newUser().newWindow(); 2
}
@AfterEach
void tearDown() {
app.close(); 3
}
@Test
void setText_clickButton_notificationIsShown() {
window.navigate(HelloWorldView.class); 4
window.findTextField().withLabel("Your name").setValue("Test");
window.findButton().withText("Say hello").click();
Assertions.assertEquals("Hello Test",
window.findNotification().getText());
}
}-
Creates the application context, which creates views through Quarkus dependency injection. It scans the package of
HelloWorldViewand its sub-packages for routes; if your views are in several packages, pass a class from each. -
Creates a user with its own Vaadin session, and opens a window for that user. The window shows the root route.
-
Closes the application context, together with every user and window created from it.
-
The test drives the UI through the window: it finds components by their label or text, and types and clicks, as a user does.
See How a Browserless Test Works for what each line of the test method does.
|
Note
|
@QuarkusTest starts the application and its HTTP server, which browserless tests don’t use.
The browserless tests still run in a mocked Vaadin environment.
|
Run the Test
Run the test from your IDE or with mvn test.
The test passes when entering a name and clicking the button shows the expected notification.
Replace a Service with a Test Profile
Annotate a test with @TestProfile to run it with a specific test configuration.
A test profile can, for example, override application configuration, enable bean alternatives, and provide custom test resources.
See the Quarkus Testing Profiles documentation for all options.
This example replaces a GreetingService with a test implementation.
It assumes a WelcomeView that shows the result of greetingService.greet("Quarkus") in a span stored in its greeting field.
The test implementation is a CDI bean annotated with @Alternative:
Source code
MockService.java
MockService.javaimport jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Alternative;
@Alternative
@ApplicationScoped
public class MockService implements GreetingService {
@Override
public String greet(String name) {
return "Hello " + name + " from the mock service";
}
}The profile enables the alternative and also overrides the app.some.config property:
Source code
MockServiceProfile.java
MockServiceProfile.javaimport java.util.Collections;
import java.util.Map;
import java.util.Set;
import io.quarkus.test.junit.QuarkusTestProfile;
public class MockServiceProfile implements QuarkusTestProfile {
@Override
public Map<String, String> getConfigOverrides() {
return Collections.singletonMap("app.some.config","value");
}
@Override
public Set<Class<?>> getEnabledAlternatives() {
return Collections.singleton(MockService.class);
}
}A test that uses the profile gets the alternative injected into the view:
Source code
MockServiceViewTest.java
MockServiceViewTest.javaimport org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.vaadin.browserless.BrowserlessApplicationContext;
import com.vaadin.browserless.BrowserlessUIContext;
import com.vaadin.browserless.quarkus.QuarkusBrowserlessApplicationContext;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.TestProfile;
@QuarkusTest
@TestProfile(MockServiceProfile.class)
class MockServiceViewTest {
private BrowserlessApplicationContext app;
private BrowserlessUIContext window;
@BeforeEach
void setUp() {
app = QuarkusBrowserlessApplicationContext.create(WelcomeView.class);
window = app.newUser().newWindow();
}
@AfterEach
void tearDown() {
app.close();
}
@Test
void view_usesMockService() {
WelcomeView view = window.navigate(WelcomeView.class);
Assertions.assertEquals("Hello Quarkus from the mock service",
view.greeting.getText());
}
}Extend a Base Class Instead
A test can also extend QuarkusBrowserlessTest, which creates the Vaadin environment with one user and one window before each test method, and closes it afterwards.
The test then calls the window methods on itself:
Source code
HelloWorldViewTest.java
HelloWorldViewTest.javaimport org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.vaadin.browserless.quarkus.QuarkusBrowserlessTest;
import com.vaadin.flow.component.notification.Notification;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest
class HelloWorldViewTest extends QuarkusBrowserlessTest {
@Test
public void setText_clickButton_notificationIsShown() {
final HelloWorldView helloView = navigate(HelloWorldView.class);
test(helloView.name).setValue("Test");
test(helloView.sayHello).click();
Notification notification = find(Notification.class).single();
Assertions.assertEquals("Hello Test", test(notification).getText());
}
}The base class scans the whole classpath for routes, unless the test class has a @ViewPackages annotation.
It applies the Quarkus @TestSecurity annotation to its user; see Use Quarkus Test Security.
See Base Classes for when to choose a base class.
Next Steps
-
Test User Interactions explains how the test works and how to cover more complex views.
-
Test View Access Control covers protected views with Quarkus Security.
-
Debug a Failing Browserless Test helps when a test fails.
09A26994-97AB-4877-AEB1-717BE02E348D