AI coding agents write code fast. The bottleneck is no longer typing, it is verification. How fast can the agent find out that the code it just wrote is correct? This is where testing speed and testing architecture suddenly matter more than ever.

With Vaadin Browserless Testing I can write full integration tests that include the UI code, and they run in milliseconds instead of seconds. No browser, no web server. In this post I explain why this is a game changer, especially compared to the classic JavaScript SPA plus Java backend architecture.

The SPA testing problem

With a React or Angular frontend and a Java backend, the UI logic lives in a different language and a different process. The result is two test worlds:

  • Frontend: Vitest or Jest with Testing Library, mocked API calls, Istanbul for coverage
  • Backend: JUnit, Spring Boot tests, JaCoCo for coverage
  • Integration: Only tested by end-to-end tests with Playwright or Cypress

Three test layers, three toolchains, and no combined coverage number.

The worst part: the contract between frontend and backend is only covered by the slowest and most fragile layer, the end-to-end tests. And that contract is exactly where most bugs live. A renamed field in a DTO, a changed validation rule, a different date format. The frontend unit tests will not catch it because the API is mocked. The backend tests will not catch it because they do not know the frontend. Only the e2e test fails, minutes later, if it is not flaky that day.

What Browserless Testing does differently

With Vaadin Flow the UI is server-side Java. The view calls the service directly in the same JVM. Vaadin Browserless Testing lets me test this component tree without starting a browser or a web server.

One test exercises the whole flow: the button click, the binder validation, the service call, and the jOOQ query against the database. The test extends SpringBrowserlessTest from the browserless-test-spring dependency, and @SpringBootTest gives it the full application context. Here is what a typical test looks like:

@SpringBootTest
class CustomerViewTest extends SpringBrowserlessTest {

    @Test
    void createCustomer() {
        CustomerView view = navigate(CustomerView.class);

        test(view.name).setValue("Martinelli LLC");
        test(view.save).click();

        Notification notification = find(Notification.class).single();
        assertThat(test(notification).getText()).contains("Customer saved");
    }
}

This is not a mock of the UI. It is the real component tree, the real binder, the real service, the real SQL. It just runs without the browser. A test like this runs in milliseconds. A comparable Playwright test takes seconds, plus the startup time of the application and the browser.

Why milliseconds matter for AI agents

When a test runs in milliseconds, the agent can run the whole suite after every change. The loop becomes: write the view, run the tests, see the failure, fix it. All within one iteration.

With browser-based tests, this loop takes minutes. Worse, the agent burns tokens on flaky failures: timing issues, missing waits, screenshots to analyze. Browserless tests are deterministic because everything runs in the same JVM. When a test fails, the code is wrong. Not the timing, not the network, the code.

One honest coverage number

There is a second effect that many people miss: code coverage.

With Playwright the UI runs in a separate server process. JaCoCo sees nothing from the view layer. Your coverage report shows the views as untested even when the e2e suite covers them. To get a real number, you would have to merge JaCoCo and Istanbul reports across processes and languages. Nobody does that.

With Browserless Testing the views, binders, and listeners all execute in the test JVM. JaCoCo instruments them like any other class. I get one honest coverage number for the whole application: UI, services, and jOOQ repositories together.

This matters for AI workflows too. If I tell the agent “coverage must stay above 80 percent”, JaCoCo can actually enforce it in the build, because the UI code counts.

One ecosystem

The agent only needs Java, JUnit, and Maven or Gradle. No Node, no browser binaries in CI, no version drift between the Playwright container and the application.

And the agent does not have to keep two codebases consistent. With a SPA every change touches both sides: TypeScript types, DTOs, API client, endpoint. A mismatch only shows up in the slow e2e layer. With Vaadin the compiler already catches the mismatch, and the Browserless test proves the whole flow in milliseconds.

But what about the classic reasons for a SPA?

Let us look at the usual arguments for the SPA architecture:

“We need an API anyway.” This mixes two concerns. An API for client-server communication and a public API are different things with different requirements. The internal one changes with every UI iteration. The public one needs versioning, stability, and documentation. Teams that expose their internal REST API as a public API usually regret it. You can build a Vaadin application and still offer a clean public API next to it, designed for its real consumers.

“We have a frontend team.” The historical reason for the split was specialization: JavaScript people and Java people. But an AI agent does not care about that boundary. It writes Java views as easily as React components. What the agent cares about is feedback speed and consistency, and there the single ecosystem wins clearly. The SPA split keeps the coordination overhead between two codebases but no longer delivers the specialization benefit that justified it.

“We need offline support.” This one is valid. If your client must work offline, you need client-side logic and a SPA or a native app. But be honest: how many business applications really need this?

Conclusion

For typical business applications, the unified stack with Vaadin, Spring Boot, and jOOQ now has a testing story that the SPA architecture cannot match:

  • Full integration tests including UI code, in milliseconds
  • Deterministic tests, no flakiness, perfect for AI agents
  • One honest JaCoCo coverage number for the whole application
  • One ecosystem, one toolchain, one CI setup

I still write a small set of Playwright journey tests for the critical user flows. But the workhorse of my test suite is Browserless Testing. For AI generated projects it is not just convenient. It changes what is possible, because the agent can verify its own work at the speed it writes it.

Keep IT simple.