Capability 27 · Quality Assurance

Quality Assurance

Tests that protect money and trust — because with payments, a small regression costs cash.

Before you read: Written from live engineering practice — the money-moving, million-user work our team runs on our own products, set down so anyone building something can learn from it.

01 · What it is

Quality assurance on a money product isn't a nice-to-have; a regression in the payment path costs customers cash and trust in real time. We build automated unit, integration and end-to-end tests that run on every release, manual QA for the human touches automation can't judge, and edge-case and boundary testing that finds the bug your users would have found first. Payment and reconciliation scenarios are tested as scenarios — double-submission, retries, partial failures, exact rounding — and regression suites exist precisely to ensure what we already fixed never comes back. Bugs are triaged with clear severity so the scary ones never wait behind the cosmetic ones.

What a quality assurance build covers:

  • Automated unit, integration & E2E test suites
  • Manual QA for the feel automation can't judge
  • Edge-case & boundary testing that finds hidden bugs
  • Payment & reconciliation scenarios tested as scenarios
  • Regression suites protecting everything already fixed
  • Bug triage with clear severity & honest priorities
What we do · How we do it — as TGJOF Enterprise

This is how we do Quality Assurance

A QA engineer sees a release differently: not as the features that shipped, but as a set of claims — about the fee, the balance, the retry, the callback — each of which must be provably true. We build that wall from the inside, starting with the flows that can lose money or trust and moving outward to the cosmetic, because a severity-ranked queue is the only queue a payments product survives with. On a platform that pays through many rails at once, that discipline repeats on every one of them: the same callback, idempotency and reconciliation checks that guard an M-Pesa/Daraja flow at home are reapplied to PayPal, Stripe, PayStack, cards and bank transfers. Money does not get an easier standard because it travelled a different wire.

What we do

  • QA is a wall, not a phase — quality starts at intake with acceptance criteria, and every release walks the gate: automated suites, a manual pass and a severity review, with the evidence written down.
  • The suite ships with the feature — tests are written beside the code, not bolted on in release panic, so 'done' has a testable meaning from the day the build starts.
  • The pyramid is sized to the risk — many fast unit tests, honest integration seams and a handful of precious end-to-end money journeys, with skilled humans on the flows automation cannot judge.
  • Payment scenarios tested as scenarios — double submission, duplicate callbacks, retries, rounding and terminal-state replay are rehearsed on every rail, not just on the happy path.
  • Severity beats volume — a balance, escrow or refund defect outranks any cosmetic complaint, and a critical failure blocks the release while a typo rides the next train.

How we do it

  • Map the risk before the strategy — the flows that can lose money, trust or data are named first, and the test plan is built around protecting them in priority order.
  • Run the same scenario battery on every rail — the dropped callback, the doubled tap and the replay are rehearsed against the M-Pesa/Daraja flow and equally against PayPal, Stripe, PayStack, cards and bank, so no gateway gets an easier bar.
  • Stub the gateway honestly — provider sandboxes are wired where they exist and real-shaped mocks elsewhere, including failure shapes and duplicate payloads, so the seam is proven rather than assumed.
  • Gate every release in CI — the fast layers run on every commit and the full wall before deploy, with a red suite stopping the pipeline and the evidence attached.
  • Prove the fix in production, not just in the build — every defect leaves a regression test, releases document what the suite protected, and crash and error signals confirm a fix held after it shipped.

02 · The full discipline

On a money product a small regression costs cash and trust in real time. QA is the wall between confidence and the customers' wallets.

Most teams discover quality after the fact — a bug in production, a customer who notices before you do, a release that has to be reverted at the worst hour. Quality assurance is the discipline that moves those discoveries earlier: proving the system behaves before it meets real users, and being able to say exactly what was tested, what passed and what was deliberately deferred.

We build QA into every money product we ship — and we run it every day on KodiiPay, a live payments platform where a regression means real cash and real trust in real time. Automated unit, integration and end-to-end suites gate every release; payment scenarios are tested as scenarios — retries, double-submission, rounding, network drops; skilled humans cover the moments automation cannot judge; and bugs are triaged by severity, not volume, so the money-critical fix never waits behind a typo.

Below is how we actually do QA — the pyramid, the environments, the bug lifecycle, the coverage reality and the honest economics of test automation — because on a product that moves money, 'it works on my machine' is not a quality plan.

