# How Does Agentic Testing Actually Work?

> Agentic testing lets AI agents test your app. See how e2e keeps the agent on track with code checkpoints, has a separate judge decide pass or fail, mixes in deterministic locators, and replays cached steps without calling the model.

By Kacper Kapuściak. Published 2026-11-06. Canonical URL: https://e2e.com/blog/how-does-agentic-testing-actually-work

Manual testing is quite boring. There is this tiny spike of dopamine when you find a bug and the app crashes, but on a normal day, clicking around your app by hand takes a lot of time. And most of the time, it's not the most exciting thing in the world.

A long time ago, we humans had an idea: computers are really good at doing tedious stuff like clicking on sites. A computer is never tired, and it's never bored. So we started writing scripts, which evolved into the end-to-end testing frameworks we use every day. But computers have a problem that is both their strength and their flaw. They are fully deterministic. They need the exact values to match every time, and in the real world things change a lot. A computer doesn't "get it" that this is the same button it clicked a second ago and we just fixed a typo in the label.

Then AI happened. A model can read and reason that "Add to basket" is the same button that said "Add to cart" yesterday.

## What is AI testing?

In a nutshell, agentic testing means AI agents test your app.

That's it? Not really. If you just let an agent roam around your app, how do you know it tested what you wanted it to test? You could point [Codex's computer use](https://learn.chatgpt.com/docs/computer-use) at your app. It would click around, open a few pages, and stop. How would you know that it went through every flow that you care about? That's one of the reasons we built [e2e](https://e2e.com/).

## How to write agentic tests?

With e2e, you [define agentic tests with code](https://e2e.com/docs/core-concepts). Code acts as checkpoints for the agent, so it can't steer away from the predefined path that you've set.

```ts
import { test, expect } from "e2e";

test("checkout", async ({ app, agent, screen }) => {
  await app.open("/");

  await agent.act('add the "Classic T-Shirt" in size M to the cart');
  await expect(screen.getByRole("status", "Cart")).toHaveText("1 item");

  await agent.act("go to checkout");
  await agent.assert("the order summary lists one Classic T-Shirt, size M");
  await expect(screen.getByTestId("order-item")).toHaveCount(1);
});
```

If you've ever used Playwright, this should look familiar. The first line opens the app on the home page. No AI involved just yet.

Then we have `agent.act`. This is a [goal](https://e2e.com/docs/core-concepts#goals) for the agent, written the same way a user would describe it. Notice that there are no selectors! I didn't tell the agent where the size picker is or what the "Add to cart" button is called. It reads [a text snapshot of the page](https://e2e.com/docs/agent-steps#what-the-model-sees) built from the accessibility tree, can take [screenshots](https://e2e.com/docs/reference/agent#pixel-tools-screenshot-and-the-point-verbs) when the text isn't enough, and figures it out. On the screen, you can see it find the Classic T-Shirt, open the product page, pick size M, and add it to the cart. Pretty much what you'd do by clicking around by hand.

See that adding to the cart and checking out are two separate `act` calls, each being an outcome you can verify. When the test fails, the report names the goal that broke, and each goal gets its own recording in the cache (more on that later). You could write "add it to the cart and check out" in one call, but then you lose both.

Next is `agent.assert`. This is an [agentic assertion](https://e2e.com/docs/reference/agent#agent-assert), so the agent looks at the order summary and reasons about whether there really is one Classic T-Shirt in size M in it. This is the part that decides whether the test passes or fails, and a separate agent, the judge, makes that call. You can even [use a separate model, a smarter one, to judge](https://e2e.com/docs/models#a-judge-of-its-own) what a faster, smaller model has done. So there is an agent doing the actions, and there is a judge asserting what happened. The judge can [decide](https://e2e.com/docs/agent-steps#how-a-step-ends) that one of three things happened: passed, failed, or blocked. Inconclusive assertions also count as a failure. If the judge can't see the thing it's supposed to check, the test doesn't pass.

## Combining AI tests with deterministic assertions

The two `expect` lines are plain old [locator assertions](https://e2e.com/docs/reference/expect#locator-matchers) that don't need any AI to run. The last one finds every element with the `order-item` test id and checks there's exactly one of them.

You might ask why we bother if the judge already checked. Mixing agentic and deterministic steps is a tradeoff, and each one is good at different things.

Agentic steps need a model to run. Most of the time, that means a network call and every step waits for tokens to come back. You can run an AI model offline on your own machine instead, but on most hardware that's even slower.

Deterministic steps are the opposite. They need no network and no AI model to call, so they're fast. But they're exact. Rename a `testId` or reword a button and the test breaks, even though the app works fine.

The power of e2e lies in mixing the agentic with the deterministic APIs. Let the agent handle the parts of the UI that change often, like finding the right product and picking a size from whatever picker the team came up with this week. Then lock in the hard facts with a locator. You know there should be exactly one item in the cart, and a locator checks that in a few milliseconds without calling the model.

## AI test caching and self-healing tests

Running tests fully agentically for every step of every run on every pull request in your company would burn a lot of tokens. Luckily, e2e comes with a [replay cache](https://e2e.com/docs/cache). When an `agent.act` step finishes and a later check passes, like the locator right after it or the `agent.assert`, the runner [records what the agent did](https://e2e.com/docs/cache#when-a-recording-is-written). On the next run, it replays those exact actions without calling the model at all. A cached run is about as fast as a deterministic one, and the agent actions cost you close to nothing. Assertions are never cached. `agent.assert` runs live on every run, so the judge still looks at the real screen each time.

But what happens when the UI of your app changes? Let's say someone moves a button to a different spot. On the next run, e2e replays the recorded steps from the cache until it reaches a button that no longer exists.

The replay stops and the agent takes over from the current screen. We call this a [handoff](https://e2e.com/docs/self-healing). The agent knows which actions already ran and why the replay stopped, so it doesn't start the step again from the beginning. It finds the button, finishes the goal, and once a check passes again, the new path gets recorded. The next run replays all of it from cache and you don't have to touch the test at all.

## Getting started with agentic testing

To try it on your own app, follow the [quickstart](https://e2e.com/docs/quickstart) or run this in your project:

```bash
npx e2e init
```

It asks you a couple of questions and sets everything up, including an example test.

Add your provider's [API key](https://e2e.com/docs/models) or [log in with a subscription](https://e2e.com/docs/subscriptions), then run the example:

```bash
npx e2e run
```

From there, take one flow you test by hand every release, like signup or checkout, and write it as a set of `agent.act`s. Run it, see what the agent does, and then add an `agent.assert` and a locator or two for the facts that must hold.

## Wrapping up

So that's agentic testing with e2e. The agent handles the parts of your UI that change all the time. Your code acts as checkpoints so it doesn't wander off. A separate judge decides if the test passed. Locators check the hard facts in milliseconds. And the replay cache means you pay for the agentic actions once.

You still get that little dopamine spike when a test catches a bug. You just don't have to click around for an hour to find it!

These are just the basics, but there's a lot more in [the e2e documentation](https://e2e.com/docs). Giving a star on [GitHub](https://github.com/tester-army/e2e) would help more people find it.
