.NET MAUI
A .NET MAUI app runs on iOS and Android, so MobileEngine drives it like any other mobile app. A Debug build can also be driven through the MAUI DevFlow agent, which needs no Node and sees the MAUI visual tree.
1. Give controls an AutomationId
Section titled “1. Give controls an AutomationId”GetByTestId finds a control by its AutomationId. Set one on every control a test touches. Use SemanticProperties.Description for the accessible name.
<Entry AutomationId="name" Placeholder="Ada Lovelace" SemanticProperties.Description="Name" /><Button AutomationId="greet" Text="Greet" Clicked="OnGreetClicked" /><Label AutomationId="greeting" />2. Build the app
Section titled “2. Build the app”dotnet workload install mauidotnet build MyApp -f net10.0-ios -r iossimulator-arm64 # iOS simulatordotnet build MyApp -f net10.0-android -t:SignAndroidPackage # AndroidThe iOS build writes MyApp.app under bin/Debug/net10.0-ios/iossimulator-arm64/. Build and install again after every app change: the tests do not build the app.
3. Create the test project
Section titled “3. Create the test project”Keep it a plain net10.0 project, so it builds on a machine without the MAUI workload.
dotnet new nunit -n MyApp.E2ETestscd MyApp.E2ETestsdotnet add package E2E.Mobile.NUnit{ "targets": [ { "name": "myapp", "platform": "ios", "app": { "bundleId": "com.example.myapp", "appPath": "../MyApp/bin/Debug/net10.0-ios/iossimulator-arm64/MyApp.app" } } ], "agents": { "default": { "provider": "copilot", "model": "claude-sonnet-5.5", "context": "MyApp is a MAUI app with a greeting form." } }, "cache": { "dir": ".e2e/cache" }}using E2E.Mobile.NUnit;
public sealed class GreetingTests : MobileAppTest{ [Test] public async Task The_agent_gets_a_greeting() { await Agent.ActAsync("get the app to greet {name}", new ActOptions { Params = new Dictionary<string, object?> { ["name"] = "Grace" }, });
await Expect.That(Screen.GetByTestId("greeting")).ToHaveTextAsync("Hello, Grace!"); }}4. Run
Section titled “4. Run”xcrun simctl boot "iPhone 17"dotnet test --project .For Android, boot an emulator and set E2E_MOBILE_PLATFORM=android and E2E_MOBILE_APP_PATH to the .apk.
Drive the app through DevFlow (preview)
Section titled “Drive the app through DevFlow (preview)”Add Microsoft.Maui.DevFlow.Agent to the app and register it in Debug builds:
#if DEBUGbuilder.AddMauiDevFlowAgent();#endifLaunch the app, then run the tests against it:
dotnet build MyApp -f net10.0-ios -r iossimulator-arm64 -t:RunE2E_MOBILE_PROVIDER=devflow E2E_DEVFLOW_APP=MyApp dotnet test --project .The tests attach to the running app. Nothing is installed and the app is not relaunched between tests, so each test starts from the state the last one left. Tests that send the app to the background or relaunch it are inconclusive in this mode. Use AttachesToRunningApp in Assume.That to skip them. This mode is a preview and has not been run against a device yet.