Quarkus Integration Testing using Playwright
Testing in Quarkus can be confusing at times because it involves many different frameworks and concepts. This article go over the setup of a simple integration test using Playwright for web-pages.
2024-12-09 at 10:04PM
# Playwright Integration Testing
If you are developing under Quarkus, surely you have read the
getting-started-testing
guide.
If you bootstrapped your project using Quarkus CLI
quarkus create
it will generate a dummy GreetingResource and the following Integration Test:
@QuarkusIntegrationTest
public class GreetingResourceIT extends GreetingResourceTest {
// Run the same tests
}
where GreetingResourceTest looks like
@QuarkusTest
public class GreetingResourceTest {
@Test
public void testHelloEndpoint() {
given().when()
.get("/hello")
.then()
.statusCode(200)
.body(is("hello"));
}
}
Which is fine,
but
- GreetingResourceTest whatever is behind GreetingResource is not mocked out
- GreetingResourceTest make use of rest-assured which is fine for an API but not necessarily the best choice for asserting HTML content
- GreetingResourceIT is highly coupled to GreetingResourceTest
# Add Playwright dependency
If your application serves
html
content
Playwright
is a the de facto dependency as it will offer everything you need for parsing and asserting DOM documents.
<dependency>
<groupId>io.quarkiverse.playwright</groupId>
<artifactId>quarkus-playwright</artifactId>
<version>${quarkus-playwright.version}</version>
<scope>test</scope>
</dependency>
# @QuarkusTest
Let's consider the following
home
resource. It is exposed at root level and depends on
myService
to display
some content
.
@Path("/")
@RequiredArgsConstructor
public class HomeResource {
private final IMyService myService;
@GET
@Produces(MediaType.TEXT_HTML)
public TemplateInstance home() {
var content = myService.fetchSomeContent();
return Templates.home().data("content", content);
}
}
@QuarkusTest
is comparable to
@SpringBootTest
and the test execution runs within the same process, which allows us to mock out Beans. It is also important to underline that
@QuarkusTest
runs within the JVM and not natively.
@QuarkusTest
@WithPlaywright
public class HomeResourceTest {
@InjectMock
IMyService myService;
@InjectPlaywright
BrowserContext context;
@TestHTTPResource("/")
URL home;
@Test
void home() {
// given
var page = context.newPage();
when(myService.findNextUrl).thenReturn("next-url/go");
// when
var actual = page.navigate(home.toString());
// then
page.waitForLoadState();
assertThat(actual.status()).isEqualTo(200);
assertThat(page.locator(".my-content-link").getAttribute("href")).isEqualTo("next-url/go");
}
}
# @QuarkusIntegrationTest
Quarkus integration tests are run against the native executable and consequently outside of the process. They are made for testing the application
in production mode
. Consequently mocking out services becomes more complicated. Profiles (
quarkus.test.integration-test-profile
) can still be used to stir the application but that requires larger integration environment set up.
@WithPlaywright
@QuarkusIntegrationTest
public class HomeResourceIT {
@InjectPlaywright
BrowserContext context;
@TestHTTPResource("/")
URL home;
@Test
void home() {
// given
var page = context.newPage();
// when
var actual = page.navigate(home.toString());
// then
page.waitForLoadState();
assertThat(actual.status()).isEqualTo(HttpStatus.SC_OK);
assertThat(page.locator(".my-content-link").getAttribute("href")).isEqualTo("next-production-url/go");
}
}
# Conclusion
- Consider Playwright for end-to-end testing
- @QuarkusTest Beans can be easily mocked out by declaring Mocked beans annotated with @InjectMock
- @QuarkusIntegrationTest mocking is limited and could be stirred by using different type of profiles
More to be found on
gdevxy Github repository
.