03

QA is a wall, not a phase

Testing is not a stage the product passes through before launch; it is a wall between the team's confidence and the customers' wallets. We treat QA as a standing function that starts at requirements and ends after the fix has survived production.

  • Quality is decided at intake — acceptance criteria are defined with the feature, so 'done' has a testable meaning before the build starts.
  • Tests exist before the feature — the suite is written with the code (or before it), not bolted on in the release panic.
  • Every release walks the wall — no deploy ships without the gate: the automated suites, the manual pass and the severity review.
  • QA owns the evidence — what was tested, what passed, what failed and what was deferred is written down, not remembered.
  • The wall moves with the risk — money flows are gated harder than cosmetic pages; the height of the wall tracks the blast radius.
  • QA reports to the outcome — the function's job is shipped trust, not finding bugs; the bug list is a symptom, never the goal.

On our platform the wall is literal: a money path that fails its suites cannot ship, and no urgency argues around it.

04

The testing pyramid: unit, integration, e2e, manual

We test in layers because each layer catches a different class of screw-up, and the pyramid shape makes the suite fast, cheap and dependable — many small unit tests, fewer integration tests, a precious few end-to-end journeys and a thin, deliberate layer of human judgement on top.

  • The base is unit tests — the fastest, cheapest layer, proving the smallest truths in isolation and running on every keystroke.
  • The middle is integration — proving the seams: the module, the database, the API and the third-party stub.
  • The point is end-to-end — full journeys with real components and real runs, few enough to stay fast and honest.
  • The top is human judgement — exploratory and manual passes on the flows where feel, timing and empathy decide.
  • The shape is a budget — a pyramid of many unit tests, fewer journeys and a thin layer of human passes; the inverted version is unaffordable.
  • Layer honesty — we never claim an e2e suite replaces a unit test; each layer earns its slot and its cost.

The pyramid is why our suite is fast enough to run on every commit and strong enough to block a release — speed and protection are the same thing when a suite must gate everything.

05

Unit tests: the smallest truths

Unit tests prove the smallest units behave: a fee function returns the right amount, a validator rejects a malformed phone, a state machine refuses an illegal transition. They run in milliseconds, they run on every commit, and they make the base of the pyramid solid.

  • Behaviour over implementation — tests assert outcomes a user would care about, not the private guts of a function.
  • The arithmetic is tested as arithmetic — fees, rounding, balances and shortfall math are unit-tested to the decimal.
  • Validation rules are proven — every input rule (phone format, amount bounds, required fields) has a passing and a failing test.
  • State machines are exhaustively checked — each allowed transition works; each forbidden one is refused loudly.
  • Edge cases are first-class tests — zero, negative, maximum, empty, whitespace and the off-by-one are cases, not accidents.
  • Tests are fast enough to live in the loop — a unit test that takes a hundred milliseconds is a test that gets skipped; ours run in milliseconds.

Unit tests are how a fee change is safe to ship on a Friday — and how the team knows it before the build, not after the complaint.

06

Integration tests: the seams between systems

Products break at the seams — where the app meets the API, the API meets the database, the database meets the gateway. Integration tests prove the seams hold: the request, the query, the constraint and the response behave together.

  • API contracts are exercised — every endpoint is called with real payloads and the responses asserted, not eyeballed.
  • Database constraints are honoured — the generated column, the check constraint and the foreign key are proven by tests that would trip them.
  • Third parties are stubbed honestly — the gateway or provider is simulated with real-shaped payloads, including failures and duplicates.
  • State across systems is asserted — after a payment, the transaction, the ledger and the notification all agree; integration proves it.
  • Retries and timeouts are rehearsed — the integration suite replays a timeout and asserts the system re-arms, not crashes.
  • Test data is seeded deliberately — fixtures are built for the cases that matter, so tests do not depend on yesterday's leftovers.

Integration is where 'the screen worked in isolation' stops being enough — because in production nothing is isolated.

07

End-to-end tests: the journey with real threads

