the whole setup · one sentence per flow · no test code

End-to-end tests for Astro.

Astro ships static HTML with islands of JavaScript, so the page looks completely finished several hundred milliseconds before the one button on it does anything. Write a sentence describing what should work and an agent waits for the control to be real before it clicks.

the whole setup
$ npx smolanalytics test \
    --url https://your-site.pages.dev \
    --test "the newsletter form on the homepage accepts an email and confirms it"

No account, no config file, nothing written to your repo. It prints a verdict and exits non-zero if the app did not do what the sentence describes.

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

To test an Astro site end to end without writing test code, run npx smolanalytics test --url https://your-site --test with one sentence describing what should work. An agent opens a real browser, waits for the island carrying the control to actually be interactive, does the thing, and returns passed or failed. That waiting is the whole point on Astro: with client:visible or client:idle the markup exists long before the JavaScript that makes it do anything, so any check that reads the HTML says the button is there while a real visitor clicks it and nothing happens. On a pull request one comment says what broke, edited in place. A passing run is recorded and every run after it replays with no model call at all — measured on our own site, 8.0 seconds for the agent and 1.4 seconds for the replay — and the agent comes back only when the recording stops fitting the page, which is reported as stale rather than as a failure because a rename and a removal look the same to a replay. Setup is a URL you already have: a Netlify or Cloudflare Pages deploy preview, a staging build, or localhost through a tunnel. Nothing is written to your repo. The same walk also maintains your tracking calls in the analytics you already use. 14-day trial at Pro limits, no card, then $19/month.

The bug this catches on Astro sites is almost always the same one, and it is invisible to every check that reads HTML. A client:visible or client:idle island renders its markup at build time and becomes interactive whenever the browser gets round to it, so the button is on the page and does nothing. A crawler sees a button. A snapshot test sees a button. A person clicks it, nothing happens, and they leave. The agent drives a real browser, so it waits for the control to be actionable and then reports what happened after the click — which is the only way to tell a rendered button from a working one.

The second Astro-shaped failure is the directive itself: change client:load to client:visible on a component that is above the fold on desktop and below it on a phone, and the flow works for you and breaks for a third of your traffic. A test that says "submit the form on the homepage" runs the same either way and only goes red on the version that is actually broken.

Then the tracking. Astro pages are mostly static, so the events worth having are the few real interactions, and they live inside the islands. The same agent that just used the form knows the form exists, so it writes and maintains those tracking calls inside the SDK you already run — PostHog, Mixpanel, Amplitude, Google Analytics, Plausible or Segment — in the island component rather than in a global script that fires on a page nobody interacted with. If you have no analytics at all, the same engine can be it: autocapture, funnels, retention and paths are included.

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 Astro 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.

questions

Most of my site is static content. Is there anything to test?
The few places a visitor can do something, and those are the ones worth a sentence each: the newsletter form, the search box, the pricing toggle, the buy button. Static pages are the part of an Astro site least likely to break and easiest to notice when they do. The islands are the opposite — they break silently, because the page around them still renders perfectly. Three sentences covering your three interactive components is a proportionate suite for most Astro sites.
Will it get confused by content collections and dynamic routes?
It never enumerates your routes, so it cannot. You give it a URL and a sentence, and it navigates the way a person would, by reading what is on the page and clicking. If the test says "open the blog, click the first post, and confirm the author's name is shown", it works on a site with four posts and on the same site next month with four hundred, without a fixture or a list of slugs to keep in step.
What do I actually get back after a run on Astro?
One of four words, and the difference between them is the product. Passed. Failed, which means your app did not do what the test describes, so it is a bug report. Stale, which means a recording no longer fits the page — a rename and a removal look identical to a replay, so this is never worded or coloured as a failure and the agent goes and works out which it was. Errored, which means our runner could not run at all: no browser, no network, no key. That one is our fault and it says so, because telling you your checkout is broken when our own runner fell over is the fastest way to lose you.

keep reading