[Testing] Add UITest Stepper actions (#25130)

* Added Stepper UITests

* Added iOS version

* Updated Stepper UITests

* Fix build error

* More changes in the iOS impl

* Added support to Windows

* More changes in the Windows impl

* More changes

* More changes

* Changes to avoid not find MauiStepper container from Appium

* More changes

* More fixes
This commit is contained in:
Javier Suárez 2024-10-14 19:52:01 +02:00 коммит произвёл GitHub
Родитель fc5c3754a6
Коммит 24c6cd4127
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
10 изменённых файлов: 394 добавлений и 14 удалений

Просмотреть файл

@ -1,18 +1,31 @@
using Microsoft.Maui.Controls;
namespace Maui.Controls.Sample;
internal class StepperCoreGalleryPage : CoreGalleryPage<Stepper>
internal class StepperCoreGalleryPage : ContentPage
{
protected override bool SupportsFocus => false;
protected override bool SupportsTapGestureRecognizer => false;
protected override void InitializeElement(Stepper element)
public StepperCoreGalleryPage()
{
}
var layout = new StackLayout
{
Padding = new Thickness(12)
};
protected override void Build()
{
base.Build();
// Default
var defaultLabel = new Label { AutomationId = "DefaultLabel", Text = "Default" };
var defaultStepper = new Stepper { AutomationId = "DefaultStepper" };
var defaultLabelValue = new Label
{
AutomationId = "DefaultLabelValue",
Text = defaultStepper.Value.ToString()
};
layout.Add(defaultLabel);
layout.Add(defaultStepper);
layout.Add(defaultLabelValue);
defaultStepper.ValueChanged += (s, e) =>
{
defaultLabelValue.Text = e.NewValue.ToString();
};
Content = layout;
}
}
}

Просмотреть файл

@ -0,0 +1,82 @@
#if ANDROID || IOS || WINDOWS
using NUnit.Framework;
using NUnit.Framework.Legacy;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests
{
[Category(UITestCategories.Stepper)]
public class StepperUITests : UITest
{
public const string StepperGallery = "Stepper Gallery";
public StepperUITests(TestDevice device)
: base(device)
{
}
protected override void FixtureSetup()
{
base.FixtureSetup();
App.NavigateToGallery(StepperGallery);
}
[Test]
[Category(UITestCategories.Stepper)]
[Description("Increase the Stepper value")]
public void IncreaseStepper()
{
const string titleAutomationId = "DefaultLabel";
const string stepperAutomationId = "DefaultStepper";
const string valueAutomationId = "DefaultLabelValue";
App.WaitForElement(titleAutomationId);
// 1. Check the current value.
var step1Value = App.FindElement(valueAutomationId).GetText();
ClassicAssert.AreEqual("0", step1Value);
// 2. Increase the value.
App.IncreaseStepper(stepperAutomationId);
App.Screenshot("Increase the Stepper value");
// 3. Verify that the value has increased.
var step3Value = App.FindElement(valueAutomationId).GetText();
ClassicAssert.AreEqual("1", step3Value);
}
[Test]
[Category(UITestCategories.Stepper)]
[Description("Decrease the Stepper value")]
public void DecreaseStepper()
{
const string titleAutomationId = "DefaultLabel";
const string stepperAutomationId = "DefaultStepper";
const string valueAutomationId = "DefaultLabelValue";
App.WaitForElement(titleAutomationId);
// 1. Check the current value.
var step1Value = App.FindElement(valueAutomationId).GetText();
ClassicAssert.AreEqual("0", step1Value);
// 2. Increase the value.
App.IncreaseStepper(stepperAutomationId);
App.Screenshot("Increase the Stepper value");
// 3. Verify that the value has increased.
var step3Value = App.FindElement(valueAutomationId).GetText();
ClassicAssert.AreEqual("1", step3Value);
// 4. Decrease the value.
App.DecreaseStepper(stepperAutomationId);
App.Screenshot("Decrease the Stepper value");
// 5. Verify that the value has decreased.
var step5Value = App.FindElement(valueAutomationId).GetText();
ClassicAssert.AreEqual("0", step5Value);
}
}
}
#endif

Просмотреть файл

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using Microsoft.Maui.Graphics;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using WBrush = Microsoft.UI.Xaml.Media.Brush;
@ -98,14 +99,21 @@ namespace Microsoft.Maui.Platform
{
base.OnApplyTemplate();
var mauiStepperAutomationId = AutomationProperties.GetAutomationId(this);
_plus = GetTemplateChild("Plus") as Button;
if (_plus != null)
{
AutomationProperties.SetAutomationId(_plus, mauiStepperAutomationId + "Plus");
_plus.Click += OnPlusClicked;
}
_minus = GetTemplateChild("Minus") as Button;
if (_minus != null)
{
AutomationProperties.SetAutomationId(_minus, mauiStepperAutomationId + "Minus");
_minus.Click += OnMinusClicked;
}
UpdateEnabled(Value);
UpdateButtonBackground();
}

