← All work

Scandiweb · internal product · Full stack, front to back · 2026

Load testing without writing a script

A full-stack internal product so a product manager can answer their own question

5 → 50
virtual users per run
19.08%
error rate surfaced
60s
worst p95 exposed
The generated report from a run. It caught what the error rate hid: three add-to-cart calls returned 200 while adding nothing, so a clean 0.00% was masking real cart losses.
The generated report from a run. It caught what the error rate hid: three add-to-cart calls returned 200 while adding nothing, so a clean 0.00% was masking real cart losses.
The exported PDF report. Client, environment and the colleague who ran it are redacted; every figure is untouched.
The exported PDF report. Client, environment and the colleague who ran it are redacted; every figure is untouched.
Predefined Magento journeys plus custom scripts, which are smoke-tested against a live k6 run before they are accepted.
Predefined Magento journeys plus custom scripts, which are smoke-tested against a live k6 run before they are accepted.

The problem

Load testing a Magento environment meant writing k6 scripts by hand. In practice that meant only engineers could do it, and the people who actually needed the answers, product managers deciding whether a campaign would hold, could not get them without interrupting someone.

What I did

I built it outside our usual stack, on both sides. Behind: a Fastify API in TypeScript with Prisma on PostgreSQL, the run lifecycle, and the awkward part nobody plans for, recovering long-running tests orphaned by a server restart. In front: a Next.js dashboard in React with live run progress streaming over Server-Sent Events rather than websockets, since the traffic only goes one way.

Scenario discovery runs headless Playwright against the target, so a run covers what the site actually has rather than a hand-written list. One recent run walked 18 categories, 41 products and 21 add-to-carts without anyone naming a URL. The Anthropic Claude API turns the raw k6 output into a summary a non-engineer can act on, including which step failed and how many requests it took with it. A safety interlock restricts every test to the selected store's own origin, because a load-testing tool that can be pointed at somebody else's server by mistake is a liability.

The outcome

It finds things. One recent run against a storefront ramped 5, 25 and 50 virtual users through a browse-and-add-to-cart journey, 941 requests in total, and drew a clear line: at baseline the store was healthy at 697ms average with no errors, and at five times that load it fell over. The error rate hit 19.08%, and the report named the culprit rather than gesturing at it: the product step, 25 of 39 requests failed, 17 timeouts and 8 responses of 502, with p95 pinned at the 60-second timeout ceiling. At ten times load the session-init step was the slowest at 31.3 seconds p95.

That is the output a product manager can act on. It arrives as plain English with the numbers behind it, and it says which step broke and how, not that something somewhere was slow.

Built with

  • Node.js
  • Fastify
  • TypeScript
  • Prisma
  • PostgreSQL
  • Next.js
  • React
  • Server-Sent Events
  • Playwright
  • Grafana k6
  • Claude API