The end-to-end layer drives the full product as a user would: open the app, walk the flow, reach the outcome. It is the most expensive layer, so we choose the journeys that carry the most risk and protect them like wiring.

  • Money journeys get the slots — top-up, pay, send, withdraw and refund flows are the journeys e2e protects first.
  • Real components, real runs — the build under test is the real stack, in a production-like environment, not a mocked shell.
  • Few, precious and slow-but-safe — dozens of journeys, not hundreds, so the suite stays reliable and non-flaky.
  • Flakiness is treated as a bug — a test that passes on Tuesday and fails on Wednesday is investigated like a product defect.
  • The e2e layer never replaces the lower layers — it proves the composition; the units and seams are already proven underneath.
  • Recovery journeys are included — the 'kill the app mid-payment' and 'gateway times out' scenarios run end-to-end, not just unit-level.

An e2e journey is the only test that knows what a user feels — and on a money product, feeling is part of correctness.

08

Payment scenarios tested as scenarios

Money logic fails in scenarios, not in units: a double callback, a retried push, a rounding split, an insufficient balance at the worst moment. We test payments as the situations they really are, not as happy-path functions.

  • Double submission — the user taps pay twice; the assertion is one charge, one transaction and one notification.
  • Duplicate callbacks — the gateway confirms twice — whether on M-Pesa/Daraja at home or on PayPal, Stripe, PayStack, a card or a bank rail — and the ledger changes exactly once.
  • Retries and transport errors — a dropped response leaves the money pending, and the retry recovers the truth.
  • Rounding across a batch — fees and splits across dozens of rows still total to the exact amount.
  • Insufficient balance with a fee — the user gets the exact shortfall, never a vague error and a dead end.
  • Interruption in the flow — the app is killed between initiation and confirmation; recovery is provable.
  • Terminal-state replay — a confirmed transaction on any rail receives a stray callback and answers with the settled state; the same idempotency check that holds on M-Pesa/Daraja holds on PayPal, Stripe, PayStack, cards and bank transfers.

Our own payment suite rewinds these scenarios every release, on M-Pesa/Daraja as the lived home-market rail and on every card, PayPal, Stripe, PayStack and bank rail we touch — because each once cost us a real lesson, and each is now a permanent gate.

09

Regression: everything already fixed stays fixed

The most expensive bug is the one you already fixed that came back. Regression suites carry the entire history of the product's hard-won lessons and re-run them on every change, so nothing the team conquered gets quietly resurrected.

  • The suite is the memory — every significant bug leaves a regression test behind it, so it cannot return unnoticed.
  • Every release runs the whole history — old, fixed flows are re-proven alongside new ones, not assumed safe.
  • Money regressions are the priority — balance math, fee logic, escrow and refunds carry the strictest regression protection.
  • The suite grows but stays fast — layers and prioritization keep the growing suite under the time budget that lets it gate every commit.
  • A regression is a double failure — a bug that returns means the fix was incomplete or the suite was shallow; both are investigated.
  • Regression proof is released — each release documents what the suite protected, so the evidence is never private.

Regression is why the product can keep getting faster and newer without forgetting the million small truths it already learned.

10

UAT and acceptance: proof the owner can see

User acceptance testing is where the owner agrees the product does what they asked. Because we write acceptance criteria into every feature, UAT is a structured walkthrough of proven behaviours, not a demo day of vague impressions.

  • Criteria are written at intake — each feature arrives with its own acceptance checklist, so 'done' means testable things.
  • UAT is a scripted session — the owner walks the flows with the criteria beside them; every pass or fail is recorded.
  • Edge-case scenarios are part of UAT — the owner sees the error, the recovery and the boundary, not just the sunshine path.
  • The evidence is captured — screenshots, recordings and results are kept, so 'we agreed this' survives the memory of the meeting.
  • Fails go to a managed queue — UAT findings enter the bug lifecycle like any defect, with severity, not just emotion.
  • Sign-off is earned — the owner signs because the checklist is green, not because the demo looked good.

A signed-off UAT is the moment trust becomes contractual — which is why we make it impossible to fake.

11

Exploratory testing: where the scripts end

Scripted tests prove what we predicted; exploratory testing hunts what we failed to predict. A skilled tester walking the product without a script — trying the weird path, the old device, the double tap — finds the bugs the automation never imagined.

  • Charter, not script — the tester gets a goal ('break the withdrawal flow') and freedom in how they pursue it.
  • The tester's toolkit is skill — domain understanding, a suspicious mind and the memory of past failure classes.
  • Weird paths are the quarry — the orphaned back button, the stale session, the two-tap race, the state that lies.
  • Findings are triaged like any bug — an exploratory find enters the same lifecycle with severity, not a separate shadow queue.
  • Sessions are time-boxed bursts — focused sprints on the risky flows beat a heroic all-week wander.
  • Context is king — the explorer knows the device, the network and the user the flow was built for.

