End-to-end tests for Express.
Supertest tells you the route returns the right body. It does not tell you the session cookie is dropped behind a proxy in production, which is the Express bug that always ships. The agent drives a real browser, where cookies are real.
--- title: "A user stays signed in across a page load" --- Sign in with the test account, reload the page, and confirm the account menu still shows the signed-in name.
One reload is the whole test, and it is the one supertest structurally cannot do: a real browser, real cookie jar, two requests.
how do I write end-to-end tests for a Express app?
Supertest covers an Express route's request and response inside the process. What it cannot cover is the state a browser carries between requests, and that is where the Express bugs that reach production live: a session cookie without Secure or SameSite that works on localhost and is dropped behind TLS, trust proxy left unset so every user shares the load balancer's address, a redirect chain that only loops once a real cookie jar is involved. To test those, write one sentence per flow and run npx smolanalytics test --suite tests/ --url against a running URL. An agent drives a real browser, reads the page through its accessibility tree, and returns passed, failed, stale or errored, with one comment per pull request saying what broke, edited in place, posted from your own CI runner with the GITHUB_TOKEN GitHub Actions provides. A passing run is recorded and replays afterwards with no model call at all. If your Express service is a pure JSON API with no user interface, this is the wrong tool and supertest is the right one — the agent drives browsers only. The same walk also writes and maintains your tracking calls in the analytics you already use. 14-day trial at Pro limits, no card, then $19/month.
The Express failures that reach production are almost all about state between requests, which is the one thing an in-process request assertion cannot model. A session cookie missing Secure or SameSite behaves perfectly on localhost and is dropped by the browser once there is a proxy and TLS in front of it. trust proxy left unset gives every user the load balancer's address, so a rate limiter locks everybody out at once. A redirect chain that works when you follow it manually and loops when the browser carries a cookie you did not. Every one of those is green under supertest, because supertest is not a browser and does not keep a cookie jar across a redirect the way one does.
The second category is middleware order, which is invisible until it is catastrophic: an error handler registered before a route, a body parser after it, a CORS layer that answers the preflight and not the request. The route's own test still passes.
There is a boundary worth stating. If your Express service is a pure JSON API with no UI anywhere, a browser is the wrong instrument and supertest is the right one. This is for the app in front of it, and for the session and redirect behaviour that only exists in a real browser.
The instrumentation half is the same walk. Server-side events are the ones most often missing, because nobody wires analytics into a route handler, and the agent has just exercised those handlers through the UI. It writes and maintains the tracking calls in the SDK you already run: PostHog, Mixpanel, Amplitude, Google Analytics, Plausible or Segment.
How it works walks the whole loop from the sentence to the comment on the pull request, instrumentation covers the second half — the tracking calls the same walk writes and maintains — and the free tools run without an account. The docs have the flags, the suite format and the CI step.
Pro $19/mo, 100 tested pull requests included, unlimited projects, after a 14-day trial at Pro limits with no card. full pricing, including overage →
One sentence, on your Express app, tonight.
Point it at a URL that is already running and describe what should work. The first run uses the agent; once it passes it is recorded, so every run after that replays with no model at all — measured on our own site, 8.0s the first time and 1.4s the second.