Modern applications are no longer just a browser connected to a single API. An enterprise application may contain a web or mobile frontend, backend services, microservices, REST APIs, GraphQL APIs, WebSockets, databases, Kafka or another message broker, topics, publishers and consumers, and event-driven workflows.
For a modern SDET, testing only the UI or checking that an API returns 200 OK is often not enough. Playwright can be used as part of a broader Quality Engineering architecture where one test project validates the application across multiple layers:
UI
↓
REST / GraphQL
↓
Microservices
↓
Database
↓
Messaging / Kafka
↓
WebSocket Events
↓
UIThis tutorial explains these technologies from a Playwright testing perspective and then shows how they can be organized into one professional automation framework.
1. Understanding the Modern Application Architecture
Consider an e-commerce application:
React UI
│
┌───────────┴───────────┐
│ │
REST API GraphQL
│ │
└───────────┬───────────┘
▼
Backend
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
Product Service Order Service User Service
│ │ │
▼ ▼ ▼
Product DB Order DB User DB
│
│ Publish Events
▼
Message Broker
│
Topics
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Inventory Email Analytics
Consumer Consumer Consumer
│
▼
WebSocket
│
▼
Real-Time UIThese technologies solve different problems. They are not replacements for one another.
2. What Is a Backend?
The backend is the server-side part of an application. It commonly handles:
- Business logic
- Authentication
- Authorization
- Database operations
- API processing
- Integrations
- Messaging
- Calculations
- Validation
For example:
Browser
│
│ GET /products/100
▼
Backend
│
├── Validate request
├── Check authorization
├── Execute business logic
├── Query database
└── Build response
▼
200 OKA frontend displays information. The backend determines how much of that information is created, retrieved, validated, transformed, and stored.
3. What Is a Microservice?
A traditional application may contain most backend functionality inside one application. This is generally called a monolithic architecture.
Backend
Users
Products
Orders
Payments
Inventory
One ApplicationA microservices architecture separates major capabilities into independently deployable services.
Application
│
┌──────────────┼──────────────┐
▼ ▼ ▼
Product Service Order Service Payment Service
│ │ │
▼ ▼ ▼
Product DB Order DB Payment DBProduct Service
- create product
- retrieve product
- update product
- inventory information
Order Service
- create order
- cancel order
- order status
Payment Service
- payment
- refund
- payment statusMicroservices can communicate using REST, GraphQL, messaging, or other protocols.
How should an SDET test a microservice?
A professional strategy usually includes:
Unit
↓
Component
↓
API
↓
Contract
↓
Integration
↓
End-to-EndYou should test both the service itself and its interactions with dependent systems. For example, an Order Service may depend on a Payment Service, an Inventory Service, an Order Database, and Kafka.
Important scenarios include:
- Successful order
- Payment declined
- Inventory unavailable
- Dependency timeout
- Database failure
- Duplicate request
- Invalid request
- Unauthorized request
- Event publishing failure
4. What Is an API?
An API — Application Programming Interface — provides a defined interface through which software systems communicate.
React UI
│
│ API
▼
Product Service
│
▼
PostgreSQLThe browser does not need to know how the database works. It can request GET /products/100 and receive:
{
"id": 100,
"name": "Laptop",
"price": 1499
}The API acts as the interface between the systems.
5. REST API and HTTP
REST is a common architectural style used to build web APIs. A product API might expose:
GET /products
GET /products/{id}
POST /products
PUT /products/{id}
PATCH /products/{id}
DELETE /products/{id}REST APIs commonly communicate using HTTP. Common HTTP methods:
- GET — Retrieve
- POST — Create/process
- PUT — Replace/update
- PATCH — Partial update
- DELETE — Delete
POST /products
Content-Type: application/json
{
"name": "MacBook Pro",
"price": 1999
}Possible response: 201 Created.
6. REST API Testing with Playwright
Playwright includes API testing capabilities through APIRequestContext.
import { test, expect } from '@playwright/test';
test('get product', async ({ request }) => {
const response = await request.get(
'/products/100'
);
expect(response.status()).toBe(200);
const product = await response.json();
expect(product.id).toBe(100);
expect(product.name).toBeDefined();
expect(product.price).toBeGreaterThan(0);
});Do not stop at expect(response.status()).toBe(200). A professional REST test should consider:
- Status code
- Response payload
- Headers
- Schema
- Authentication
- Authorization
- Business rules
- Invalid input
- Boundary values
- Database state
- Response time
- Downstream behavior
REST CRUD Workflow
A useful automated workflow is:
POST
Create Product
↓
Capture ID
↓
GET
Validate Product
↓
PATCH
Update Product
↓
GET
Validate Changes
↓
DELETE
Delete Product
↓
GET
Expect 404This tests the lifecycle of the resource instead of isolated endpoints.
7. What Is GraphQL?
GraphQL provides another approach to API communication. With REST (GET /products/100), the server determines the shape of the response. GraphQL allows the client to request specific fields.
query {
product(id: 100) {
id
name
price
}
}Response:
{
"data": {
"product": {
"id": 100,
"name": "Laptop",
"price": 1499
}
}
}The three important GraphQL operations are:
- Query — retrieve data
- Mutation — change data
- Subscription — receive updates
8. GraphQL Testing with Playwright
Playwright can send GraphQL requests just like other HTTP requests.
const response = await request.post('/graphql', {
data: {
query: `
query Product($id: ID!) {
product(id: $id) {
id
name
price
}
}
`,
variables: {
id: 100
}
}
});
const body = await response.json();
expect(body.data.product.id).toBe(100);One important GraphQL testing concept is that HTTP 200 does not automatically mean the GraphQL operation succeeded. You might receive:
{
"data": {
"product": null
},
"errors": [
{
"message": "Product not found"
}
]
}Therefore validate both the HTTP status and the errors field when success is expected:
expect(response.status()).toBe(200);
expect(body.errors).toBeUndefined();GraphQL testing should cover:
- Queries
- Mutations
- Variables
- Required arguments
- Nested objects
- Schema
- Invalid fields
- Error objects
- Authentication
- Field-level authorization
- Null handling
- Subscriptions when supported
9. What Is WebSocket?
Traditional REST communication follows a request/response model: the client sends a request, the server responds, and the interaction ends. WebSocket creates a persistent bidirectional connection:
Client <====================> Server
WebSocketAfter connection establishment, either side can send messages. This is useful for stock prices, trading applications, chat, live notifications, sports scores, real-time dashboards, and order-status updates.
Order status changes
│
▼
Backend
│
│ WebSocket
▼
Browser
"Order SHIPPED"No page refresh is required.
10. Testing WebSockets
For Node.js/Playwright-based frameworks, a WebSocket client library can be integrated alongside Playwright.
import WebSocket from 'ws';
const ws = new WebSocket(
'ws://localhost:3000/ws'
);
ws.on('open', () => {
ws.send(JSON.stringify({
type: 'SUBSCRIBE',
orderId: 100
}));
});
ws.on('message', data => {
const event =
JSON.parse(data.toString());
console.log(event);
});Important WebSocket tests include:
- Connection
- Authentication
- Subscription
- Message sending
- Message receiving
- Event payload
- Event type
- Ordering
- Disconnect
- Reconnect
- Timeout
- Invalid messages
- Unauthorized subscriptions
- Multiple events
- High-frequency events
A valuable integration scenario is:
REST request
↓
Backend changes state
↓
WebSocket event
↓
Playwright validates event
↓
UI updates11. What Is Messaging?
REST generally involves direct communication: the Order Service calls the Inventory Service directly. But an enterprise system may need many systems to react to one event — for example, when an order is created you may need to update inventory, send an email, update analytics, and notify the warehouse. Calling every service directly creates tighter coupling.
Messaging provides another model:
Order Service
│
│ OrderCreated
▼
Message Broker
│
├── Inventory
├── Email
├── Analytics
└── WarehouseThis is commonly asynchronous. Technologies may include Kafka, RabbitMQ, AWS SNS/SQS, and other messaging/event platforms.
12. Broker vs Topic
A broker and a topic are not the same thing. The broker is part of the messaging infrastructure. A topic is a named message stream/channel managed by that infrastructure.
Publisher
│
▼
Messaging Infrastructure
│
├── order-created
├── payment-completed
└── product-updatedIn Kafka specifically, a broker technically refers to an individual Kafka server. Multiple brokers form a Kafka cluster. A topic is a named stream of records distributed through that cluster.
13. Publisher and Subscriber
The publisher produces an event. For example, the Order Service publishes an OrderCreated event to the order-created topic:
{
"eventType": "OrderCreated",
"orderId": "ORD-1001",
"customerId": 200,
"amount": 299.99
}Subscribers or consumers react to that event:
order-created
│
┌──────────┼──────────┐
▼ ▼ ▼
Inventory Email Analytics
Consumer Consumer ConsumerEach system can process the same business event independently, depending on the messaging technology and consumer configuration.
14. Testing Kafka Topics and Messaging
A useful integration test is:
Playwright
│
│ POST /orders
▼
Order API
│
▼
Order Service
│
│ publishes
▼
Kafka
│
▼
order-created Topic
│
▼
Test Consumer
│
▼
Validate EventThe test should find the event associated with its own transaction. For example, an event with eventType OrderCreated and the orderId your test just created.
Validate:
- Topic
- Event type
- Event key
- Payload
- Required fields
- Schema
- Timestamp
- Correlation ID
- Duplicate events
- Ordering when required
- Sensitive information
15. Testing the Publisher
Suppose POST /orders triggers the Order Service to publish an OrderCreated event to Kafka. Your test should verify both that the business operation succeeds and that the correct event is published.
Also test negative behavior. For example, when payment fails and order creation fails, you may need to verify — depending on the business design — that an OrderCreated event was not published.
Other important cases include:
- Duplicate publishing
- Retry behavior
- Broker unavailable
- Invalid payload
- Serialization errors
16. Testing the Consumer
Now reverse the test. Publish a controlled event:
{
"eventType": "OrderCreated",
"orderId": "ORD-1001"
}Then verify that the consumer performs the expected operation:
Test Publisher
│
▼
order-created
│
▼
Inventory Consumer
│
▼
Inventory DBValidate that the message was received, parsed, the business logic executed, the database updated, and the message acknowledged. Also test invalid messages and failure handling:
Invalid Message
↓
Consumer
↓
Processing Failure
↓
Retry
↓
Retry
↓
Dead-Letter QueueRetry and DLQ behavior are important parts of enterprise messaging testing.
17. Database Testing with Playwright
Playwright itself is not a database library, but a Playwright TypeScript framework can use Node.js database clients. For PostgreSQL:
import { Pool } from 'pg';
const pool = new Pool({
connectionString:
process.env.DB_CONNECTION_STRING
});
const result = await pool.query(
`
SELECT id, status
FROM orders
WHERE id = $1
`,
[orderId]
);
expect(result.rows[0].status)
.toBe('CREATED');Database validation is useful when you need to confirm the full chain: API → Business Logic → Database. For example, POST /products returns 201 Created, and PostgreSQL contains the new product row.
18. Handling Eventual Consistency
Distributed applications do not always update every system immediately. For example: REST Request → Order Created → Kafka Event → Consumer → Database Updated. This might take hundreds of milliseconds or several seconds.
Avoid fixed sleeps like await page.waitForTimeout(5000). A better approach is polling.
const rows = await waitUntil(
() =>
dbClient.query(
`
SELECT *
FROM orders
WHERE id = $1
`,
[orderId]
),
rows => rows.length === 1,
{
timeoutMs: 10000,
intervalMs: 250
}
);Conceptually: check, not ready, wait, check again, ready, continue. This produces faster and more reliable tests than fixed sleeps.
19. Enterprise Playwright Framework Architecture
Instead of putting every protocol directly inside test files, separate infrastructure from business behavior.
tests/
├── ui/
├── api/
│ ├── rest/
│ └── graphql/
├── websocket/
├── messaging/
└── e2e/
clients/
├── restClient.ts
├── graphQLClient.ts
├── websocketClient.ts
└── messageClient.ts
services/
├── productService.ts
├── orderService.ts
└── userService.ts
pages/
└── productPage.ts
fixtures/
└── testFixtures.ts
utils/
├── dbClient.ts
├── schemaValidator.ts
├── eventValidator.ts
└── waitUtils.ts
schemas/
└── product.schema.ts
test-data/
└── products.ts
config/
└── env.tsThe dependency flow becomes:
Playwright Tests
│
┌──────────┴──────────┐
▼ ▼
Page Objects Services
│
▼
Clients
│
┌─────────┬───────────┼─────────┐
▼ ▼ ▼ ▼
REST GraphQL WebSocket Messaging
│
▼
Database20. Why Use a Client Layer?
Low-level communication belongs in clients. For example:
await restClient.get('/products/100');
await graphQLClient.execute(
query,
variables
);
await messageClient.publish(
'order-created',
event
);
await websocketClient.connect();Tests should not repeatedly implement connection, headers, serialization, error handling, or protocol configuration.
21. Why Use a Service Layer?
The service layer represents business operations. Instead of raw requests in every test, tests can use readable business calls:
await productService.createProduct(product);
await productService
.getProductGraphQL(productId);
await orderService.createOrder(
productId,
2
);This creates readable tests where the flow is Test → Business Service → Protocol Client → Application. The service layer hides transport details from business-level tests.
22. Schema Validation
Checking individual values is useful, but API contracts should also be validated:
validateSchema(
productSchema,
product
);A schema might require: id → number, name → string, price → number, inventory → number. Schema validation helps detect contract-breaking changes that simple assertions may miss.
23. Playwright Fixtures
Playwright fixtures can provide reusable framework components.
test(
'create product',
async ({
productService,
dbClient
}) => {
const product =
await productService.createProduct({
name: 'Laptop',
price: 1499
});
expect(product.id).toBeTruthy();
}
);The fixture layer can initialize and clean up the REST client, GraphQL client, product service, order service, database client, and authentication. This keeps setup and teardown out of individual tests.
24. The Most Valuable Test: Cross-System E2E
Now combine everything. Imagine this business flow:
Playwright
│
│ POST /orders
▼
REST API
│
▼
Order Service
│
├──────────────► PostgreSQL
│
└──────────────► Kafka
│
▼
OrderCreated
│
▼
Inventory Service
Order status changes
│
▼
Order Service
│
▼
WebSocket
│
▼
UIThe test can validate:
- REST request succeeds
- Order is stored in PostgreSQL
- Correct Kafka event is published
- Consumer processes the event
- Order status changes
- WebSocket publishes the update
- UI displays the new state
That is significantly stronger than checking expect(response.status()).toBe(201).
25. Example Enterprise Playwright Test
Conceptually:
test(
'order workflow across REST, DB, Kafka and WebSocket',
async ({
orderService,
dbClient
}) => {
// REST
const order =
await orderService.createOrder(
101,
1
);
expect(order.id).toBeTruthy();
// DATABASE
const rows =
await waitUntil(
() =>
dbClient.query(
`
SELECT id, status
FROM orders
WHERE id = $1
`,
[order.id]
),
rows =>
rows.length === 1
);
expect(rows[0].status)
.toBe('CREATED');
// KAFKA
const event =
await messageClient.waitForMessage(
event =>
event.eventType ===
'OrderCreated'
&&
event.orderId === order.id
);
expect(event.orderId)
.toBe(order.id);
// WEBSOCKET
websocketClient.send({
type: 'SUBSCRIBE',
orderId: order.id
});
// REST
await orderService.updateStatus(
order.id,
'SHIPPED'
);
// WEBSOCKET VALIDATION
const wsEvent =
await websocketClient.waitForMessage(
event =>
event.eventType ===
'ORDER_UPDATED'
&&
event.orderId === order.id
);
expect(wsEvent.status)
.toBe('SHIPPED');
}
);The important idea is not that every test should validate every layer. Instead, create the appropriate test at the appropriate level.
26. Recommended Test Strategy
A healthy enterprise Playwright project might contain:
- UI Tests — Browser behavior
- REST Tests — REST contracts and business APIs
- GraphQL Tests — Queries, mutations and GraphQL contracts
- WebSocket Tests — Real-time communication
- Messaging Tests — Producers, consumers and events
- Database Tests — Persistence and backend state
- E2E Tests — Critical cross-system business journeys
27. Synchronous vs Asynchronous Testing
This distinction is critical. REST and many GraphQL operations are commonly synchronous: Request → Processing → Response. Messaging is commonly asynchronous: Publish → Topic → Consumer → Processing happens later. WebSocket is long-lived and event-driven.
Your automation strategy must reflect these differences. This is why utilities such as waitForMessage(), waitForEvent(), waitUntil(), and pollDatabase() are more appropriate than fixed sleeps.
28. What Should a Professional SDET Remember?
The simplest mental model is:
- Backend = Server-side logic
- Microservice = Independently deployable backend capability
- API = Interface between software systems
- REST = Resource-oriented API architectural style
- HTTP = Communication protocol commonly used by web APIs
- GraphQL = Query language and runtime for APIs
- WebSocket = Persistent bidirectional communication
- Messaging = Asynchronous/event-based system communication
- Broker = Messaging infrastructure/server role
- Topic = Named message stream/channel
- Publisher = Produces messages/events
- Subscriber / Consumer = Receives and processes messages/events
And from the Playwright testing perspective, Playwright can cover browser testing, REST API testing, GraphQL testing, WebSocket integration, database integration, Kafka/messaging integration, and enterprise E2E testing — all in one project.
29. Final Architecture
The complete picture is:
PLAYWRIGHT
│
Test / Fixture / Service Layer
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
UI REST GraphQL
│ │ │
└────────────────────┼────────────────────┘
▼
Backend
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Product Order User
Service Service Service
│ │ │
▼ ▼ ▼
Databases
│
▼
Messaging System
│
Kafka Topics
│
┌──────────┼──────────┐
▼ ▼ ▼
Consumer Consumer Consumer
│
▼
WebSocket
│
▼
Real-Time UIModern Quality Engineering is therefore not simply open browser, click button, check text — and backend automation is not simply call API, check 200. A mature Playwright automation architecture can validate the behavior of a distributed application across the boundaries that matter: UI + REST + GraphQL + Microservices + Database + Kafka/Messaging + WebSocket + End-to-End Business Workflows.
The goal is not to test every technology in every scenario. The goal is to use the correct test level for each risk and then use a smaller number of cross-system Playwright tests to prove that the most important enterprise business workflows work correctly from beginning to end.
Complete professional Playwright + TypeScript framework covering UI, REST API, GraphQL, WebSocket, Kafka, Database, E2E and Agentic AI testing — with a complete AUT included.
Get Playwright tutorials in your inbox
Weekly tips, real-world examples, and framework patterns – no spam, unsubscribe anytime.
Playwright Framework Series
View all →- 1Getting Started with Playwright: Installation, Setup, and Your First Test
- 2Playwright Locators: The Complete Guide with Real-World Examples
- 3Playwright Actions: Complete Guide to Click, Fill, Hover, Keyboard, Mouse & File Upload
- 4Playwright Assertions: The Complete Guide with Real-World Examples
- 5Playwright Auto Waiting: The Complete Guide with Real-World Examples
- 6Playwright Fixtures: The Complete Guide with Real-World Examples
- 7Playwright Browser Context & Multiple Tabs: The Complete Guide with Real-World Examples
- 8Playwright Authentication & Session Management: Complete Guide with Enterprise Examples
- 9Playwright Network Interception & API Mocking: Complete Guide with Real-World Examples
- 10Playwright Page Object Model (POM): The Complete Guide with Enterprise Examples
- 11Page Object Model with Playwright: A Practical Guide
- 12How to Build a Robust Professional Playwright Framework from Scratch (Step-by-Step)
- 13Building an Enterprise Playwright Framework from Scratch
API Testing Series
View all →- 1Playwright API Testing: The Complete Guide with Real-World Examples
- 2Part 1 : Playwright API Testing Tutorial: Build Enterprise-Level API Automation Framework
- 3Part 2: Playwright API Testing Tutorial: Setting Up Project & Sending Your First API Request
- 4Part 3: Mastering CRUD Operations in Playwright API Testing
- 5Part 4: Authentication in Playwright API Testing (Bearer Token, JWT, API Key & Reusable Fixtures)
- 6Part 5: Building an Enterprise-Level Playwright API Automation Framework
- 7Part 6: API Models, Schema Validation & Test Data Management in Playwright
- 8Part 7: Custom Fixtures, Hooks, Logging & Parallel Execution in Playwright API Testing
- 9Part 8: Building a Production-Ready Playwright API Framework (Environment Management, CI/CD, Reporting & Best Practices)
- 10Part 9: Advanced Playwright API Testing Techniques for Enterprise Automation
- 11Part 10: Building a Complete Enterprise Playwright API Automation Framework (Final Part)
- 12API Testing with Playwright: Request Context, Auth, and Assertions
- 13Playwright Backend Testing Tutorial – REST API, GraphQL, WebSocket, Kafka, Database & Microservices