Automation tells us what we built behaves as designed; exploration tells us what we forgot to design — we run both, always.

12

Accessibility testing: the second wall

A product that excludes users not only fails people; it fails audits, reputations and sometimes the law. We test accessibility as a quality gate, automatically in the build and manually on the assistive paths that matter.

  • Automated checks run in the gate — axe and Lighthouse scan every release and block regressions the day they land.
  • Keyboard journeys are scripted — tab order, focus visibility and shortcut behaviour carry e2e coverage.
  • Screen-reader passes are manual — a skilled pass reads the key flows through TalkBack and VoiceOver as the user hears them.
  • Contrast is continuously verified — the token and component layers are checked against the palette's contrast proofs.
  • Colour-blindness is designed and tested — meaning never rides on a hue; patterns and labels carry it.
  • a11y regressions are handled immediately — an accessibility failure hits the same severity triage as a functional one.

Accessibility is not a niche audit in our QA; it is one of the standing walls every release walks through.

13

Performance and load: tested before the traffic

Performance problems are release problems: the platform is slower than it was, the launch day melts the database, the rent rush exhausts the pool. We test performance before the traffic arrives — load, stress, endurance and the budget — so speed is proven, not discovered.

  • Load tests at realistic peaks — the suite simulates the expected concurrent load and finds the breaking point before launch day.
  • Stress beyond the peak — we push past the expected load to learn where the system degrades and how it fails.
  • Budgets are enforced in CI — bundle size, API latency and start time have limits a feature cannot silently cross.
  • Slow networks are included — a fast-on-Wi-Fi-and-dead-on-3G product has not been performance tested.
  • Database queries are examined — the hot paths carry explain plans and indexes; a slow query is a finding, not a fact.
  • The baseline is measured first — we cannot prove the change helped without knowing what the before looked like.

On a platform where rent day is the load test, we compress the test to a Thursday afternoon instead of discovering it in production.

14

Test environments that actually match production

Tests run in an environment that lies about production produce tests that lie. We maintain environments that reflect the real stack — the real database shape, the real provider integrations, the real version drift — so a passing test means something true.

  • Production-like, never production — staging mirrors the stack and the data shape without risking real money or real data.
  • Seeded, shaped data — fixtures reflect production shape (users, wallets, transactions, edge cases), not a toy database.
  • Provider sandboxes are wired — where a real gateway sandbox exists, tests hit it; elsewhere honest stubs.
  • Versions are pinned — the environment runs the same dependency versions as production, so 'works locally' is not a lie.
  • Test data is disposable — environments spin clean, seed fresh and reset on demand, so leftovers cannot poison a run.
  • Secrets never enter tests — test environments use their own credentials; production keys stay out of the pipeline.

A test that passes only in an environment that shares nothing with production is a test that passes for a holiday — the wall needs an environment it can believe in.

15

The device and browser matrix

Kenyan users hold an enormous range of phones on a range of networks, and the difference between a cheap Android and a flagship is not cosmetic. We test across a deliberate matrix — entry-level, mid, high-end; Android and iOS; the browsers that matter — so the product survives the market's full hardware.

  • Entry-level Android is the floor — limited RAM, old OS versions and small screens are first-class test targets.
  • The main browsers are covered — plus the in-app browsers users actually land in, which are often the forgotten ones.
  • Network profiles are sampled — 3G, flapping 4G and offline are tested, because the lab's Wi-Fi is not the country.
  • The matrix is a budget — we test the combinations that carry risk, transparently, rather than pretending coverage of everything.
  • Device farms are used where they pay — real-hardware testing on the budget tier beats an emulator's confidence.
  • Regressions on old devices gate the release — a slow-down on the entry tier is a blocker, not a footnote.

A product that only smiles on a flagship has not been tested in Kenya; our matrix is built around who actually holds the phone.

16

The bug lifecycle: triage, severity, closure

