Skip to main content

Testing Against It

Table of Contents

Hosted or local​

The hosted copy puts everything behind one HTTPS domain. Locally, each part has its own port.

WhatHostedLocal
Shophttps://pizzaplayground.deta.myhttp://localhost:3000
Admin loginhttps://pizzaplayground.deta.my/admin/loginhttp://localhost:3000/admin/login
API basehttps://pizzaplayground.deta.my/api/v1http://localhost:8080/api/v1
Swagger UIhttps://pizzaplayground.deta.my/swagger-ui.htmlhttp://localhost:8080/swagger-ui.html
Healthhttps://pizzaplayground.deta.my/actuator/healthhttp://localhost:8080/actuator/health
Mock pay pagehttps://pizzaplayground.deta.my/pay/...http://localhost:8090/pay/...

The examples below use a BASE variable so they work against either:

BASE=https://pizzaplayground.deta.my # or http://localhost:8080

Test accounts​

Seeded on first boot. Every password is Password123!.

AccountRoleCan do
owner@playground.localOWNEREverything: kanban, history, reset
cashier@playground.localCASHIERKanban only; history and reset return 403
customer01@playground.local to customer20@playground.localCUSTOMEROrder and see their own orders

The repository ships test-data/customers.csv with the twenty customer logins, ready for a JMeter CSV Data Set or a k6 SharedArray. Guest checkout also works with no login at all.

Reset between runs​

Every test should start from the same state, so the API owns the reset instead of the UI.

TOKEN=$(curl -s -X POST $BASE/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"owner@playground.local","password":"Password123!"}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])')

curl -s -X POST $BASE/api/v1/admin/reset -H "Authorization: Bearer $TOKEN"

That clears orders and payments and restarts the order numbers at 1001. Add ?full=true to also reseed users and the menu. It runs in one transaction and returns in well under a second. Put it in your JMeter setUp thread group or your k6 setup().

On the hosted copy, a reset clears everyone's orders, not just yours. Reset your local copy instead.

For load testers​

  • autoPay: true on POST /api/v1/orders marks the order paid inside the same transaction and never touches the mock gateway. Use it when you want order throughput without the payment hop in the loop.
  • X-Mock-Delay: <milliseconds> on POST /api/v1/orders (forwarded to the gateway) or on any mock request directly makes the gateway slow. The hosted copy only exposes the mock's /pay page, so there use it on POST /api/v1/orders. Good for showing how a slow third party backs up your thread pool.
  • Order numbers come from a database sequence starting at 1001, so a run of 5,000 orders after a reset ends at 6000. Handy for a sanity check in the report.
  • Prices are computed on the server. The request carries ids and quantities only, so a load script cannot accidentally send a wrong total.
  • Every error has the same shape: {"error": "...", "requestId": "..."} with a 4xx or 5xx status. Assert on error, not on prose.

For UI testers​

Every control Playwright needs has a stable data-testid. Click the Customize button on a card, not the card itself.

PageTest ids
Menumenu-pizza-card, customize, customizer-size-<id>, customizer-crust-<id>, customizer-topping-<id>, add-to-cart, cart-count, cart-open
Checkoutcheckout-name, checkout-email, checkout-phone, checkout-type-PICKUP, checkout-type-DELIVERY, checkout-submit, checkout-error
Mock pay page#pay-button, #fail-button (plain ids, it is not a React page)
Confirmationorder-number, payment-status
Login and registerlogin-form, register-form, auth-error, admin-login-error
Adminkanban-column-NEW, kanban-column-PREPARING, kanban-column-READY, order-card (with data-order-number), advance-status, cancel-order, refresh-orders, history-from, history-to, history-load, history-table, history-forbidden, admin-logout

The admin board refreshes itself every five seconds. In a test, click refresh-orders instead of waiting.

API map​

Base path /api/v1. Swagger UI (hosted or http://localhost:8080/swagger-ui.html) has the full contract.

EndpointAuthPurpose
POST /auth/register, POST /auth/loginnoneGet a JWT
GET /menunonePizzas, sizes, crusts, toppings
POST /ordersoptionalCreate an order, returns payUrl or, with autoPay, a paid order
GET /orders/{id}noneOne order
GET /orders/mineCUSTOMERThe caller's orders
POST /payments/callbackHMAC signatureThe gateway's webhook
GET /payments/{orderId}/statusnoneWhat the confirmation page polls
GET /admin/orders?status=OWNER or CASHIERKanban data
PATCH /admin/orders/{id}/statusOWNER or CASHIERMove an order
GET /admin/orders/history?from=&to=OWNERCompleted and cancelled orders
POST /admin/reset[?full=true]OWNERClean slate

Tips​

  • Use 127.0.0.1 in scripts if localhost misbehaves. Some tools resolve localhost to IPv6 first; the containers listen on IPv4.
  • CORS allows http://localhost:3000 and the hosted domain. Only matters if you point a browser at a different origin; API tools do not care.
  • Load-test locally, not on the hosted copy. It is one small shared server.
  • The JWT lasts twelve hours. Fetch one token in a setUp group and share it, rather than logging in per virtual user.