This capstone project brings together every concept from the course into a single, production-grade test suite. You will build a complete K6 performance testing solution for ShopFast — a fictional e-commerce REST API — covering all four testing patterns, realistic data management, custom business metrics, quality gates, and CI/CD integration.
The system under test
ShopFast is a REST API that powers an online retail platform. The API has five functional areas:
Authentication — login with email/password, returns a JWT. Tokens expire after 24 hours.
Products — list all products (paginated), search by keyword, get product detail. High read volume: 70% of all traffic.
Cart — add items, view cart contents, update quantities, remove items. Stateful: each user has their own cart tied to their session.
Checkout — create an order from the current cart, process payment (simulated), return an order ID. The most complex flow: involves inventory reservation, payment processing, and order record creation.
User — view profile, list past orders, update preferences. Low volume but sensitive to latency.
For the capstone, use https://jsonplaceholder.typicode.com as a stand-in for the ShopFast API. Map the ShopFast operations to real endpoints: products → /posts, users → /users, carts → /todos, orders → POST /posts. The testing patterns and code structure are what matter — not the specific API responses.
Performance SLAs
| Endpoint category | p95 target | p99 target | Error rate |
|---|---|---|---|
| Authentication | < 300ms | < 500ms | < 0.01% |
| Product browsing | < 500ms | < 800ms | < 0.1% |
| Cart operations | < 400ms | < 700ms | < 0.1% |
| Checkout | < 1000ms | < 2000ms | < 0.01% |
| User profile | < 400ms | < 700ms | < 0.1% |
| Overall throughput | > 200 RPS | — | — |
These SLAs drive the threshold configuration. Checkout gets a lenient latency threshold (1000ms) because it involves payment processing. It gets a strict error threshold (0.01%) because a failed checkout is a direct revenue loss.
The full deliverables
- – smoke.js — 1 VU, 60s, every PR
- – load.js — mixed workload, 30m
- – stress.js — find breaking point
- – spike.js — 10× surge
- – soak.js — 4h stability
- – SharedArray: 1000 simulated users
- – SharedArray: 500 product IDs
- – setup(): shared auth token
- – Per-VU token pattern for multi-user scenarios
- – SLA thresholds per endpoint category
- – Custom metric: order_success_rate > 99%
- – Custom metric: checkout_flow_ms p(95) < 3000
- – abortOnFail on error rate > 10%
- GitHub Actions: smoke on every PR –
- GitHub Actions: load test on merge to main –
- Scheduled: full suite nightly –
- HTML report uploaded as artifact –
Project structure
Organise the project as you would any production code:
tests/
smoke.js # 1 VU sanity check
load.js # mixed workload load test
stress.js # breaking point test
spike.js # traffic surge test
soak.js # 4-hour stability test
lib/
auth.js # login helper, token management
http-helpers.js # tagged request wrappers
metrics.js # custom metric definitions
data/
users.json # 1000 simulated users
products.json # 500 product IDs and names
baselines/
load-test-baseline.json # committed baseline for regression detection
.github/
workflows/
performance.yml # GitHub Actions workflowKeep the lib/ helpers lean. Their job is to reduce boilerplate in test files, not to build a framework. Three files — auth, request helpers, metrics — is enough.
The load test workload model
The load test must reflect real ShopFast traffic patterns. Based on analytics from similar e-commerce platforms:
- 60% — product browsing: list products, view product detail, search by keyword
- 20% — cart activity: add to cart, view cart, update quantities
- 10% — checkout: full cart-to-order flow with payment
- 10% — account activity: view profile, order history
Model this with Math.random() in the default function and distinct tagged requests for each flow. Run with the standard load test stage pattern: 5-minute ramp to 100 VUs, 20-minute hold, 5-minute ramp down.
Custom business metrics
HTTP metrics tell you that /orders took 420ms. Custom metrics tell you that 98.7% of checkout flows succeeded. Both are needed for a complete picture:
orders_created(Counter): increments on every successfulPOST /orderswith status 201checkout_completion_rate(Rate):truefor completed checkouts,falsefor failures — threshold atrate>0.99checkout_flow_ms(Trend): end-to-end duration from cart add to order confirmation — threshold atp(95)<3000cart_items_added(Counter): tracks cart add volume as a business throughput signal
These metrics appear in the HTML report and Grafana dashboard alongside standard K6 metrics.
Acceptance criteria
Your test suite is complete when:
- All five test scripts (smoke, load, stress, spike, soak) run without errors against the mock API
- All thresholds pass for the smoke and load tests under normal conditions
- The stress test output shows the VU count at which the system's error rate crosses 5%
- The spike test output shows whether the system recovers within 2 minutes of the load dropping
handleSummarygenerates an HTML report in every test- The GitHub Actions workflow runs the smoke test on every commit and blocks on failure
- The load test nightly job uploads the HTML report as an artifact
These acceptance criteria are the definition of done. Work through them in order — each one builds on the previous.
Before you start
Read through the project brief completely before writing any code. Sketch the project structure on paper or in a text file. Identify which lessons from the course map to each deliverable:
- SharedArray data → Chapter 5, Lesson 2
- Multiple scenarios for mixed workload → Chapter 5, Lesson 3
constant-arrival-rateexecutor for throughput testing → Chapter 5, Lesson 4- Custom metrics definitions → Chapter 3, Lesson 4
- SLA thresholds with
abortOnFail→ Chapter 7, Lesson 2 handleSummarywith HTML report → Chapter 6, Lesson 1- GitHub Actions workflow → Chapter 7, Lesson 1
The next lesson is a guided walkthrough. Try to implement each piece independently first — even a rough version — before reading the walkthrough. The struggle of independent implementation is where the learning happens.