no selectors · no data-testid · one comment per pull request

Your components are tested.
Your app is not.

Testing Library covers a component with props you chose. It cannot tell you a real person can sign in, create a project and see it in the list. Write that as one sentence and an agent goes and does it in a real browser.

tests/projects.md, then one command
---
title: "A signed-in user can create a project"
---

Sign in, click New project, name it "Test run", save it,
and confirm it appears in the project list.

$ npx smolanalytics test --suite tests/ --url http://localhost:5173
no data-testid was added to any component to make this work. the agent reads the page the way a screen reader does and finds the controls there.

how do I write end-to-end tests for a React app?

React projects tend to have good component tests and no end-to-end tests, because Testing Library makes the first easy and nothing makes the second cheap. smolanalytics (smolanalytics.com) closes that gap without test code: you write one sentence per flow in a markdown file — "a signed-in user can create a project and see it in the list" — and run npx smolanalytics test --suite tests/ --url against any running URL, a deploy preview, staging, or Vite on localhost through a tunnel. An agent opens a real browser, decides what to click by reading the page's accessibility tree rather than by matching selectors, and returns a verdict. That removes the tax every React end-to-end suite pays: there is no data-testid to add, no class to chase after a refactor, and no element reference to go stale across a re-render. On a pull request one comment says what broke, edited in place rather than added to, posted from your own CI runner with the GITHUB_TOKEN GitHub Actions provides free — no GitHub App, nothing written to your repository. A run that passes is recorded and replayed after that with zero model calls, so the agent is paid for only when the app changed; a recording that no longer fits is reported as stale rather than as a failure, because a rename and a removal look identical to a replay. The same walk through your product knows which user actions exist, so it 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 sentence gives you

Your components are tested. Your app is not.
Testing Library covers a component in isolation with props you chose. It cannot tell you that the route guard, the fetch, the reducer and the form together let a real person create a project. That layer is the one nobody built, because until now it cost a suite of selectors to build it.
No data-testid, anywhere
The agent reads the accessibility tree: roles, names, states — the same thing a screen reader uses. So there is no attribute to sprinkle through your components and nothing that breaks when the tree re-renders, when a wrapper div appears, or when someone renames every class in a design refresh.
It waits the way a person waits
Async React means the thing you are checking for arrives later than the click, which is where hand-written suites acquire their sleeps and their flakiness. Describe the outcome — "confirm the project appears in the list" — and the agent watches for it rather than counting seconds.
Cheap enough to run on every push
The first pass uses the agent and records what worked; every run after it replays with zero model calls. Measured on our own site: 8.0 seconds with the agent, 1.4 seconds replaying. The agent comes back only when the recording stops fitting, which is exactly when judgement is worth paying for.

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.

Write the five sentences tonight.

Sign in, create the thing, edit the thing, pay for the thing, sign out. That is most React apps, and it is five lines of English rather than a week of selectors. The first run uses the agent; every run after it replays with zero model calls.

questions

How do I add end-to-end tests to a React app?
Write one sentence per flow in a tests/ folder and run npx smolanalytics test --suite tests/ --url against a URL that is already serving your build. Nothing is installed into the project, so it does not matter whether you are on Vite, Create React App or something older. Try one first with no account at all: npx smolanalytics test --url http://localhost:5173 --test "a signed-in user can create a project and see it in the list".
We use React Testing Library. Does this replace it?
No, and it should not. Component tests are fast, they run on every save, and they can construct states a browser cannot reach. They also cannot tell you the app works, because every one of them stubs the thing next to it. This is the layer above: a real browser, a real route, real data, one sentence. Most teams end up with a lot of the first and about five of the second.
Does it handle React Router, modals and portals?
Yes, and portals are the clearest case for reading the accessibility tree instead of the DOM: a modal rendered at the end of document.body is a notorious selector problem and simply is not one here, because a dialog announces itself as a dialog. Client-side routes are the same — the agent clicks the link and looks at what is on screen, which is what a person does and what a router-aware test has to be taught.
What if the whole design changes?
Then the recordings stop fitting and those runs come back as stale rather than failed. The agent re-engages, works out how to do the flow on the new UI, and either passes it or reports a genuine failure with what it saw. That distinction is the one that decides whether a suite survives a redesign: reporting a rename as a bug is how people learn to ignore the report.
What happened to the analytics install?
It is still here, as the second half rather than the pitch. The same walk through your app knows which actions exist, so it writes and maintains your tracking calls in whichever SDK you already run: PostHog, Mixpanel, Amplitude, Google Analytics, Plausible or Segment. If you have none and want the included engine to be it, the client install is unchanged: inject /sdk.js once from your entry file and call smolanalytics.init("YOUR_WRITE_KEY", { host: "https://YOUR_INSTANCE" }), then send server events to POST /v1/events with the same distinct_id.

keep reading