Просмотреть файл

@ -0,0 +1,94 @@
using OpenQA.Selenium.Appium;
using UITest.Core;
namespace UITest.Appium;
public class AppiumAndroidStepperActions : ICommandExecutionGroup
{
const string IncreaseCommand = "increaseStepper";
const string DecreaseCommand = "decreaseStepper";
readonly List<string> _commands = new()
{
IncreaseCommand,
DecreaseCommand
};
readonly AppiumApp _appiumApp;
public AppiumAndroidStepperActions(AppiumApp appiumApp)
{
_appiumApp = appiumApp;
}
public bool IsCommandSupported(string commandName)
{
return _commands.Contains(commandName, StringComparer.OrdinalIgnoreCase);
}
public CommandResponse Execute(string commandName, IDictionary<string, object> parameters)
{
return commandName switch
{
IncreaseCommand => Increase(parameters),
DecreaseCommand => Decrease(parameters),
_ => CommandResponse.FailedEmptyResponse,
};
}
CommandResponse Increase(IDictionary<string, object> parameters)
{
string? elementId = parameters["elementId"].ToString();
if (elementId is null)
return CommandResponse.FailedEmptyResponse;
var element = _appiumApp.FindElement(elementId);
var stepper = GetAppiumElement(element);
if (stepper is null)
return CommandResponse.FailedEmptyResponse;
var buttons = AppiumQuery.ByClass("android.widget.Button").FindElements(stepper, _appiumApp);
if(buttons is not null && buttons.Count > 1)
{
var increaseButton = buttons.LastOrDefault();
increaseButton?.Tap();
}
return CommandResponse.SuccessEmptyResponse;
}
CommandResponse Decrease(IDictionary<string, object> parameters)
{
string? elementId = parameters["elementId"].ToString();
if (elementId is null)
return CommandResponse.FailedEmptyResponse;
var element = _appiumApp.FindElement(elementId);
var stepper = GetAppiumElement(element);
if (stepper is null)
return CommandResponse.FailedEmptyResponse;
var buttons = AppiumQuery.ByClass("android.widget.Button").FindElements(stepper, _appiumApp);
if (buttons is not null && buttons.Count > 1)
{
var decreaseButton = buttons.FirstOrDefault();
decreaseButton?.Tap();
}
return CommandResponse.SuccessEmptyResponse;
}
static AppiumElement? GetAppiumElement(object element) =>
element switch
{
AppiumElement appiumElement => appiumElement,
AppiumDriverElement driverElement => driverElement.AppiumElement,
_ => null
};
}

Просмотреть файл

@ -0,0 +1,94 @@
using OpenQA.Selenium.Appium;
using UITest.Core;
namespace UITest.Appium;
class AppiumIOSStepperActions : ICommandExecutionGroup
{
const string IncreaseCommand = "increaseStepper";
const string DecreaseCommand = "decreaseStepper";
readonly List<string> _commands = new()
{
IncreaseCommand,
DecreaseCommand
};
readonly AppiumApp _appiumApp;
public AppiumIOSStepperActions(AppiumApp appiumApp)
{
_appiumApp = appiumApp;
}
public bool IsCommandSupported(string commandName)
{
return _commands.Contains(commandName, StringComparer.OrdinalIgnoreCase);
}
public CommandResponse Execute(string commandName, IDictionary<string, object> parameters)
{
return commandName switch
{
IncreaseCommand => Increase(parameters),
DecreaseCommand => Decrease(parameters),
_ => CommandResponse.FailedEmptyResponse,
};
}
CommandResponse Increase(IDictionary<string, object> parameters)
{
string? elementId = parameters["elementId"].ToString();
if (elementId is null)
return CommandResponse.FailedEmptyResponse;
var element = _appiumApp.FindElement(elementId);
var stepper = GetAppiumElement(element);
if (stepper is null)
return CommandResponse.FailedEmptyResponse;
var buttons = AppiumQuery.ByClass("XCUIElementTypeButton").FindElements(stepper, _appiumApp);
if (buttons is not null && buttons.Count > 1)
{
var increaseButton = buttons.LastOrDefault();
increaseButton?.Tap();
}
return CommandResponse.SuccessEmptyResponse;
}
CommandResponse Decrease(IDictionary<string, object> parameters)
{
string? elementId = parameters["elementId"].ToString();
if (elementId is null)
return CommandResponse.FailedEmptyResponse;
var element = _appiumApp.FindElement(elementId);
var stepper = GetAppiumElement(element);
if (stepper is null)
return CommandResponse.FailedEmptyResponse;
var buttons = AppiumQuery.ByClass("XCUIElementTypeButton").FindElements(stepper, _appiumApp);
if (buttons is not null && buttons.Count > 1)
{
var decreaseButton = buttons.FirstOrDefault();
decreaseButton?.Tap();
}
return CommandResponse.SuccessEmptyResponse;
}
static AppiumElement? GetAppiumElement(object element) =>
element switch
{
AppiumElement appiumElement => appiumElement,
AppiumDriverElement driverElement => driverElement.AppiumElement,
_ => null
};
}

