Multi-Layer Playwright Framework
One order verified at every layer: UI, REST/GraphQL, Postgres, Kafka, and WebSocket.
Playwright · TypeScript · Docker · PostgreSQL · Kafka · GraphQL · GitHub Actions
Results
- 154
- tests across UI, API, DB, Kafka, WebSocket, and E2E
- 34
- @smoke tests on every pull request
- 12
- parallel test jobs in every nightly full run
Problem
In an event-driven app, the expensive failures live between layers: an order that's saved but never announced, stock that goes negative under concurrent orders, events out of order, or a real-time update reaching the wrong user. UI tests alone can't see most of that.
Approach
- Built a shop app to test (Express, Postgres, Kafka, WebSocket, GraphQL) in Docker Compose, and one Playwright + TypeScript framework with page objects, typed REST/GraphQL/WebSocket/Kafka clients, and worker-scoped DB and Kafka fixtures.
- Put each risk at the layer that checks it directly: OpenAPI contract validation and security cases at the API, persistence and rollback checks in Postgres, schema, keys, and ordering on Kafka, per-user pushes over WebSocket, and a thin end-to-end layer proving the layers agree.
- Tiered CI by risk: a @smoke set on every pull request, the full suite nightly, sharded API and UI jobs, and cross-browser and mobile runs limited to smoke.
- Opt-in chaos tests stop Kafka mid-flow; one exposed a real defect (the order is saved but the API returns 500), kept as an expected failure that documents it.
From the code
/**
* UI -> REST / GraphQL -> Database -> Kafka / WebSocket -> UI
* One business transaction verified at every layer.
*/
// …
await test.step('DB: order row, item row and stock', async () => {
// …
const stock = await db.queryOne<{ stock: number }>(
'SELECT stock FROM products WHERE id = $1', [product.id]);
expect(stock!.stock).toBe(23);
});
await test.step('Kafka: order.created event', async () => {
const event = await listener.waitForEvent(
(e) => e.value?.order?.id === orderId && e.value.eventType === 'order.created',
);
expect(validate(OrderEventSchema, event.value).order.total).toBe(39.98);
});Outcome
A public framework that tests a real event-driven system layer by layer, with CI tiers that match cost to risk and a documented defect the chaos tests caught.
Business Impact
The way I'd structure quality for any multi-service product: test each risk where it's cheapest to catch, and keep end-to-end tests for proving the layers agree.