Appium, Android and MAUI

Prerequisites

You’ll need Appium server (I’m using Appium Server UI), I installed into my Windows c:\tools\Appium folder and next (whilst not a requirement but is very useful) grab the latest version of Appium Inspector this will allows us to inspect elements within our running Android application, I unzipped this to c:\tools\AppiumInspector.

Appium Server GUI has a button to run the inspector but, unless I’m missing something, this simply sends you to the GitHub repo for the inspector, so run the inspector yourself separately.

Creating a simple app.

Create yourself a MAUI application (mine’s call MauiUIAutomationTest, so you’re see this listed in various places below, if you create your own name, remember to update in the code as well).

Like my previous Appium test samples the code is simple (I’ll recreate here). The MainPage.xaml within the ContentPage looks like this

<Grid>
   <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
   </Grid.RowDefinitions>

   <Entry Grid.Row="0" AutomationId="input" Margin="10" Text="{Binding Input}" />
   <Button Grid.Row="1" AutomationId="copy" Margin="10" Command="{Binding ProcessCommand}" Text="Copy" />
   <Label Grid.Row="2" AutomationId="output" Margin="10" Text="{Binding Output}"/>
</Grid>

I’m using MVVM Community Toolkit and so MainPageViewModel.cs is simply this

public partial class MainPageViewModel : ObservableObject
{
    [ObservableProperty] private string input;
    [ObservableProperty] private string output;

    [RelayCommand]
    private void Process()
    {
       Output = Input;
    }
}

Creating our test code

I’ve created an NUnit test class library and added the NuGet package Appium.WebDriver (yes I know it’s an app. but that’s the NuGet package we need). If you’re creating your unit test class library from scratch you’ll need NUnit and NUnit3TestAdapter installed as dependencies as well).

Now my first unit test is, as follows

public class Tests
{
    private AndroidDriver<AndroidElement> _driver;

    [SetUp]
    public void Setup()
    {
        var driverOptions = new AppiumOptions();
        driverOptions.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Android");
        driverOptions.AddAdditionalCapability(MobileCapabilityType.AutomationName, "UiAutomator2"); 
        driverOptions.AddAdditionalCapability(MobileCapabilityType.DeviceName, "Pixel_3_XL_API_29");

        _driver = new AndroidDriver<AndroidElement>(new Uri("http://localhost:4723/wd/hub"), driverOptions); 
        _driver.ActivateApp("com.companyname.mauiuiautomationtest");
    }

    [TearDown]
    public void TearDown()
    {
        _driver.Quit();
    }

    [Test]
    public void ChangeInput_ThenCopy_ExpectMatchingOutput()
    {
        var entry = _driver.FindElementById("com.companyname.mauiuiautomationtest:id/input666");
        entry.Clear();
        entry.SendKeys("Hello World");
        var button = _driver.FindElementById("com.companyname.mauiuiautomationtest:id/copy666");
        button.Click();
        var label = _driver.FindElementById("com.companyname.mauiuiautomationtest:id/output666");
        Assert.That(label.Text, Is.EqualTo("Hello World"));
    }
}

Obviously this is not perfect as we’re running the setup and tear down code after every test, but as I only have one test, I don’t care (it’s for the reader to do this correctly). Now we setup the driver options, the platformName is ofcourse Android, the deviceName relates to the device you’re using, I’m using the Android emulator for the Pixel 3 API 29, finally automationName specifies the automation engine to use, to be honest you could remove this and it’ll default the standard Appium engine but UiAutomator2 is listed as Appiums flagship engine, so let’s use that.

I had all sorts of issues trying to get Appium to start my MAUI app (as it will try to install it), however I think this is likely down to the way Visual Studio builds the apk, i.e. I probably need to publish a signed apk or the likes, but for now I’ll let Visual Studio deploy the app and then access it via Appium. Hence we have the following code to active an already installed app.

 
_driver.ActivateApp("com.companyname.mauiuiautomationtest");

Eager to see something working?

If you’re eager to see something working, then

  • Deploy your application to your Android emulator (I just get Visual Studio to deploy it)
  • Run the Appium Server GUI and start a new session
  • Run your unit test

If all went well the test was green and if not, check your application name etc.

Appium Inspector

The Appium server does not come with an inspector now, you need to download it separately (as stated earlier). Ofcourse we can probably get a lot done without an inspector, but it helps and gives confidence that if it see’s our id’s etc. then Appium will. You’ll need to tell the inspector to connect to the Appium server – make sure that Remote Path has the URL /wd/hub and you have valid the following Desired Capabilities

{
  "appium:automationName": "UIAutomator2",
  "appium:deviceName": "Pixel_3_XL_API_29",
  "platformName": "Android"
}

Ensure your have Appium server is running. Before you run the inspector just make sure your app. is running (just makes things simpler) and now start a session from your Appium Inspector. It should show you the screen of the current running application.

As you can see from the code below, we expect a “copy” automation id

<Button Grid.Row="1" AutomationId="copy" Margin="10" Command="{Binding ProcessCommand}" Text="Copy" />

MAUI AutomationId’s do not appear as AutomationId or Accessibility Id for that matter, but instead they become id’s but prefixed with you app name, i.e. that’s why our unit tests has com.companyname.mauiuiautomationtest:id/output. All that really matters is that we have a unique value on an Appium accessible property to do some UI Automation testing. We do have the option of XPath locators, but these should probably be used as a the last resort, if we do not have anything else to locate against.