From b2612775beee725ccff0604b49ff77c7ea9250fb Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Wed, 21 Feb 2024 11:47:13 -0600 Subject: [PATCH] Setup Android App With More Accurate settings (#20672) * Setup Android App With More Accurate settings * - fix iOS reset * - fix windows * Update HelperExtensions.cs --- .../Platforms/Android/MainActivity.cs | 2 + src/Controls/tests/UITests/UITest.cs | 6 +++ .../Actions/AppiumLifecycleActions.cs | 36 +++++++++++++- .../src/UITest.Appium/AppiumAndroidApp.cs | 7 ++- src/TestUtils/src/UITest.Appium/AppiumApp.cs | 3 ++ .../src/UITest.Appium/HelperExtensions.cs | 48 ++++++++++++++++++- .../src/UITest.NUnit/UITestContextBase.cs | 2 +- 7 files changed, 97 insertions(+), 7 deletions(-) diff --git a/src/Controls/samples/Controls.Sample.UITests/Platforms/Android/MainActivity.cs b/src/Controls/samples/Controls.Sample.UITests/Platforms/Android/MainActivity.cs index be015c14658d..a0eb1ce025ec 100644 --- a/src/Controls/samples/Controls.Sample.UITests/Platforms/Android/MainActivity.cs +++ b/src/Controls/samples/Controls.Sample.UITests/Platforms/Android/MainActivity.cs @@ -1,5 +1,6 @@ using Android.App; using Android.Content.PM; +using Android.Runtime; using Microsoft.Maui; namespace Maui.Controls.Sample.Platform @@ -11,6 +12,7 @@ namespace Maui.Controls.Sample.Platform [IntentFilter( new[] { Microsoft.Maui.ApplicationModel.Platform.Intent.ActionAppAction }, Categories = new[] { Android.Content.Intent.CategoryDefault })] + [Register("com.microsoft.maui.uitests.MainActivity")] public class MainActivity : MauiAppCompatActivity { } diff --git a/src/Controls/tests/UITests/UITest.cs b/src/Controls/tests/UITests/UITest.cs index e1b26e51ad68..8df106671355 100644 --- a/src/Controls/tests/UITests/UITest.cs +++ b/src/Controls/tests/UITests/UITest.cs @@ -1,5 +1,6 @@ using System.Reflection; using NUnit.Framework; +using UITest.Appium; using UITest.Appium.NUnit; using UITest.Core; using VisualTestUtils; @@ -85,6 +86,11 @@ public override IConfig GetTestConfig() return config; } + public override void Reset() + { + App.ResetApp(); + } + public void VerifyScreenshot(string? name = null) { string deviceName = GetTestConfig().GetProperty("DeviceName") ?? string.Empty; diff --git a/src/TestUtils/src/UITest.Appium/Actions/AppiumLifecycleActions.cs b/src/TestUtils/src/UITest.Appium/Actions/AppiumLifecycleActions.cs index ec0dd0f03593..d84b5e1d2d27 100644 --- a/src/TestUtils/src/UITest.Appium/Actions/AppiumLifecycleActions.cs +++ b/src/TestUtils/src/UITest.Appium/Actions/AppiumLifecycleActions.cs @@ -1,4 +1,5 @@ -using UITest.Core; +using OpenQA.Selenium.Appium.Android; +using UITest.Core; namespace UITest.Appium { @@ -6,6 +7,7 @@ public class AppiumLifecycleActions : ICommandExecutionGroup { const string LaunchAppCommand = "launchApp"; const string BackgroundAppCommand = "backgroundApp"; + const string ForegroundAppCommand = "foregroundApp"; const string ResetAppCommand = "resetApp"; const string CloseAppCommand = "closeApp"; const string BackCommand = "back"; @@ -15,6 +17,7 @@ public class AppiumLifecycleActions : ICommandExecutionGroup readonly List _commands = new() { LaunchAppCommand, + ForegroundAppCommand, BackgroundAppCommand, ResetAppCommand, CloseAppCommand, @@ -36,6 +39,7 @@ public CommandResponse Execute(string commandName, IDictionary p return commandName switch { LaunchAppCommand => LaunchApp(parameters), + ForegroundAppCommand => ForegroundApp(parameters), BackgroundAppCommand => BackgroundApp(parameters), ResetAppCommand => ResetApp(parameters), CloseAppCommand => CloseApp(parameters), @@ -54,6 +58,16 @@ CommandResponse LaunchApp(IDictionary parameters) return CommandResponse.SuccessEmptyResponse; } + CommandResponse ForegroundApp(IDictionary parameters) + { + if (_app?.Driver is null) + return CommandResponse.FailedEmptyResponse; + + _app.Driver.ActivateApp(_app.GetAppId()); + + return CommandResponse.SuccessEmptyResponse; + } + CommandResponse BackgroundApp(IDictionary parameters) { if (_app?.Driver is null) @@ -69,7 +83,25 @@ CommandResponse ResetApp(IDictionary parameters) if (_app?.Driver is null) return CommandResponse.FailedEmptyResponse; - _app.Driver.ResetApp(); + // Terminate App not supported on Mac + if (_app.GetTestDevice() == TestDevice.Mac) + { + _app.Driver.ResetApp(); + } + else if (_app.GetTestDevice() == TestDevice.Windows) + { + CloseApp(parameters); + _app.Driver.LaunchApp(); + } + else + { + _app.Driver.TerminateApp(_app.GetAppId()); + + if (_app.GetTestDevice() == TestDevice.iOS) + _app.Driver.ActivateApp(_app.GetAppId()); + else + _app.Driver.LaunchApp(); + } return CommandResponse.SuccessEmptyResponse; } diff --git a/src/TestUtils/src/UITest.Appium/AppiumAndroidApp.cs b/src/TestUtils/src/UITest.Appium/AppiumAndroidApp.cs index 0ecfa53ae558..acaae78fb79c 100644 --- a/src/TestUtils/src/UITest.Appium/AppiumAndroidApp.cs +++ b/src/TestUtils/src/UITest.Appium/AppiumAndroidApp.cs @@ -71,14 +71,17 @@ private static AppiumOptions GetOptions(IConfig config) { config.SetProperty("PlatformName", "Android"); config.SetProperty("AutomationName", "UIAutomator2"); + var appId = config.GetProperty("AppId"); var options = new AppiumOptions(); + SetGeneralAppiumOptions(config, options); - var appId = config.GetProperty("AppId"); if (!string.IsNullOrWhiteSpace(appId)) { - options.AddAdditionalAppiumOption(IOSMobileCapabilityType.BundleId, appId); + options.AddAdditionalAppiumOption(MobileCapabilityType.NoReset, "true"); + options.AddAdditionalAppiumOption(AndroidMobileCapabilityType.AppPackage, appId); + options.AddAdditionalAppiumOption(AndroidMobileCapabilityType.AppActivity, $"{appId}.MainActivity"); } return options; diff --git a/src/TestUtils/src/UITest.Appium/AppiumApp.cs b/src/TestUtils/src/UITest.Appium/AppiumApp.cs index 950cae363e8c..ad7c8c6bdcde 100644 --- a/src/TestUtils/src/UITest.Appium/AppiumApp.cs +++ b/src/TestUtils/src/UITest.Appium/AppiumApp.cs @@ -113,6 +113,9 @@ protected static void SetGeneralAppiumOptions(IConfig config, AppiumOptions appi if (config.GetProperty("FullReset")) appiumOptions.AddAdditionalAppiumOption(MobileCapabilityType.FullReset, "true"); + if (config.GetProperty("NoReset")) + appiumOptions.AddAdditionalAppiumOption(MobileCapabilityType.NoReset, "true"); + var appPath = config.GetProperty("AppPath"); if (!string.IsNullOrEmpty(appPath)) appiumOptions.App = appPath; diff --git a/src/TestUtils/src/UITest.Appium/HelperExtensions.cs b/src/TestUtils/src/UITest.Appium/HelperExtensions.cs index f195477c1a94..37f9663f0719 100644 --- a/src/TestUtils/src/UITest.Appium/HelperExtensions.cs +++ b/src/TestUtils/src/UITest.Appium/HelperExtensions.cs @@ -95,7 +95,7 @@ public static void SendKeys(this IApp app, int keyCode, int metastate = 0) ske.PressKeyCode(keyCode, metastate); return; } - + throw new InvalidOperationException($"SendKeys is not supported on {aaa.Driver}"); } @@ -452,6 +452,15 @@ public static void BackgroundApp(this IApp app) app.CommandExecutor.Execute("backgroundApp", ImmutableDictionary.Empty); } + /// + /// If the application is already running then it will be brought to the foreground. + /// + /// Represents the main gateway to interact with an app. + public static void ForegroundApp(this IApp app) + { + app.CommandExecutor.Execute("foregroundApp", ImmutableDictionary.Empty); + } + /// /// Reset the currently running app for this session. /// @@ -541,6 +550,41 @@ public static void Back(this IApp app) app.CommandExecutor.Execute("back", ImmutableDictionary.Empty); } + /// + /// Return the AppId of the running app. This is used inside any appium command that want the app id + /// + /// Represents the main gateway to interact with an app. + public static string GetAppId(this IApp app) + { + if (app is not AppiumApp aaa) + { + throw new InvalidOperationException($"GetAppId is only supported on AppiumApp"); + } + + var appId = aaa.Config.GetProperty("AppId"); + if (appId is not null) + { + return appId; + } + + throw new InvalidOperationException("AppId not found"); + } + + /// + /// Retrieve the target device this test is running against + /// + /// Represents the main gateway to interact with an app. + /// + /// + public static TestDevice GetTestDevice(this IApp app) + { + if (app is not AppiumApp aaa) + { + throw new InvalidOperationException($"GetTestDevice is only supported on AppiumApp"); + } + + return aaa.Config.GetProperty("TestDevice"); + } /// /// Check if element has focused @@ -609,4 +653,4 @@ static void WaitForNone(Func query, Wait(query, i => i == null, timeoutMessage, timeout, retryFrequency); } } -} \ No newline at end of file +} diff --git a/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs b/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs index f1ec79fc78fe..1f871cf041b5 100644 --- a/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs +++ b/src/TestUtils/src/UITest.NUnit/UITestContextBase.cs @@ -43,7 +43,7 @@ public void InitialSetup(IServerContext context) InitialSetup(context, false); } - public void Reset() + public virtual void Reset() { if (_context == null) {