A bug is not a fact until it is triaged, and it is not resolved until it has been verified and survived production. We run a disciplined lifecycle so the word 'fixed' means something the whole team can trust.

  • Capture with repro steps — a bug ticket that lacks the steps to reproduce it is a rumor, not a defect.
  • Triage by severity and risk — priority is set by the blast radius, not by who shouted loudest.
  • The money-critical bug jumps the queue — a balance, fee, escrow or refund defect outranks any cosmetic complaint, always.
  • Fix, then test, then verify, then close — a fix is provable only when its regression test passes and the tester has re-walked the flow.
  • Deferred bugs are explicit — a tracked deferral is a decision with a date and a reason, not a wish that it vanishes.
  • Root cause, not just symptom — a bug returned to the team with 'fixed' and no cause analysis is a bug on a schedule.

A mature bug lifecycle is why 'fixed' on our builds is a word you can build a weekend on.

17

Severity over volume

A backlog sorted by shout-count buries the scary bug under the cosmetic one. We triage by real severity and risk — payment-critical fixes never wait behind typos, and the cosmetic backlog is never confused with the dangerous one.

  • Severity is defined — a precise scale (crashing, money-loss, blocked flow, cosmetic) means everyone triages with the same ruler.
  • Risk to money and data outranks everything — a balance bug beats a typo every morning, on every release.
  • Volume is a dashboard, not a priority — a hundred minor issues do not outrank one serious one, no matter how noisy.
  • Release gates are severity-aware — a critical defect blocks; a cosmetic one rides the next train with a visible decision.
  • Triage is a meeting, not a whisper — priorities are set in the open so no quiet lobby games the queue.
  • The scary bug is never quiet — items that can lose money or data are flagged in every standup until they close.

We would rather ship with three cosmetic blemishes than one financial wound deferred — the severity discipline says that out loud.

18

CI-gated automated tests that block bad releases

Automation only protects a product if it can stop a bad release. Our test suites are wired into CI as a genuine gate: the build fails, the deploy stops, the notification lands, and the release cannot pass until the suites are green.

  • Every commit runs the fast layers — unit and integration suites execute on every push, so a broken foundation is known in minutes.
  • Every release runs the full wall — e2e journeys, device checks and manual gates run before the deploy is allowed.
  • Failure blocks, not notifies — CI is a gate, not an afterthought; a red suite stops the pipeline with the evidence attached.
  • Fast feedback is a design goal — suites are engineered to run quickly enough that no team learns about a failure the next morning.
  • Flaky tests are quarantined — an unreliable test is fixed or removed; it never becomes a silent skip, because silences become corpses.
  • The gate is visible — release coverage is public to the team, so 'it ships' always knows what was proven.

A gate that can be argued around is a gate that will be argued around exactly once, on the worst bug of the year.

19

Manual QA for the human touches

Automation catches the logic; skilled humans catch the feel. A careful manual pass catches the awkward wording, the unreadable row on a small screen, the moment a flow feels wrong even though every assertion passed — the judgements a machine cannot run.

  • The freshness of a human walk — a trained tester notices the inverted dropdown far before the users do.
  • First-run experience is walked by hand — onboarding, empty states and first impressions are judged by feel, not assertions.
  • Money flows get a human once-over — beyond the scripts, a person reads every prompt on the withdrawal path with a user's eyes.
  • Copy is read as a user reads it — every label, fee and error string is proof-read with a real user's patience, and a typo is a bug.
  • The exploratory pass rides alongside — the manual layer is structured (charters, time-boxes, session notes), never a vague wander.
  • Manual findings feed the suite — every manual discovery becomes a regression test, so nothing is caught only once.

Machines are honest about logic; humans are honest about feeling — QA on a product worth shipping is always both.

20

QA is a reference: evidence the business can hold

QA is not just a bug-catcher; it is the reference a business holds up to prove its product is real — to partners, to regulators, to auditors and to itself. We treat test evidence as a deliverable, written so the truth is inspectable long after the sprint.

  • The test report is a document — what was run, what passed, what failed and what was deferred, written for humans.
  • Coverage is stated, not imagined — the share of flows under automated protection is reported honestly, with the gaps named.
  • Risk is documented with the code — the suite itself is reviewed and maintained like code, so the reference stays true.
  • Evidence survives the people — when a tester leaves or a client asks later, the record answers, not the memory.
  • Auditors get a story — for a money product, test evidence is the difference between a calm audit and a rebuild.
  • The numbers are shared plainly — passing rates, flake rates and known risks are reported without spin or hiding.

