Documentation
Agentic end-to-end tests for .NET. Describe a goal in plain language, let an agent drive the app in Chromium, then check the result with locators. A verified agent step is recorded and replays on the next run with no model call.
dotnet add package E2Edotnet add package E2E.NUnit # or E2E.XUnit.V3 for xUnit v3Start here
Section titled “Start here”Test filters (ITestFilter, TestFilterContext, and TestFilterResult) leave out the tests a change cannot affect. The seam, the change detection (INVALID_CHANGED_SINCE), and the run.changes and run.filters report fields are ported; no dotnet test host calls a filter yet.
Filtering a locator
Section titled “Filtering a locator”Locator.Filter keeps or drops the matches of a locator by their subtree. It takes any of four named arguments, and at least one.
var row = Screen.GetByRole("listitem").Filter(hasText: "Invoice 42", hasNotText: "Paid");await row.GetByRole("button", "Void").TapAsync();hasTextwith a string is a case-insensitive substring match over the match and its descendants, unlike a query text, which matches exactly. Pass aRegexfor anything stricter.hasNotTextexcludes matches with that subtree text, using the same substring orRegexrules.haskeeps a match whose subtree resolves the inner locator.hasNotdrops a match whose subtree resolves the inner locator. It follows the same scoping rules ashas.
Filter() with none of the four throws INVALID_LOCATOR, and so does a has or hasNot locator made by another screen. Filter("text") and Filter(locator) remain as the one-argument forms of hasText and has. On iOS, a plain React Native View has no children in the tree, so has on it matches nothing and hasNot keeps every such row.
Scrolling to a node
Section titled “Scrolling to a node”Screen.ScrollUntilVisibleAsync(target, options) scrolls the viewport until target resolves visibly. Locator.ScrollUntilVisibleAsync(target, options) swipes that node instead, so a feed or table that is its own scroll container pages without the pointer hovering it first.
await Screen.ScrollUntilVisibleAsync(Screen.GetByRole("button", "Accept"));await Screen.GetByTestId("feed").ScrollUntilVisibleAsync(row, new ScrollUntilVisibleOptions { Momentum = Momentum.Fast });| Option | Type | Default |
|---|---|---|
Direction |
ScrollDirection |
Down |
Momentum |
Momentum (None, Slow, Fast) |
Slow |
Timeout |
TimeSpan |
30 seconds |
Timeout is its own default, not actionTimeout, and bounds the whole scroll, each swipe included. LOCATOR_NOT_FOUND means the deadline expired first, a swipe it cut short included. INVALID_LOCATOR means target was made by another target’s screen.
Errors
Section titled “Errors”A read or navigation that times out fails with OPERATION_TIMEOUT. It is not retried, even when the call log mentions a detached element or a navigation race. On a device, an input (a tap, key, swipe, or Back) that the device does not answer within actionTimeout fails with ACTION_MAY_HAVE_COMMITTED and is never repeated, because it may have landed; an input the timeout ran out before is not sent (OPERATION_TIMEOUT), and a long press that holds at least as long as the time left is refused (NOT_ACTIONABLE). See EngineErrorCodes in the API reference.