Skip to content

UITests

Javier Suárez edited this page Oct 31, 2024 · 46 revisions

Prerequisites

To run the tests on iOS or Catalyst, you'll need a Mac. To run the tests on Windows, you'll need a Windows machine. Android tests can be run from either platform.

Structure

├──  Controls
│    ├── tests
│    ├── ├── Controls.TestCases.App
│    │   ├── Controls.TestCases.Shared.Tests
  • Controls.TestCases.App: .NET MAUI Sample used for the automated UI tests
  • Controls.TestCases.Shared.Tests: .NET MAUI library used to define the UI tests

Each platform has a specific UI tests library project where it is possible to add specific tests per platform.

├──  Controls
│    ├── tests
│    │   ├── Controls.TestCases.Android.Tests
│    │   ├── Controls.TestCases.iOS.Tests
│    │   ├── Controls.TestCases.Mac.Tests
│    │   ├── Controls.TestCases.WinUI.Tests

Writing Tests

https://github.com/dotnet/maui/blob/main/docs/design/UITesting.md

Running Tests

Windows prerequisites

  • make sure a dotnet tool restore on the repo home
  • Make sure Developer Mode is turned on in Windows Settings
  • Install LTS version of nodejs https://nodejs.org
  • Install Windows App Driver from https://github.com/microsoft/WinAppDriver/releases/tag/v1.2.1
  • Validate you have on your path %USERPROFILE%\AppData\Roaming\npm
    • Note: you may need to restart your machine for this to take effect
  • dotnet pwsh .\eng\scripts\appium-install.ps1
    • Ignore "apkanalyzer.bat could NOT be found" error from appium-doctor

Mac prerequisites

  • make sure to run dotnet tool restore on the repo home

Option 1

Option 2 (HomeBrew)

Android prerequisites

  • You will need to setup the ANDROID_HOME and JAVA_HOME environment variables so that Appium and android.cake can find them.

  • Ensure that you have the Android API 30 SDK installed, with the emulator image for Play store on x86/x64. By default, the tests use that. See screenshot below. If you want to use another image you can specify the --device argument, with something like --device="android-emulator-64_33" where the 64 means image x86_x64 and 33 indicates the API level.

image

Running from an IDE

Launch the host app

Build and run the host app. For Android & iOS, the proper emulator/simulator image is launched.

Android:

./build.ps1 -Script eng/devices/android.cake --target=uitest-build
./build.ps1 -Script eng/devices/android.cake --target=uitest-prepare

iOS:

./build.ps1 -Script eng/devices/ios.cake --target=uitest-build
./build.ps1 -Script eng/devices/ios.cake --target=uitest-prepare

Windows: Launch Controls.TestCases.HostApp from the IDE

Catalyst: Launch Controls.TestCases.HostApp from the IDE

Running from Visual Studio

  • Build the Controls.AppiumTests.csproj so the tests show up on the Test Explorer
  • Run the tests

