Test Coverage Targets for Payment Code
Payment code coverage targets: webhook handler (critical business logic) → 100% branch coverage; amount/commission calculation functions → 100% branch coverage; checkout initiation → 90%+; error handling paths → 80%+; frontend checkout UI → 60-70% is acceptable (covered by E2E tests). Use Istanbul/nyc (JS) or coverage.py (Python) to measure. Block merges if webhook handler coverage drops below 90%.
Payment Code Coverage Target Matrix
| Code Component | Target Coverage | Why |
|---|---|---|
| Webhook signature validation | 100% | Security-critical — missing this allows fake events |
| Webhook event routing (charge.success, etc.) | 100% branches | Each event type triggers different business logic |
| Order fulfillment after payment | 100% branches | Bugs here mean unfulfilled orders or double fulfillment |
| Amount/commission calculations | 100% branches | Rounding bugs cost money — cover all number edge cases |
| Checkout API call construction | 90%+ | Ensure correct parameters are sent to Paystack |
| Error handling (network, 5xx) | 80%+ | Prevent silent failures and 500 responses to customers |
| Idempotency checks | 100% | Duplicate processing = financial data corruption |
| Transfer payout logic | 90%+ | Wrong recipient or amount = real financial loss |
| Frontend checkout UI | 60-70% | E2E tests cover the full user flow |
Setting Coverage Thresholds in Jest
// jest.config.js
module.exports = {
collectCoverage: true,
coverageDirectory: 'coverage',
collectCoverageFrom: [
'src/**/*.{js,ts}',
'!src/**/*.test.{js,ts}',
'!src/types/**',
],
coverageThreshold: {
// Global minimum
global: {
branches: 80,
functions: 85,
lines: 85,
statements: 85,
},
// Per-file minimums for critical payment code
'./src/webhooks/paystack-handler.js': {
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
'./src/payments/fulfillment.js': {
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
'./src/payments/calculations.js': {
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
},
};
Learn More
This guide is part of the Paystack testing guide.
Key Takeaways
- ✓Webhook handler business logic should have 100% branch coverage — every code path that handles money must be tested.
- ✓Amount and commission calculation functions need 100% branch coverage, including edge cases (0 amount, max amount, rounding).
- ✓Checkout initiation code (API call construction) should be at 90%+ coverage.
- ✓Error handling paths (network errors, 5xx from Paystack, invalid response format) need dedicated tests — do not rely on the happy path to cover these.
- ✓Frontend payment UI can have 60-70% coverage — E2E tests cover the rest.
- ✓Set coverage thresholds in your test config (Jest coverageThreshold, pytest-cov --fail-under) to block low-coverage merges.
Frequently Asked Questions
- Is 100% coverage achievable for a webhook handler?
- Yes — webhook handlers are pure logic functions with a finite number of input combinations. Write a test for each event type you handle (charge.success, charge.failed, etc.), each branch condition (metadata missing, order not found, duplicate reference), and each error case. 100% branch coverage is realistic and worth the effort for money-moving code.
- Does high test coverage mean my payment code is secure?
- Coverage measures which code paths are tested, not how well they are tested. 100% coverage with poor assertions means nothing. A 90% covered webhook handler with rigorous assertions (testing that the right DB columns update, the right amounts are recorded) is better than 100% coverage with "expect(result).toBeTruthy()" everywhere.
- Should I measure line coverage or branch coverage for payment code?
- Branch coverage is more meaningful for payment code. A function with an if/else might have 100% line coverage if tests exercise both the if and else code, but if you only test one branch, you have 50% branch coverage. Branch coverage catches untested conditional logic that line coverage misses.
- What is a good coverage target for a first-time payment integration?
- Start with 80% statement coverage globally, and set per-file 100% for webhook handler and amount calculation files. As you add more tests, raise the global threshold. The key is to start with thresholds and enforce them in CI — even imperfect targets are better than no targets.
Ready to build real-world apps?
Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.
Apply to the McTaba Marathon