Просмотреть файл

@ -0,0 +1,61 @@
using UITest.Core;
namespace UITest.Appium;
public class AppiumWindowsStepperActions : ICommandExecutionGroup
{
const string IncreaseCommand = "increaseStepper";
const string DecreaseCommand = "decreaseStepper";
readonly List<string> _commands = new()
{
IncreaseCommand,
DecreaseCommand
};
readonly AppiumApp _appiumApp;
public AppiumWindowsStepperActions(AppiumApp appiumApp)
{
_appiumApp = appiumApp;
}
public bool IsCommandSupported(string commandName)
{
return _commands.Contains(commandName, StringComparer.OrdinalIgnoreCase);
}
public CommandResponse Execute(string commandName, IDictionary<string, object> parameters)
{
return commandName switch
{
IncreaseCommand => Increase(parameters),
DecreaseCommand => Decrease(parameters),
_ => CommandResponse.FailedEmptyResponse,
};
}
CommandResponse Increase(IDictionary<string, object> parameters)
{
string? elementId = parameters["elementId"].ToString();
if (elementId is null)
return CommandResponse.FailedEmptyResponse;
var increaseButton = _appiumApp.FindElement(elementId + "Plus");
increaseButton?.Click();
return CommandResponse.SuccessEmptyResponse;
}
CommandResponse Decrease(IDictionary<string, object> parameters)
{
string? elementId = parameters["elementId"].ToString();
if (elementId is null)
return CommandResponse.FailedEmptyResponse;
var decreaseButton = _appiumApp.FindElement(elementId + "Minus");
decreaseButton?.Click();
return CommandResponse.SuccessEmptyResponse;
}
}

Просмотреть файл

@ -14,6 +14,7 @@ namespace UITest.Appium
_commandExecutor.AddCommandGroup(new AppiumAndroidSpecificActions(this));
_commandExecutor.AddCommandGroup(new AppiumAndroidVirtualKeyboardActions(this));
_commandExecutor.AddCommandGroup(new AppiumAndroidAlertActions(this));
_commandExecutor.AddCommandGroup(new AppiumAndroidStepperActions(this));
}
public static AppiumAndroidApp CreateAndroidApp(Uri remoteAddress, IConfig config)

Просмотреть файл

@ -18,6 +18,7 @@ namespace UITest.Appium
_commandExecutor.AddCommandGroup(new AppiumIOSThemeChangeAction(this));
_commandExecutor.AddCommandGroup(new AppiumIOSAlertActions(this));
_commandExecutor.AddCommandGroup(new AppiumIOSThemeChangeAction(this));
_commandExecutor.AddCommandGroup(new AppiumIOSStepperActions(this));
}
public override ApplicationState AppState

Просмотреть файл

@ -10,7 +10,7 @@ namespace UITest.Appium
public AppiumWindowsApp(Uri remoteAddress, IConfig config)
: base(new WindowsDriver(remoteAddress, GetOptions(config)), config)
{
_commandExecutor.AddCommandGroup(new AppiumWindowsStepperActions(this));
}
public override ApplicationState AppState

Просмотреть файл

@ -766,6 +766,32 @@ namespace UITest.Appium
});
}
/// <summary>
/// Increases the value of a Stepper control.
/// </summary>
/// <param name="app">Represents the main gateway to interact with an app.</param>
/// <param name="marked">Marked selector of the Stepper element to increase.</param>
public static void IncreaseStepper(this IApp app, string marked)
{
app.CommandExecutor.Execute("increaseStepper", new Dictionary<string, object>
{
["elementId"] = marked
});
}
/// <summary>
/// Decreases the value of a Stepper control.
/// </summary>
/// <param name="app">Represents the main gateway to interact with an app.</param>
/// <param name="marked">Marked selector of the Stepper element to decrease.</param>
public static void DecreaseStepper(this IApp app, string marked)
{
app.CommandExecutor.Execute("decreaseStepper", new Dictionary<string, object>
{
["elementId"] = marked
});
}
/// <summary>
/// Performs a continuous drag gesture between 2 points.
/// </summary>