Running from Visual Studio Code (requires C# Dev Kit with .NET MAUI Extension installed)

  • If you don't have your development environment already setup, please consult the development guide.
  • For Windows & Catalyst, you'll want to deploy the host app first. Go to the Run and Debug window and select the correct project:
C# Controls TestCases HostApp

However, this will just load the test in the app. To have Appium drive the test, you’ll need to run them in the Testing pane in VS Code. Before that, make sure to build the project where your test is located:

  1. Ensure that you are in Explorer.
  2. Expand the Solution Explorer
  3. Find the project that your test is located in.
  4. Right click and select build.
Pasted Graphic 2

Now if you click on the Testing icon, you will see the test that you were working on. Click the play icon to launch your test:

• GestureRecognizerUlTests(Android)

Running from the command line (you can replace ./build.ps1 by dotnet cake)

Android

./build.ps1 -Script eng/devices/android.cake --target=uitest-build
./build.ps1 -Script eng/devices/android.cake --target=uitest

iOS

./build.ps1 -Script eng/devices/ios.cake --target=uitest-build
./build.ps1 -Script eng/devices/ios.cake --target=uitest

Windows

./build.ps1 -Script eng/devices/windows.cake --target=uitest-build
./build.ps1 -Script eng/devices/windows.cake --target=uitest

Catalyst

./build.ps1 -Script eng/devices/catalyst.cake --target=dotnet-samples --catalyst --verbosity=diagnostic --usenuget=false
./build.ps1 -Script eng/devices/catalyst.cake --target=uitest --apiversion="10.13" --configuration="Release" --device=mac

Additional Parameters

Filter by specific tests

You can pass any of the filters that are compatible with dotnet test

dotnet cake eng/devices/android.cake --target=uitest --test-filter="TestCategory=Border"

From Xamarin.UITest to .NET MAUI Appium

Below you can find an equivalent table between Xamarin.UITest and Appium.

Action Description Xamarin.UITest Appium (.NET MAUI) Example
Back Navigate back. public void Back (); public void Back (); App.Back();
BackgroundApp Send the currently running app for this session to the background. - public void BackgroundApp(); App.BackgroundApp();
ForegroundApp If the application is already running then it will be brought to the foreground. - public void ForegroundApp(); App.ForegroundApp();
ClearText Clears text. public void ClearText (string marked); public void ClearText (string marked); App.ClearText("AutomationId");
ClearText Clears text from a matching element that supports it. public void ClearText (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppWebQuery> query); public void ClearText (IQuery query);
DismissKeyboard Hides keyboard if present public void DismissKeyboard (); public void DismissKeyboard (); App.DismissKeyboard();
IsKeyboardShown Whether or not the soft keyboard is shown. - public bool IsKeyboardShown(); bool result = App.IsKeyboardShown();
DimissAlert Dismisses the alert. - public void DimissAlert(); App.DimissAlert();
DoubleTap Performs two quick tap / touch gestures. public void DoubleTap (string marked); public void DoubleTap (string marked); App.DoubleTap("AutomationId");
DoubleTap Performs two quick tap / touch gestures on the matched element. If multiple elements are matched, the first one will be used. public void DoubleTap (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> query); public void DoubleTap (IQuery query);
DoubleClick Performs two quick mouse clicks. - public void DoubleClick (string marked); App.DoubleClick("AutomationId");
DoubleTapCoordinates Performs a quick double tap / touch gesture on the given coordinates. public void DoubleTapCoordinates (float x, float y); public void DoubleTapCoordinates (float x, float y); App.DoubleTapCoordinates(100, 100);
DragAnDrop Drags the from element to the to element. public void DragAndDrop (string from, string to); public void DragAndDrop (string from, string to); App.DragAnDrop("from", "to");
DragAnDrop Drags the from element to the to element. public void DragAndDrop (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> from, Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> to); public void DragAndDrop (IQuery from, IQuery to);
DragCoordinates Performs a continuous drag gesture between 2 points. public void DragCoordinates (float fromX, float fromY, float toX, float toY); public void DragCoordinates (float fromX, float fromY, float toX, float toY); App.DragCoordinates(0, 0, 100, 100);
EnterText Enters text into the currently focused element. public void EnterText (string marked, string text); public void EnterText (string marked, string text); App.EnterText("AutomationId", "Text");
EnterText Enters text into a matching element that supports it. public void EnterText (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppWebQuery> query, string text); public void EnterText (IQuery query, string text);
Flash Highlights the results of the query by making them flash. public Xamarin.UITest.Queries.AppResult[] Flash (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> query = null); - -
IncreaseStepper Increases the value of a Stepper control. - public void IncreaseStepper(string marked); App.IncreaseStepper("AutomationId");
DecreaseStepper Decreases the value of a Stepper control. - public void DecreaseStepper(string marked); App.DecreaseStepper("AutomationId");
Invoke Invokes a method on the app's main activity for Android and app delegate for iOS. public object Invoke (string methodName, object[] arguments); - -
LongPress Performs a long mouse click on the matched element. - public static void LongPress(string element) App.LongPress("AutomationId");
Lock Lock the screen. Functionality that's only available on Android and iOS. - public void Lock(); App.Lock();
Unlock Unlock the screen. Functionality that's only available on Android and iOS. - public void Unlock(); App.Unlock();
Pan Performs a pan gesture between 2 points. - public void Pan(float fromX, float fromY, float toX, float toY) App.Pan(0, 0, 100, 100);
PincToZoomIn Performs a pinch gestures on the matched element to zoom the view in. public void PinchToZoomIn (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> query, Nullable duration = null); public void PinchToZoomIn (string marked, Nullable duration = null); App.PincToZoomIn("AutomationId");
PinchToZoomInCoordinates Performs a pinch gestures to zoom the view in on the given coordinates. public void PinchToZoomInCoordinates (float x, float y, Nullable duration); public void PinchToZoomInCoordinates (float x, float y, Nullable duration); App.PinchToZoomInCoordinates(100, 100);
PincToZoomOut Performs a pinch gestures on the matched element to zoom the view out. public void PinchToZoomOut (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> query, Nullable duration = null); public void PinchToZoomOut (string marked, Nullable duration = null); App.PincToZoomOut("AutomationId");
PinchToZoomOutCoordinates Performs a pinch gestures to zoom the view in on the given coordinates. public void PinchToZoomOutCoordinates (float x, float y, Nullable duration); public void PinchToZoomOutCoordinates (float x, float y, Nullable duration); App.PinchToZoomOutCoordinates(100, 100);
PressEnter Presses the enter key in the app. public void PressEnter (); public void PressEnter (); App.PressEnter();
PressVolumeDown Presses the volume down button on the device. public void PressVolumeDown (); public void PressVolumeDown (); App.PressVolumeDown();
PressVoumeUp Presses the volume up button on the device. public void PressVolumeUp (); public void PressVolumeUp (); App.PressVoumeUp();
Query Queries web view objects using the fluent API. Defaults to only return view objects that are visible. public Xamarin.UITest.Queries.AppWebResult[] Query (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppWebQuery> query); - -
QueryUntilPresent Repeatedly executes a query until it returns a non-empty value or the specified retry count is reached. public static T QueryUntilPresent(Func func, int retryCount = 10, int delayInMs = 2000); public static T QueryUntilPresent(Func func, int retryCount = 10, int delayInMs = 2000); App.QueryUntilPresent(() => App.WaitForElement("success"));
QueryUntilNotPresent Repeatedly executes a query until it returns a null value or the specified retry count is reached. public static T QueryUntilNotPresent(Func func, int retryCount = 10, int delayInMs = 2000); public static T QueryUntilNotPresent(Func func, int retryCount = 10, int delayInMs = 2000);  
Repl Starts an interactive REPL (Read-Eval-Print-Loop) for app exploration and pauses test execution until it is closed. public void Repl (); - -
Screenshot Takes a screenshot of the app in it's current state. public System.IO.FileInfo Screenshot (string title); public System.IO.FileInfo Screenshot (string title); App.Screenshot("Sample");
StartRecording Start recording screen. Functionality that's only available on Android, iOS and Windows. - public void StartRecording(); App.StartRecording();
StopRecording Stop recording screen. Functionality that's only available on Android, iOS and Windows. - public void StopRecording(); App.StopRecording();
SetLightMode Sets light device's theme. - public void SetLightMode(); App.SetLightMode();
SetDarkMode Sets dark device's theme. - public void SetDarkMode(); App.SetDarkMode();
ToggleWifi Switch the state of the wifi service. Functionality that's only available on Android. - public void ToggleWifi(); App.ToggleWifi();
ToggleAirplane Toggle airplane mode on device. Functionality that's only available on Android. - public void ToggleAirplane(); App.TogleAirplane();
VerifyScreenshot Takes a screenshot and compare it pixel by pixel with a reference one using the specified name or the test name. - public void VerifyScreenshot(string? name = null); VerifyScreenshot();
ScrollDown Scrolls down on the first element matching query. public void ScrollDown (string withinMarked, Xamarin.UITest.ScrollStrategy strategy = Xamarin.UITest.ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true); public void ScrollDown(string marked, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true); App.ScrollDown("CollectionView", ScrollStrategy.Gesture, 0.5);
ScrollDownTo Scroll down until an element that matches the toQuery is shown on the screen. public void ScrollDownTo (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> toQuery, Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> withinQuery = null, Xamarin.UITest.ScrollStrategy strategy = Xamarin.UITest.ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, Nullable timeout = null); public void ScrollDownTo (IQuery toQuery, string withinMarked, Xamarin.UITest.ScrollStrategy strategy = Xamarin.UITest.ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, Nullable timeout = null); -
ScrollTo Scroll until an element that matches the toMarkedis shown on the screen. public void ScrollTo (string toMarked, string withinMarked = null, Xamarin.UITest.ScrollStrategy strategy = Xamarin.UITest.ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, Nullable timeout = null); public static void ScrollTo(string toElementId, bool down = true); App.ScrollTo("Item10", true);
ScrollUp Scrolls up on the first element matching query. public void ScrollUp (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> query = null, Xamarin.UITest.ScrollStrategy strategy = Xamarin.UITest.ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true); public static void ScrollUp(string marked, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true); App.ScrollUp("CollectionView", ScrollStrategy.Gesture, 0.5);
ScrollUpTo Scroll up until an element that matches the toQuery is shown on the screen. public void ScrollUpTo (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> toQuery, Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> withinQuery = null, Xamarin.UITest.ScrollStrategy strategy = Xamarin.UITest.ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, Nullable timeout = null); public void ScrollUpTo (IQuery toQuery, string withinMarked, Xamarin.UITest.ScrollStrategy strategy = Xamarin.UITest.ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, Nullable timeout = null); -
SetOrientationLandscape Changes the device (iOS) or current activity (Android) orientation to landscape mode. public void SetOrientationLandscape (); public void SetOrientationLandscape (); App.SetOrientationLandscape();
SetOrientationPortrait Changes the device (iOS) or current activity (Android) orientation to portrait mode. public void SetOrientationPortrait (); public void SetOrientationPortrait (); App.SetOrientationPortrait();
SetSliderValue Sets the value of a slider element that matches marked. public void SetSliderValue (string marked, double value); public void SetSliderValue (string marked, double value); App.SetSliderValue("AutomationId", 4);
Shake Simulate the device shaking. Functionality that's only available on iOS. - public void Shake(); App.Shake();
SwipeLeftToRight Performs a left to right swipe gesture on an element matched by 'query'. public void SwipeLeftToRight (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppWebQuery> query, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true); - -
SwipeLeftToRight Performs a left to right swipe gesture on the matching element. If multiple elements are matched, the first one will be used. public void SwipeLeftToRight (string marked, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true); public void SwipeLeftToRight(double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true);  
SwipeRightToLeft Performs a right to left swipe gesture on an element matched by 'query'. public void SwipeRightToLeft (Func<Xamarin.UITest.Queries.AppQuery,Xamarin.UITest.Queries.AppQuery> query, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true); - -
SwipeRightToLeft Performs a right to left swipe gesture on the matching element. If multiple elements are matched, the first one will be used. public void SwipeRightToLeft (string marked, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true); public void SwipeRightToLeft(double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true);  
Tap Performs a tap / touch gesture on the matched element. If multiple elements are matched, the first one will be used. public void Tap (string marked); public void Tap (string marked); App.Tap("AutomationId");
TapCoordinates Performs a tap / touch gesture on the given coordinates. public void TapCoordinates (float x, float y); public void TapCoordinates (float x, float y); App.TapCoordinates(100, 100);
TouchAndHold Performs a continuous touch gesture on the matched element. If multiple elements are matched, the first one will be used. public void TouchAndHold (string marked); public void TouchAndHold (string marked); App.TouchAndHold("AutomationId");
TouchAndHoldCoordinates Performs a continuous touch gesture on the given coordinates. public void TouchAndHoldCoordinates (float x, float y); public void TouchAndHoldCoordinates (float x, float y); App.TouchAndHoldCoordinates(100, 100);
WaitFor Generic wait function that will repeatly call the predicatefunction until it returns true. Throws a TimeoutExceptionif the predicate is not fullfilled within the time limit. public void WaitFor (Func predicate, string timeoutMessage = "Timed out waiting...", Nullable timeout = null, Nullable retryFrequency = null, Nullable postTimeout = null); - -
WaitForElement Wait function that will repeatly query the app until a matching element is found. Throws a TimeoutExceptionif no element is found within the time limit. public Xamarin.UITest.Queries.AppResult[] WaitForElement (string marked, string timeoutMessage = "Timed out waiting for element...", Nullable timeout = null, Nullable retryFrequency = null, Nullable postTimeout = null); public IUElement WaitForElement (string marked, string timeoutMessage = "Timed out waiting for element...", Nullable timeout = null, Nullable retryFrequency = null, Nullable postTimeout = null); App.WaitForElement("AutomationId");
WaitForNoElement Wait function that will repeatly query the app until a matching element is no longer found. Throws aTimeoutExceptionif the element is visible at the end of the time limit. public void WaitForNoElement (string marked, string timeoutMessage = "Timed out waiting for no element...", Nullable timeout = null, Nullable retryFrequency = null, Nullable postTimeout = null); public void WaitForNoElement (string marked, string timeoutMessage = "Timed out waiting for no element...", Nullable timeout = null, Nullable retryFrequency = null, Nullable postTimeout = null); App.WaitForNoElement("Selected: Item 1");

Troubleshooting

The local appium server has not been started

  • Try starting appium from the command line to get a better error message node /usr/local/lib/node_modules/appium/build/lib/main.js
Clone this wiki locally