local end-to-end test environment. runs paystable + a mock PayU gateway + a mock merchant app, all in docker.
fill in your PayU test credentials:
cp .env.testkit.example .env.testkit
# edit .env.testkit with your test key and saltdocker compose -f docker-compose.testkit.yml --env-file .env.testkit up --buildpaystable: http://localhost:8080
mock gateway: http://localhost:9090
mock merchant: http://localhost:9091
go run ./testkit/scenarios <scenario>available scenarios:
| scenario | what it tests |
|---|---|
happy-path |
webhook says success, gateway confirms success. hold → CONFIRMED. |
false-failure |
webhook says FAILED, but gateway actually returns success after 25s. paystable should still reach CONFIRMED. this is the core case paystable exists to solve. |
genuine-failure |
webhook and gateway both say failed. hold → FAILED. |
amount-mismatch |
gateway reports success but wrong amount. hold -> MISMATCH. |
merchant-offline |
merchant callback endpoint is down. hold confirms, delivery retries. bring merchant back online to see delivery succeed. |
duplicate-webhook |
same webhook fired 3 times. should not produce duplicate state transitions. |
script a transaction:
POST http://localhost:9090/script
body: { "txn_id": "x", "status": "success", "amount": 49900, "fail_until_s": 30 }
setting fail_until_s makes the status endpoint return "failed" for that many seconds, then switch to the scripted status. this simulates replica lag.
fire a webhook:
POST http://localhost:9090/fire-webhook
body: { "txn_id": "x", "status": "failure" }
sends a correctly HMAC-signed PayU webhook to paystable.
curl -X POST http://localhost:9091/toggle-offlinecall again to bring it back online.