tests/first-click.md · one sentence per flow · no test code

End-to-end tests for Qwik.

Qwik skips hydration by fetching the handler for a control the moment you touch it. That is the whole trick, and it means the first click on any control is a network request that can fail. Describe the flow in a sentence and an agent performs the real click.

tests/first-click.md
---
title: "The pricing toggle switches to annual"
---

Open /pricing, click the annual toggle, and confirm the
headline price changes and the yearly saving is shown.

One sentence, and the criticality if you want it. There is no page object, no fixture and no selector anywhere in the suite.

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

To test a Qwik app end to end without writing test code, describe each flow in one sentence and run npx smolanalytics test --url against a running URL — a deploy preview, staging, or localhost through a tunnel. An agent drives a real browser and works out what to click by reading the accessibility tree. On Qwik that real click matters more than usual: resumability fetches a control's handler at the moment of interaction, so a broken chunk path gives you a page that renders perfectly and a button that does nothing the first time it is pressed. Nothing that inspects HTML catches that. The verdict comes back as passed, failed, stale or errored, and on a pull request one comment says what broke, edited in place rather than added to. It runs on your own CI runner and comments with the GITHUB_TOKEN GitHub Actions provides, so there is no GitHub App required and nothing is written to your repo. A run that passes is recorded and replays afterwards with no model call at all; the agent comes back only when the recording stops fitting the app, which is reported as stale rather than as a failure. 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.

Resumability moves work out of page load and into the first interaction, which is a genuinely better trade and a new place for things to go wrong. The handler for a button lives in a separate chunk that is fetched when the button is touched, so a misconfigured base URL, a CDN path that is right in production and wrong on a preview, or a chunk that failed to upload gives you a page that renders perfectly and a button that does nothing on the first press. Everything that reads HTML says the page is fine. Only something that actually clicks finds out.

The second Qwik-specific case is state that was serialised into the HTML and cannot be resumed — a closure capturing something unserialisable, which throws at click time rather than at build time. Again the page is fine until someone uses it. A sentence like "click the annual toggle and confirm the headline price changes" is a check on exactly that, and it does not care how the chunk was named.

The instrumentation half uses the same walk through the app. Because the agent has just performed the interactions, it knows which ones exist, so it writes and maintains your tracking calls inside the SDK you already run — PostHog, Mixpanel, Amplitude, Google Analytics, Plausible or Segment — in the $ handler where the action happens rather than in a page-level effect that fires whether or not anyone did anything.

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 Qwik 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

Is a headless browser fair to a framework built around real interaction?
It is the only fair test of one. The agent uses a real browser engine and performs real clicks and real typing, so a handler chunk is fetched exactly as it would be for a visitor. What it deliberately does not do is guess at pixel coordinates: it picks an element from the accessibility tree, which is how it avoids clicking the wrong thing and then blaming the wrong feature.
What happens the first time a test fails on a rename?
It comes back as stale, not as a failure, and that distinction is deliberate. A replay cannot tell a renamed control from a removed one, and reporting a copy change as a bug at two in the morning is how a suite gets muted. Stale means the recording no longer fits and the agent is going back to work out which it was. Only the agent's verdict can be a failure, and a failure means the app did not do what the sentence describes.
What do I actually get back after a run on Qwik?
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