Skip to content

Get started

E2E for .NET drives an app with an agent, then checks the result with locators. Pick the platform your app runs on. Every page ends with a test you can run.

Platform Engine Packages Runs on
Web WebEngine (Chromium through Playwright) E2E, E2E.NUnit or E2E.XUnit.V3 Windows, macOS, Linux
Mobile MobileEngine (iOS simulator, Android emulator) E2E.Mobile.NUnit or E2E.Mobile.XUnit.V3 macOS for iOS, any host for Android
.NET MAUI MobileEngine, or DevFlowAgents for a Debug build E2E.Mobile.NUnit, E2E.Mobile.DevFlow macOS for iOS, any host with the Android SDK
Windows WinAppEngine (Windows UI Automation) E2E.WinApp.NUnit or E2E.WinApp.XUnit.V3 Windows 10 or 11

Every platform shares the same test API: App, Agent, Screen, and Expect.

await Agent.ActAsync("sign in as {user}", new ActOptions { Params = new Dictionary<string, object?> { ["user"] = "ada" } });
await Expect.That(Screen.GetByTestId("greeting")).ToHaveTextAsync("Hello, ada!");

ActAsync takes one goal and lets the agent work out the steps. Expect checks an exact value with no model call. A verified ActAsync is recorded, and the next run replays it with no model call until the screen no longer matches.

  1. Install the .NET 10 SDK.

  2. Sign in to a model. For a GitHub Copilot plan:

    Terminal window
    dotnet tool install --global E2E.Cli
    e2e login github-copilot

    For an API key, set provider and model under agents.default in e2e.config.json, and export the key the provider reads, for example OPENAI_API_KEY. See the guide for ChatGPT, OpenCode Console, and SuperGrok.

  3. Tests that never call the agent need no model, so you can start with locators only. A model request that fails on the network or with a 408, 409, 429, or 5xx answer is sent again up to 5 times before the step fails with MODEL_PROVIDER_FAILED. A SigV4-signed Bedrock request (AWS credentials, not a Bedrock API key) is signed again for every attempt, so a long wait does not end in RequestExpired.

Each test project has an e2e.config.json next to its .csproj. It names the app under test (targets), the agent, and the replay cache:

{
"targets": [{ "name": "web", "platform": "web", "app": { "url": "http://localhost:3000" } }],
"actionTimeout": 15000,
"assertionTimeout": 10000,
"agents": { "default": { "provider": "copilot", "model": "claude-sonnet-5.5" } },
"cache": { "dir": ".e2e/cache" }
}

A web target takes app.url. An ios or android target takes app.bundleId and app.appPath. A windows target takes app.appPath and app.bundleId. The context string under agents.default tells the agent what the app is, for example that the data is shared and must not be edited.