SDLC 04: Quality Assurance Protocols and Test Cases
Revision history: Updated June 2026 — 19-microservice architecture; Go/Python service testing; Meilisearch; BullMQ; Playwright E2E; k6 performance tests; OWASP ZAP security scanning; dedicated test environment.
1. Testing Levels
| Level | Tool | Scope | Run by |
|---|---|---|---|
| Unit | Jest (Node), pytest (Python), Go test | Individual functions, utilities, service logic | Local + CI |
| Integration | Jest + Supertest (Node), httpx (Python), Go test + httptest | API route handlers + DB operations | CI |
| Component | React Testing Library | Frontend components (checkout, overlay, tracking map, etc.) | CI |
| Microservice | Jest (Node), pytest (Python), Go test | Service-to-service contracts, queue processing | CI |
| End-to-End | Playwright | Critical user journeys on staging | Pre-release |
| Performance | k6 | Search, checkout, tracking endpoints | Weekly on staging |
| Security | OWASP ZAP, npm audit | Vulnerability scanning, dependency audit | CI + weekly |
| Payment Sandbox | PawaPay / Flutterwave sandbox | Gateway integration against real sandbox APIs | Manual QA |
2. Required Test Coverage
| Layer | Minimum coverage |
|---|---|
Backend utilities (utils/) | 90% |
Service layer (services/) | 80% |
Route handlers (routes/) | 100% happy path + key error paths |
Payment service (services/payment/) | 100% (all provider branches, all webhook events) |
Fraud detection (services/fraud/) | 100% (all rule branches, scoring logic) |
| Frontend components | 70% |
| Go services (search, analytics) | 80% |
| Python services (moderation, recommendations) | 80% |
3. Testing Strategy by Service Type
3.1 Node.js Services (Jest + Supertest)
All Node.js services follow the same testing pattern:
// services/backend/src/__tests__/payments.integration.test.js
describe('POST /api/v1/payments/initiate', () => {
it('returns ussd response for MTN_MONEY', async () => {
process.env.PAYMENT_PROVIDER = 'MOCK';
const { body } = await request(app)
.post('/api/v1/payments/initiate')
.set('Authorization', `Bearer ${testUserToken}`)
.set('x-pakashop-key', process.env.PAKASHOP_CLIENT_KEY)
.send({
orderId: testOrderId,
paymentMethod: 'MTN',
phoneNumber: '0977123456'
})
.expect(200);
expect(body.success).toBe(true);
expect(body.data.transactionId).toBeDefined();
expect(body.data.message).toMatch(/payment request/i);
});
it('returns redirect response for CARD', async () => {
const { body } = await request(app)
.post('/api/v1/payments/initiate')
.set('Authorization', `Bearer ${testUserToken}`)
.set('x-pakashop-key', process.env.PAKASHOP_CLIENT_KEY)
.send({ orderId: testOrderId, paymentMethod: 'CARD' })
.expect(200);
expect(body.data.redirectUrl).toMatch(/^https?:\/\//);
});
it('blocks payment when fraud score exceeds threshold', async () => {
// Simulate high-risk transaction
const { body } = await request(app)
.post('/api/v1/payments/initiate')
.set('Authorization', `Bearer ${testUserToken}`)
.send({ orderId: suspiciousOrderId, paymentMethod: 'MTN' })
.expect(403);
expect(body.code).toBe('FRAUD_001');
});
});
3.2 Go Services (Go test)
// services/search/search_test.go
func TestSearchProducts(t *testing.T) {
req := httptest.NewRequest("GET", "/search?q=phone", nil)
rr := httptest.NewRecorder()
handler := http.HandlerFunc(SearchHandler)
handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
var results SearchResults
json.Unmarshal(rr.Body.Bytes(), &results)
assert.True(t, len(results.Hits) > 0)
assert.Less(t, results.ProcessingTimeMs, 100)
}
3.3 Python Services (pytest)
# services/moderation/tests/test_moderation.py
import pytest
from moderation import process_image
@pytest.mark.asyncio
async def test_nsfw_detection():
result = await process_image(
"https://example.com/test-image.jpg",
asset_id="test-uuid",
asset_type="PRODUCT_IMAGE"
)
assert "approved" in result
assert "scores" in result
assert 0 <= result["scores"]["nudity_safe"] <= 1
3.4 Payment Testing Strategy
Because real gateway calls must be avoided in CI, the payment system supports three testing modes:
MockAdapter (Local and CI)
# .env.local / CI environment
PAYMENT_PROVIDER=MOCK
MockAdapter simulates all gateway responses:
initiateDeposit()→ returnsACCEPTEDafter a 500 ms delaysimulateWebhook()→ fires adeposit.completedevent after 2 screatePaymentLink()→ returns a local/mock-checkoutURL
Use MockAdapter for all unit and integration tests.
Sandbox Mode (Manual QA)
# staging .env
PAYMENT_PROVIDER=AUTO
PAWAPAY_BASE_URL=https://api.sandbox.pawapay.io
FLUTTERWAVE_BASE_URL=https://api.flutterwave.com/v3
Test card (Flutterwave): 4187427415564246 / any future expiry / CVV 828.
PawaPay sandbox: trigger callbacks from the PawaPay Sandbox Simulator dashboard.
4. Critical E2E Test Cases (Playwright)
4.1 Authentication Journeys
- User registers with email + password → email verification → login.
- User requests password reset → receives Resend email → resets successfully.
- Google OAuth flow → user created → session established.
- MFA enrollment (TOTP) → login with TOTP code → session established.
4.2 B2C Consumer Journeys
- User browses products → adds to cart → selects MTN Mobile Money → completes USSD checkout → order confirmed.
- User selects Visa/Mastercard → redirected to Flutterwave hosted page → returns to
/payment/callback→ order confirmed. - User views order history → correct payment method label shown (e.g., "MTN Mobile Money").
- User views order details → "Delivery Address" shown (not "Shipping Address").
- User applies coupon at checkout → discount reflected in total.
- User earns loyalty points → redeems points on next order.
4.3 B2B Vendor Journeys
- Vendor completes seller application (all 5 phases) → uploads KYC documents → submits.
- Admin approves application → shop created → user role updated to
SHOP_OWNER. - Vendor creates product with images → Sightengine moderation runs → product appears in catalogue.
- Vendor views their order items → correct
vendorAmountdisplayed. - Vendor manages inventory → stock adjustment → low-stock alert triggered.
4.4 Payment Lifecycle Journeys
- Mobile money USSD push → payment confirmed by webhook → order status →
CONFIRMED. - Webhook duplicate (same
reference) → idempotency check → second event silently ignored. - Payment times out (3 min polling) → timeout message shown → link to order page.
- Admin releases funds →
settlementStatustransitionsHELD → RELEASABLE → PAID_OUT. - Fraud detection blocks suspicious payment → admin review queue entry created.
4.5 Delivery Journeys
- Agent picks up order → GPS tracking starts → buyer sees live location on map.
- Agent within 400m of destination → buyer receives "arriving soon" notification.
- Agent delivers → customer provides PIN → digital signature captured → order
DELIVERED. - Courier company admin adds sub-agent → sub-agent appears in fleet dashboard.
4.6 Admin Journeys
- Admin views all seller applications → filters by status → approves / rejects.
- Admin sends broadcast notification → all active users receive it.
- Admin manually releases vendor funds for a confirmed delivery.
- Admin reviews flagged content → approves / rejects / escalates.
- Admin views fraud review queue → approves blocked payment.
- Admin toggles feature flag → change takes effect without redeployment.
5. Performance Tests (k6)
5.1 Search Performance
// tests/performance/search.js
import http from 'k6/http';
import { check } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 100 },
{ duration: '3m', target: 100 },
{ duration: '1m', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<100'], // 95% under 100ms
},
};
export default function () {
const res = http.get('https://staging.pakashop.store/api/v1/products?search=phone');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 100ms': (r) => r.timings.duration < 100,
});
}
5.2 Checkout Performance
// tests/performance/checkout.js
export const options = {
stages: [
{ duration: '2m', target: 50 },
{ duration: '5m', target: 50 },
{ duration: '2m', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<200'],
},
};
export default function () {
// Simulate checkout flow
http.post('https://staging.pakashop.store/api/v1/orders', orderPayload);
http.post('https://staging.pakashop.store/api/v1/payments/initiate', paymentPayload);
}
6. Security Tests
6.1 OWASP ZAP
Run ZAP baseline scan against staging before every production deploy:
# .github/workflows/security-scan.yml
docker run -t owasp/zap2docker-stable zap-baseline.py \
-t https://staging.pakashop.store \
-r zap-report.html
6.2 Dependency Audit
npm audit --audit-level=moderate
# Block PRs with high/critical vulnerabilities
6.3 SAST
Static analysis via SonarQube or GitHub CodeQL on every PR.
7. Test Environment
| Environment | Database | Gateway | Redis | Meilisearch | Purpose |
|---|---|---|---|---|---|
| Local | Local PostgreSQL (Docker) | MOCK | Local Redis | Local Meilisearch | Developer testing |
| CI (GitHub Actions) | PostgreSQL service container | MOCK | Redis service container | Meilisearch service container | Automated tests per PR |
| Staging | Staging PostgreSQL | PawaPay/Flutterwave sandbox | Staging Redis | Staging Meilisearch | Pre-release QA |
| Production | Production PostgreSQL | PawaPay/Flutterwave live | Production Redis | Production Meilisearch | Live platform |
CI service containers (see ci.yml):
services:
postgres:
image: postgres:16
env: { POSTGRES_PASSWORD: test, POSTGRES_DB: pakashop_test }
ports: ['5432:5432']
redis:
image: redis:7
ports: ['6379:6379']
meilisearch:
image: getmeili/meilisearch:v1.7
env: { MEILI_MASTER_KEY: test_key }
ports: ['7700:7700']
8. Continuous Testing
- All unit and integration tests run automatically on every pull request (GitHub Actions).
- Merges to
productionrequire the full test suite to pass. - E2E Playwright suite runs weekly on the staging environment.
- Performance tests (k6) run weekly on staging.
- Security scans (OWASP ZAP, npm audit) run on every PR and weekly.
npm auditruns in CI; PRs with high/critical vulnerabilities are blocked.
9. Test Data Management
- A
prisma/seed.ts(orseed.js) script provides consistent test data (users, shops, products, orders). - The test database is reset before each integration test run using
prisma migrate reset --force. - No production data is ever used in tests; all test records use synthetic Zambian data (e.g.,
0977000001as test phone numbers). - Test Redis uses DB 1 to avoid conflicts with development data.
- Test services run on 4000-series ports to avoid conflicts with local development.
For internal use only. Do not distribute outside Pakashop engineering.