A company that can point to its suite and its reports is a company that can survive an audit; that is the level we build to.

21

Honest coverage reporting

Coverage percent is the most lied-about number in software, because it measures lines executed, not risk covered. We report coverage honestly — what it means, what it does not, and where the real gaps live — so the number improves decisions instead of decorating a dashboard.

  • Line coverage is not truth — 90% line coverage can still miss the one fee path that matters; we say so plainly.
  • Risk coverage is tracked — the flows that can lose money or trust each have named protection, and the list is reviewed.
  • The gaps are the report — what is not covered, and why, is documented alongside what is; hiding a gap is hiding a risk.
  • Trends beat snapshots — coverage direction across releases matters more than a single number on a given Thursday.
  • Coverage is a budget, not a bounty — the target is proportional to risk; a cosmetic page does not outrank a money flow.
  • Numbers are auditable — the coverage claims are computable, reproducible and traceable to the actual suites.

An honest coverage report is the difference between a team that knows its exposure and a team that is surprised by it.

22

The ROI of test automation, honestly

We do not sell automation as free lunch. Automated tests cost time to write, time to maintain and time to run; they pay back when they catch a production bug, gate a bad release or let a change ship on a Friday in confidence. We are honest about the economics because a team that mismanages them abandons the whole idea, and everything is lost.

  • The cost is real — writing, maintaining and running suites is work; we budget it like work, not pretend it is free.
  • The return is real too — catching a bug in CI costs minutes; catching it in production costs trust, cash and a night.
  • ROI compounds across releases — the suites protect every release after the first and amortise across the product's life.
  • Stable suites ship — the ratio of fixtures to flakes is managed, because a suite the team distrusts gets skipped silently.
  • Automation replaces some, not all — it does not remove manual QA; it removes the boring repetition manual QA hates.
  • We size the suite to the risk — a brochure site gets a flying gate; a payments platform gets the wall; the size matches the price of failure.

Automation is an investment with a return curve; we build it where the curve is steepest and refuse it where it is fantasy.

23

Prevention over detection

The cheapest bug is the one never created. We push quality upstream — reviews, specification, static analysis and the discipline of writing tests as you code — so the suite is the backstop for a team that was trying to be correct all along.

  • Code review before the suite runs — a human review catches the misunderstanding no test would have targeted.
  • Static analysis runs early — linting, type checks and dependency audits fail fast, before a human eye is spent.
  • Specification prevents the defect — a feature with clear criteria generates fewer bugs than one specified in vibes.
  • Tests written beside code — the culture of test-as-you-build means coverage is a habit, not a retrospective guilt trip.
  • The five-whys of every bug — each significant defect is traced to the process gap that let it in, and the gap is closed.
  • Developers own their quality — the team that writes the feature reads its own suite and its own review.

Detection protects the release; prevention protects the team's time, the budget and the customers' mornings.

The toolchain

The quality assurance toolchain

The machinery of proof — from the smallest unit test to the load sim and the evidence report. Every layer exists because a live money product made it necessary.

stack.toolchain

01

Unit testing

The smallest truths, proven fast

  • JestThe workhorse runner for JavaScript and TypeScript unit suites.
  • VitestFast, Vite-native unit testing for modern frontend builds.
  • React Testing LibraryTests that assert behaviour the way a user experiences it.
  • pytestPython's unit framework for the backend services that need it.
  • JUnitThe Java stack's proven unit runner where the platform uses it.

02

Integration & API

Proving the seams hold

  • PostmanCrafting and asserting API contracts with real payloads.
  • SupertestIn-process HTTP tests that exercise the real request path.
  • TestcontainersReal database and service containers so tests match production.
  • PactContract testing so consumers and providers cannot drift apart.
  • InsomniaDesign-time API checking beside the automated suites.

03

End-to-end

The journey, with real threads

  • PlaywrightReliable cross-browser journeys on the modern web stack.
  • CypressDeveloper-friendly e2e for web flows that need faster iteration.
  • DetoxGrey-box e2e for React Native on real devices.
  • MaestroSimple, robust mobile UI flows for the money journeys.
  • AppiumCross-platform native drives for the device matrix that needs reach.

04

Performance & load

