The Argument
“We already use Playwright for frontend E2E tests. Let’s reuse it for backend API testing too, so we don’t introduce another tool.”
This sounds pragmatic. It is not. It confuses tool consolidation with engineering discipline.
Context
- Stack: React frontend + Spring Boot backend.
- Repos: Separate repositories for frontend and backend.
- Existing coverage:
@SpringBootTest+ MockMvc for component/integration tests (already done). - The question: For black-box API tests against a running backend instance, should we use Playwright’s
APIRequestContextor a dedicated API testing tool?
The “Reuse” Fallacy
The argument for Playwright rests on reuse: “We already have it, so using it again is free.”
This only holds when the frontend E2E tests and backend API tests share the same repo, same CI pipeline, same test suite, and same runtime. Our frontend and backend are in separate repositories.
Using Playwright in the backend repo means:
| What you think you’re getting | What you’re actually getting |
|---|---|
| Reuse of an existing tool | A second, independent installation of Playwright |
| Shared test infrastructure | Two separate setups that share nothing |
| Familiarity | Backend developers writing TypeScript tests for a Java application |
What It Actually Costs
1. A Foreign Ecosystem in the Backend Repo
The backend is a Spring Boot / Gradle project. Introducing Playwright means:
package.jsonin a Java reponode_modules/alongsidesrc/main/java/- TypeScript test files alongside JUnit tests
- npm as a second dependency manager alongside Gradle
- Node.js in every developer’s local environment and CI
This is dual-stack maintenance for a single project.
2. Assertions Designed for UI, Not APIs
Compare how API assertions look in practice:
Playwright (TypeScript):
const response = await request.get('/items?id=1,2');
expect(response.status()).toBe(207);
const body = await response.json();
expect(body.results).toHaveLength(2);
expect(body.results[0].status).toBe(200);
expect(body.results[0].data.name).toBe('Widget A');
// No JSON schema validation without extra libraries
REST Assured (Java):
given()
.queryParam("id", "1,2")
.when()
.get("/items")
.then()
.statusCode(207)
.body("results.size()", equalTo(2))
.body("results[0].status", equalTo(200))
.body("results[0].data.name", equalTo("Widget A"))
.body(matchesJsonSchemaInClasspath("items-response-schema.json"));
Karate (DSL):
Given url baseUrl + '/items'
And param id = '1,2'
When method get
Then status 207
And match response.results == '#[2]'
And match response.results[0].status == 200
And match response.results[0].data.name == 'Widget A'
Hurl (plain text):
GET {{base_url}}/items?id=1,2
HTTP 207
[Asserts]
jsonpath "$.results" count == 2
jsonpath "$.results[0].status" == 200
jsonpath "$.results[0].data.name" == "Widget A"
REST Assured, Karate, and Hurl were built for this. Playwright was not. The difference compounds as the test suite grows.
When Tests Go Beyond HTTP
Our black-box tests also:
- Query the database to verify state changes
- Check Redis keys for cache population/invalidation
- Verify WireMock stub invocations for downstream API calls
| Verification | Available in Java? | Available in Node.js? |
|---|---|---|
| Database state | JDBC / JPA (already in project) | Requires pg/mysql2 |
| Redis keys | Jedis / Lettuce (already in project) | Requires ioredis |
| WireMock stubs | WireMock Java API (already in project) | HTTP API only |
| Message queues | Spring AMQP / Kafka client (already in project) | Requires amqplib/kafkajs |
Using Playwright means maintaining a second set of infrastructure clients in a second language for the same databases and services your Java backend already connects to.
The AI-Assisted Development Reality
“But Java is verbose and slow to write.”
This was true three years ago. AI writes the test code now. Whether the test is in Java or TypeScript, an AI assistant generates it in seconds.
What AI does not eliminate:
| Concern | AI helps? | Still matters? |
|---|---|---|
| Writing test code | Yes | No longer the bottleneck |
| Java boilerplate | Yes | No longer the bottleneck |
| Node.js runtime in Java CI pipeline | No | Yes |
| Second set of infrastructure clients | No | Yes |
| Debugging Node.js stack traces in a Java project | No | Yes |
| Unified test reporting (JUnit/Surefire) | No | Yes |
AI eliminates the authoring argument. It does not eliminate the operational argument.
Right Tool for the Job
| Test type | Recommended tool | Why |
|---|---|---|
| Pure HTTP smoke tests | Hurl or Karate | Scripting feel, lightweight, no compilation |
| Integration verification (DB/Redis/WireMock) | REST Assured + JUnit | Same language, same clients, same pipeline |
| Frontend E2E with API setup | Playwright | Right tool in the frontend repo |
When Playwright API Testing IS Valid
| Scenario | Why Playwright fits |
|---|---|
| API setup/teardown within E2E tests | Share auth cookies between browser and API calls |
| Frontend-perspective contract checks | Test that the API returns what the React app expects |
| Same-repo monolith | One test runner, one CI step |
| Quick smoke tests in E2E suite | “Is the login endpoint up?” before browser tests |
None of these apply to “comprehensive black-box API testing of a Spring Boot backend in a separate repo.”
Comparison Table
| Dimension | Playwright | REST Assured | Karate | Hurl |
|---|---|---|---|---|
| Language | TypeScript | Java | Karate DSL (JVM) | Plain text |
| Native to Spring Boot repo? | No | Yes | Yes | Yes |
| JSON Schema validation | Requires Ajv | Built-in | Built-in | No |
| CI overhead in Java repo | Node.js + npm install | Zero | Zero | Single binary |
| DB/Redis/WireMock access | Separate Node.js clients | Existing Java clients | Java interop | No |
| Purpose-built for API testing | No (side feature) | Yes | Yes | Yes |
The Bottom Line
Three arguments were made for Playwright. All three collapse:
- “Reuse” – separate repos mean no reuse. You’re independently installing a Node.js tool in a Java project.
- “Lightweight mode” – skipping browser downloads removes binary bloat, but not the ecosystem mismatch.
- “Java is too verbose” – AI generates REST Assured tests as easily as Playwright tests. The authoring cost is equal. The operational cost is not.
Use the right tool for the job, not the same tool for every job.