- Node.js 22 (LTS)
- Docker Desktop
- PowerShell 7+
Check that you have Powershell 7
$PSVersionTable.PSVersionCheck that you have Node.js 22 installed
node -vInside monolith and system-test install dependencies
npm installInside system-test install:
npx playwright install.\run.ps1 allThis will:
- Build the Monolith (compile TypeScript and create build)
- Start Docker containers (Monolith, PostgreSQL, & Simulated External Systems)
- Wait for services to be healthy
- Run all System Tests
You can open these URLs in your browser:
- Monolith Application: http://localhost:8082
- ERP API (JSON Server): http://localhost:3200
- Tax API (JSON Server): http://localhost:3201
Compiles the code and creates the Docker image (local mode only):
.\run.ps1 buildStarts the Docker containers:
# Local mode (uses locally built code)
.\run.ps1 start
# Pipeline mode (uses pre-built image from registry)
.\run.ps1 start pipelineYou can open these URLs in your browser:
- Monolith Application: http://localhost:8082
- ERP API (JSON Server): http://localhost:3200
- Tax API (JSON Server): http://localhost:3201
- PostgreSQL Database: localhost:5434 (database:
eshop, user:eshop_user, password:eshop_password)
.\run.ps1 test.\run.ps1 logs.\run.ps1 stopThis project implements the Client Layer Pattern for test automation, providing a clean abstraction over Playwright API and UI interactions. The Client Layer separates test logic from implementation details and makes tests more maintainable.
system-test/
└── core/
├── clients/
│ ├── commons/ # Shared test utilities
│ │ ├── TestHttpClient.ts # HTTP request wrapper
│ │ └── TestPageClient.ts # Browser interaction wrapper
│ ├── system/ # System under test clients
│ │ ├── api/ # API client
│ │ │ ├── controllers/ # API endpoint controllers
│ │ │ │ ├── EchoController.ts
│ │ │ │ └── OrderController.ts
│ │ │ ├── dtos/ # Data transfer objects
│ │ │ │ ├── PlaceOrderRequest.ts
│ │ │ │ ├── PlaceOrderResponse.ts
│ │ │ │ ├── GetOrderResponse.ts
│ │ │ │ └── OrderStatus.ts
│ │ │ └── ShopApiClient.ts
│ │ └── ui/ # UI client
│ │ ├── pages/ # Page objects
│ │ │ ├── HomePage.ts
│ │ │ ├── NewOrderPage.ts
│ │ │ └── OrderHistoryPage.ts
│ │ └── ShopUiClient.ts
│ ├── external/ # External system clients
│ │ └── erp/
│ │ ├── controllers/
│ │ │ └── ProductController.ts
│ │ ├── dtos/
│ │ │ └── CreateProductResponse.ts
│ │ └── ErpApiClient.ts
│ ├── ClientFactory.ts # Creates client instances
│ └── Closer.ts # Manages resource cleanup
└── TestConfiguration.ts # Test environment configuration
- TestHttpClient: Wraps Playwright's API request functionality with methods like
get(),post(), and assertion helpers (assertOk(),assertCreated(), etc.) - TestPageClient: Wraps Playwright's Page API with methods like
fill(),click(),readTextContent(), providing consistent timeouts and error handling
- ShopApiClient: API client for the shop system with controller-based organization
- ShopUiClient: UI client for browser-based testing with page object pattern
- Controllers: Organize API endpoints (e.g.,
OrderControllerhandles/ordersendpoints) - Pages: Encapsulate UI page interactions (e.g.,
NewOrderPagehandles the order form)
- ErpApiClient: Client for interacting with external ERP system
- Allows tests to set up test data in external systems
- Type-safe request/response objects
- Ensures consistency between tests and API contracts
import { test } from '@playwright/test';
import { ClientFactory } from '../../core/clients/ClientFactory';
import { Closer } from '../../core/clients/Closer';
test('should place an order via API', async () => {
// Arrange
const shopApiClient = await ClientFactory.createShopApiClient();
const erpApiClient = await ClientFactory.createErpApiClient();
try {
// Create product in ERP system
const sku = await erpApiClient.products().createProduct('TEST-SKU', 99.99);
// Act - Place order
const response = await shopApiClient.orders().placeOrder(sku, '5', 'US');
// Assert
const orderResponse = await shopApiClient.orders()
.assertOrderPlacedSuccessfully(response);
expect(orderResponse.orderNumber).toMatch(/ORD-/);
} finally {
// Cleanup
await Closer.close(shopApiClient);
await Closer.close(erpApiClient);
}
});- Separation of Concerns: Tests focus on business logic, not technical details
- Reusability: Clients and pages can be reused across multiple tests
- Maintainability: Changes to API/UI only require updating the client layer
- Type Safety: TypeScript ensures compile-time type checking
- Readability: Tests read like business scenarios
- Resource Management: Consistent cleanup with
Closer
This Client Layer implementation is based on the Java reference project.
This project is released under the MIT License.