Tested before the traffic

  • k6Scriptable load testing that simulates realistic concurrent users.
  • ArtilleryScenario-heavy load simulation for API and event systems.
  • JMeterThe veteran load runner for heavier, reusable test plans.
  • Lighthouse CIPerformance budgets enforced in the pipeline for web surfaces.
  • WebPageTestReal-network speed checks on the connections users actually hold.

05

Accessibility

The second standing wall

  • axe-coreIn-browser and CI accessibility assertions on every release.
  • LighthouseAudit-level contrast and a11y checks across the whole page.
  • Pa11yAutomated a11y reporting on the HTML the user really gets.
  • WAVEQuick visual validation of page-level accessibility.
  • TalkBack / VoiceOver passesSkilled manual reads of the key flows as assistive users hear them.

06

Environments & CI

A wall it can believe in

  • GitHub ActionsThe pipeline that runs fast layers on every commit and gates the release.
  • DockerReproducible environments that match the runtime stack.
  • Provider sandboxesReal gateway sandboxes (M-Pesa's included) wired into the tests.
  • Staging parityA staging mirror of production shape, versions and data.
  • Seeded fixturesDeliberate test data covering the cases that matter.
  • Preview deploysEvery pull request reviewable in a live environment before merge.

07

Evidence & bug lifecycle

What was tested is written down

  • Linear / JiraThe bug and triage home where severity decides the queue.
  • SentryProduction crash and error signals that confirm a fix held.
  • TestRail / QA TouchTest management that records runs, results and coverage.
  • Crash reportingDevice-level failures surfaced back into the triage queue.
  • Coverage reportingReproducible coverage numbers shared plainly, gaps included.

Lifecycle

The QA lifecycle — from quality bar to production proof

Testing is not a release ritual; it is a standing loop that starts before requirements and keeps running after the fix has survived production.

01

Define the bar

What 'done' must prove per feature and per release, written before the build.

02

Map the risk

The flows that can lose money, trust or data, and the priority for protection.

03

Build the strategy

The pyramid sized to the risk: units, integrations, journeys, human passes.

04

Set the environments

Production-like staging, honest stubs, seeded fixtures, pinned versions.

05

Write the suites

Automated tests developed beside the code, not after it.

06

Gate every commit

Fast layers run in CI on every push and block a red build.

07

Walk e2e scenarios

The precious journeys and the payment scenarios tested as scenarios.

08

Run the human layer

Exploratory, accessibility and feel passes on the flows automation cannot judge.

09

Host UAT

The owner walks the checklist; every pass and fail is captured.

10

Gate the release

The full wall, the severity triage and the deliberate deferrals with reasons.

11

Monitor production

Crash, error and latency signals confirm the fix held after release.

12

Report and improve

Honest coverage, trend and prevention reviews feed the next cycle.

Closing

More than development

Quality assurance on a product that moves money is not a nice-to-have — it is the wall between the team's confidence and the customers' wallets. Our QA practice includes:

Acceptance criteria written into every feature before the build.A testing pyramid — unit, integration, end-to-end and manual — sized to risk.Unit tests that prove fees, validation and state machines to the decimal.Integration tests across the API, database and gateway seams.End-to-end journeys protecting the money flows first.Payment scenarios tested as scenarios — double taps, duplicate callbacks, retries, rounding.Regression suites carrying the product's entire history of fixed bugs.Structured UAT where the owner signs against a proven checklist.Exploratory testing that hunts what the scripts never imagined.Accessibility testing as a standing wall — automated and by ear.Performance and load tests run before the traffic arrives.Environments that actually match production, with honest stubs.A device and network matrix built around the Kenyan market.A rigorous bug lifecycle from repro steps to verified closure.Severity triage that never lets a typo outrank a money bug.CI-gated tests that genuinely block bad releases.Manual QA for the human moments automation cannot judge.Test evidence written as reference the business can hold.Honest coverage reporting with the gaps named.Automation ROI sized to the risk, never sold as magic.Prevention upstream — review, static analysis and test-as-you-build.The same QA discipline that runs on our live payments product.

QA is not the department that finds the team's mistakes; it is the function that makes the product safe to believe in — and on a money product, belief is the whole business.

We test because 'it works on my machine' is not a quality plan — and because we have run a live platform long enough to know exactly where the walls belong.

Previous capability

Product Design Systems

Next capability

Performance Engineering

Building something like this?

The discipline above is what we run on our own products every day. If it would help on yours, our door is open.