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 .
Related blog posts
Quarkus and Maven multi-modules pitfalls /