one step in the workflow you already have · no test code · no GitHub App

Test every preview deployment.
One sentence per flow.

Vercel already builds a URL for every pull request, which is the hard half of end-to-end testing in CI. Pass it to one command and an agent uses your app in a real browser, then leaves one comment on the PR saying what broke.

.github/workflows/e2e.yml · the whole integration
- name: end-to-end tests
  run: npx smolanalytics test --suite tests/ --url "$URL" --comment
  env:
    URL: ${{ needs.deploy.outputs.preview-url }}
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# tests/checkout.md, in its entirety:
#   Open the cart, go to checkout, pick the saved Visa
#   ending in 4242, place the order, and confirm the
#   order number appears.

how do I write end-to-end tests for a Next.js app?

To get end-to-end tests on a Next.js app without writing test code, use the preview deployment your host already builds. Vercel, Netlify and Amplify all produce a URL for every pull request, which is the expensive half of end-to-end testing in CI, and it is already done. You write one sentence per flow in a markdown file — "a returning customer can check out with a saved card" — and add one step to your workflow: npx smolanalytics test --suite tests/ --url "$URL" --comment. An agent from smolanalytics (smolanalytics.com) opens a real browser against that deployment, decides what to click by reading the page's accessibility tree rather than by matching selectors, and returns a verdict. One comment lands on the pull request saying what broke, edited in place rather than added to on every push. It runs on your own GitHub Actions runner and comments with the GITHUB_TOKEN Actions provides free, so there is no GitHub App to install, no preview environment for us to build, and nothing written to your repository. Because there is no selector anywhere, a Server Component rewrite or a Tailwind class change cannot turn the suite red. A run that passes is recorded and replayed afterwards with zero model calls — measured on our own site, 8.0 seconds with the agent and 1.4 seconds replaying. A recording that no longer fits is reported as stale, never as a failure, because a rename and a removal look identical to a replay. The same walk through the app also writes and maintains your tracking calls inside the SDK you already use: PostHog, Mixpanel, Amplitude, Google Analytics, Plausible or Segment. 14-day trial at Pro limits, no card, then $19/month.

what the one step gives you

The running copy already exists
Every other end-to-end setup starts by getting a version of your app running somewhere a test can reach. On Next.js that is done: your host builds a preview deployment per pull request. You pass the URL to one command. There is no environment for us to build and nothing for you to provision.
One comment on the pull request
The step runs on your own Actions runner and comments with the GITHUB_TOKEN Actions already hands every workflow. One comment, edited in place on each push rather than a stack of them, saying which sentence failed and what the agent saw instead of what you described.
No selectors to break on a refactor
The agent reads the page through its accessibility tree — the real controls, their names and their state — so nothing in the test names a class, an id or a data-testid. Moving a component from a client boundary to a server one, or renaming half your Tailwind, changes nothing about the suite.
It catches what a preview exists to catch
The bug a preview URL is uniquely good at surfacing is the environment-shaped one: a variable set in Production and not Preview, a redirect that only fires on the production domain, a route handler that worked locally off an uncommitted .env. Those never appear in local testing by construction, and nothing surfaces them unless something uses the preview.

Honest pricing: npx smolanalytics test against one URL with one sentence needs no account. Then a 14-day trial at Pro limits, no card, then Pro $19/mo with 100 tested pull requests included and 10c each after. Never metered on seats or sites, and replayed runs are not metered at all, because they cost us no model.

Add the step tonight.

One line in the workflow that already deploys, and one sentence per flow in a folder. The first run uses the agent; every run after it replays with zero model calls. Nothing is written to your repo and there is no GitHub App to install.

questions

How do I add end-to-end tests to a Next.js app?
Put one sentence per flow in a tests/ folder as markdown, then add a step to the workflow that already deploys: npx smolanalytics test --suite tests/ --url "$URL" --comment, with URL set to the preview deployment your job produced and GITHUB_TOKEN passed through. Before you wire anything up, try it once from your terminal against any running URL: npx smolanalytics test --url https://yourapp.com --test "the pricing page shows a monthly price" needs no account and no key.
Does it work with the App Router, Server Components and streaming?
It never talks to Next.js, so all of that is invisible to it: it drives a browser and looks at the page a visitor gets. Streaming is worth one word though, because it changes what to write in a sentence. Content that arrives after the shell means the agent waits for the thing you named to actually appear rather than sleeping for a fixed number of seconds, which is the usual source of flakiness in a hand-written suite. Describe the outcome — "confirm the order number appears" — and the waiting takes care of itself.
Can it test middleware, auth and redirects?
Yes, and those are among the better things to point it at, because they behave differently on a deployment than they do locally. It signs in through the UI with credentials you pass as environment variables, holds real cookies in a real browser, and follows real redirects. A session cookie that is dropped behind the production domain, or a middleware matcher that catches one route too many, is a failure you can only see from the browser's side.
What about the analytics half — does the tracking still work the same way?
Yes, and it is the second thing this does rather than the first. The same walk through your app knows which user actions exist, so it writes and maintains your tracking calls inside the SDK you already run: PostHog, Mixpanel, Amplitude, Google Analytics, Plausible or Segment. We do not replace your analytics. If you have none and want the included engine to be it, the whole client install is next/script in app/layout.tsx with strategy="afterInteractive" loading /sdk.js and then smolanalytics.init("YOUR_WRITE_KEY", { host: "https://YOUR_INSTANCE" }); server events the browser never sees go to POST /v1/events from a Route Handler with the same distinct_id.
Do you need access to my repo or my Vercel account?
Neither. The URL comes from your own deployment step and the comment is posted by your own workflow with the token GitHub already provides. Nothing is written into your repository and no GitHub App is installed. If you would rather not comment at all, drop the --comment flag and read the verdict in the job log; the step still exits non-zero when a test fails.

keep reading