End-to-end tests for SvelteKit.
The best thing about SvelteKit is the hardest thing to test: a form action is supposed to work with JavaScript and without it, and it is the without-it path nobody checks. Write one sentence describing the flow and an agent submits the real form in a real browser on every pull request.
--- title: "A logged-out visitor can sign up" --- Open /signup, fill in an email and a password, submit the form, and confirm the dashboard greeting appears. $ npx smolanalytics test --suite tests/ --url "$PREVIEW_URL"
That is the whole test. No selector for the submit button: the agent reads the page the way a screen reader does and finds it there.
how do I write end-to-end tests for a SvelteKit app?
To get end-to-end tests on a SvelteKit app without writing test code, put one sentence per flow in a markdown file and run npx smolanalytics test --suite tests/ --url against a URL that is already running: your Vercel or Netlify preview, a staging box, or localhost through a tunnel. An agent opens a real browser, reads the page through its accessibility tree rather than by matching selectors (which matters in Svelte, where class names are compiled and hashed), works out what to click, and returns a verdict. On a pull request it leaves one comment saying what broke, edited in place rather than added to. The first run uses the agent; a run that passes is recorded and replayed after that with no model call at all, so the suite costs almost nothing to keep running, and the agent only wakes up when the recording stops fitting the app. A recording that no longer fits is reported as stale, never as a failure, because a renamed button and a deleted button look identical to a replay. Nothing is written to your repo and no GitHub App is required. The same walk also writes and maintains your tracking calls in PostHog, Mixpanel, Amplitude, Google Analytics, Plausible or Segment. 14-day trial at Pro limits, no card, then $19/month.
Two SvelteKit-shaped things break quietly and neither shows up in a unit test. The first is the enhanced form: use:enhance intercepts the submit and the action returns a fail() with your errors in it, and when the shape of that return drifts the page just sits there, still rendered, still 200, doing nothing. The second is the boundary between a load function on the server and the same load re-running on the client after a soft navigation — the page you get by typing the URL is fine, and the page you get by clicking a link is missing its data. An agent that actually clicks the link and then looks at what is on screen catches both, because it is checking what a person would see rather than what the server returned.
It reads the page through the accessibility tree rather than by matching selectors, which matters more in Svelte than most places: class names are compiled and hashed, so a selector written against a component today is a different string after the next build. Nothing in the test refers to the markup, so nothing in the test breaks when the markup does.
The second half is your tracking, and it uses the same walk. An agent that has just worked out how to sign up knows the app has a signup, so it writes and maintains the tracking calls for it inside the SDK you already use — PostHog, Mixpanel, Amplitude, Google Analytics, Plausible or Segment — in the +page.svelte or the form action where the event actually happens. When an event in your tracking plan stops arriving but the traffic behind it doesn't, smolanalytics finds the commit that deleted the track() call and opens a pull request putting it back. If you have no analytics at all, the same engine can be it.
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 SvelteKit 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.