diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Stepper_ChangeFlowDirection_RTL_VerifyVisualState.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Stepper_ChangeFlowDirection_RTL_VerifyVisualState.png new file mode 100644 index 000000000000..4834c3caed21 Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Stepper_ChangeFlowDirection_RTL_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs b/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs index ae058bc9bc44..ff9d36abbaf8 100644 --- a/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs +++ b/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs @@ -71,6 +71,7 @@ public override string ToString() new GalleryPageFactory(() => new ScrollViewCoreGalleryPage(), "ScrollView Gallery"), new GalleryPageFactory(() => new SearchBarCoreGalleryPage(), "Search Bar Gallery"), new GalleryPageFactory(() => new SliderCoreGalleryPage(), "Slider Gallery"), + new GalleryPageFactory(() => new StepperControlPage(), "Stepper Feature Matrix"), new GalleryPageFactory(() => new StepperCoreGalleryPage(), "Stepper Gallery"), new GalleryPageFactory(() => new SwitchCoreGalleryPage(), "Switch Gallery"), new GalleryPageFactory(() => new SwipeViewCoreGalleryPage(), "SwipeView Gallery"), @@ -79,7 +80,6 @@ public override string ToString() new GalleryPageFactory(() => new SliderControlPage(), "Slider Feature Matrix"), new GalleryPageFactory(() => new CollectionViewFeaturePage(), "CollectionView Feature Matrix"), new GalleryPageFactory(() => new CarouselViewFeaturePage(), "CarouselView Feature Matrix"), - }; public CorePageView(Page rootPage) diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperControlPage.xaml b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperControlPage.xaml new file mode 100644 index 000000000000..fb58ba4e1fb9 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperControlPage.xaml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperControlPage.xaml.cs b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperControlPage.xaml.cs new file mode 100644 index 000000000000..5836c5ccb0e9 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperControlPage.xaml.cs @@ -0,0 +1,29 @@ +using System; +using Microsoft.Maui.Controls; + +namespace Maui.Controls.Sample; + +public class StepperControlPage : NavigationPage +{ + + public StepperControlPage() + { + PushAsync(new StepperControlMainPage()); + } +} +public partial class StepperControlMainPage : ContentPage +{ + private StepperViewModel _viewModel; + + public StepperControlMainPage() + { + InitializeComponent(); + BindingContext = _viewModel = new StepperViewModel(); + } + + private async void NavigateToOptionsPage_Clicked(object sender, EventArgs e) + { + BindingContext = _viewModel = new StepperViewModel(); + await Navigation.PushAsync(new StepperFeaturePage(_viewModel)); + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperFeaturePage.xaml b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperFeaturePage.xaml new file mode 100644 index 000000000000..fc92f4df2342 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperFeaturePage.xaml @@ -0,0 +1,154 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperFeaturePage.xaml.cs b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperFeaturePage.xaml.cs new file mode 100644 index 000000000000..d53c97f04004 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperFeaturePage.xaml.cs @@ -0,0 +1,68 @@ +using System; +using Microsoft.Maui.Controls; + +namespace Maui.Controls.Sample; + +public partial class StepperFeaturePage : ContentPage +{ + private StepperViewModel _viewModel; + + public StepperFeaturePage(StepperViewModel viewModel) + { + InitializeComponent(); + _viewModel = viewModel; + BindingContext = _viewModel; + } + + private void ApplyButton_Clicked(object sender, EventArgs e) + { + Navigation.PopAsync(); + } + + private void OnMinimumChanged(object sender, TextChangedEventArgs e) + { + if (double.TryParse(MinimumEntry.Text, out double min)) + { + _viewModel.Minimum = min; + } + } + + private void OnMaximumChanged(object sender, TextChangedEventArgs e) + { + if (double.TryParse(MaximumEntry.Text, out double max)) + { + _viewModel.Maximum = max; + } + } + + private void OnIncrementChanged(object sender, TextChangedEventArgs e) + { + if (double.TryParse(IncrementEntry.Text, out double increment)) + { + _viewModel.Increment = increment; + } + } + + private void OnValueChanged(object sender, TextChangedEventArgs e) + { + if (double.TryParse(ValueEntry.Text, out double value)) + { + _viewModel.Value = value; + } + } + + private void OnIsEnabledCheckedChanged(object sender, CheckedChangedEventArgs e) + { + _viewModel.IsEnabled = IsEnabledTrueRadio.IsChecked; + } + + private void OnIsVisibleCheckedChanged(object sender, CheckedChangedEventArgs e) + { + _viewModel.IsVisible = IsVisibleTrueRadio.IsChecked; + } + + private void OnFlowDirectionChanged(object sender, CheckedChangedEventArgs e) + { + _viewModel.FlowDirection = FlowDirectionLTRRadio.IsChecked ? FlowDirection.LeftToRight : FlowDirection.RightToLeft; + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperViewModel.cs b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperViewModel.cs new file mode 100644 index 000000000000..e51ff5f6fdfa --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/Stepper/StepperViewModel.cs @@ -0,0 +1,68 @@ +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace Maui.Controls.Sample; + +public class StepperViewModel : INotifyPropertyChanged +{ + private double _minimum = 0; + private double _maximum = 10; + private double _increment = 1; + private double _value = 0; + private bool _isEnabled = true; + private bool _isVisible = true; + private FlowDirection _flowDirection = FlowDirection.LeftToRight; + + public double Minimum + { + get => _minimum; + set => SetProperty(ref _minimum, value); + } + + public double Maximum + { + get => _maximum; + set => SetProperty(ref _maximum, value); + } + + public double Increment + { + get => _increment; + set => SetProperty(ref _increment, value); + } + + public double Value + { + get => _value; + set => SetProperty(ref _value, value); + } + + public bool IsEnabled + { + get => _isEnabled; + set => SetProperty(ref _isEnabled, value); + } + + public bool IsVisible + { + get => _isVisible; + set => SetProperty(ref _isVisible, value); + } + + public FlowDirection FlowDirection + { + get => _flowDirection; + set => SetProperty(ref _flowDirection, value); + } + + public event PropertyChangedEventHandler PropertyChanged; + + protected void SetProperty(ref T backingStore, T value, [CallerMemberName] string propertyName = "") + { + if (EqualityComparer.Default.Equals(backingStore, value)) + return; + + backingStore = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/StepperFeatureTests.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/StepperFeatureTests.cs new file mode 100644 index 000000000000..20f23edbba98 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/StepperFeatureTests.cs @@ -0,0 +1,348 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests; + +[Category(UITestCategories.Stepper)] +public class StepperFeatureTests : UITest +{ + public const string StepperFeatureMatrix = "Stepper Feature Matrix"; + + public StepperFeatureTests(TestDevice device) + : base(device) + { + } + + protected override void FixtureSetup() + { + base.FixtureSetup(); + App.NavigateToGallery(StepperFeatureMatrix); + } + + [Test, Order(1)] + public void Stepper_ValidateDefaultValues_VerifyLabels() + { + App.WaitForElement("Options"); + Assert.That(App.FindElement("MinimumLabel").GetText(), Is.EqualTo("0.00")); + Assert.That(App.FindElement("MaximumLabel").GetText(), Is.EqualTo("10.00")); + Assert.That(App.FindElement("ValueLabel").GetText(), Is.EqualTo("0.00")); + } + + [Test] + public void Stepper_SetMinimumValue_VerifyMinimumLabel() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("MinimumEntry"); + App.EnterText("MinimumEntry", "2"); + App.PressEnter(); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + Assert.That(App.FindElement("MinimumLabel").GetText(), Is.EqualTo("2.00")); + } + + [Test] + public void Stepper_SetMaximumValue_VerifyMaximumLabel() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("MaximumEntry"); + App.EnterText("MaximumEntry", "20"); + App.PressEnter(); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + Assert.That(App.FindElement("MaximumLabel").GetText(), Is.EqualTo("20.00")); + } + + [Test] + public void Stepper_SetValueWithinRange_VerifyValueLabel() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("ValueEntry"); + App.EnterText("ValueEntry", "5"); + App.PressEnter(); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + Assert.That(App.FindElement("ValueLabel").GetText(), Is.EqualTo("5.00")); + } + + [Test] + public void Stepper_SetIncrementValue_VerifyIncrement() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("IncrementEntry"); + App.EnterText("IncrementEntry", "2"); + App.PressEnter(); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + App.IncreaseStepper("StepperControl"); + Assert.That(App.FindElement("ValueLabel").GetText(), Is.EqualTo("2.00")); + } + + [Test] + public void Stepper_SetValueExceedsMaximum() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("MaximumEntry"); + App.ClearText("MaximumEntry"); + App.EnterText("MaximumEntry", "100"); + App.PressEnter(); + App.ClearText("ValueEntry"); + App.EnterText("ValueEntry", "200"); + App.PressEnter(); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + Assert.That(App.FindElement("ValueLabel").GetText(), Is.EqualTo("100.00")); + } + +#if TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_IOS && TEST_FAILS_ON_WINDOWS +// Related Issue Link : https://github.com/dotnet/maui/issues/12243 + [Test] + public void Stepper_SetValueBelowMinimum() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("MinimumEntry"); + App.ClearText("MinimumEntry"); + App.EnterText("MinimumEntry", "10"); + App.PressEnter(); + App.ClearText("ValueEntry"); + App.EnterText("ValueEntry", "5"); + App.PressEnter(); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + Assert.That(App.FindElement("ValueLabel").GetText(), Is.EqualTo("10.00")); + } + + [Test] + public void Stepper_MinimumExceedsMaximum_SetsMinimumToMaximum() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("MinimumEntry"); + App.ClearText("MinimumEntry"); + App.EnterText("MinimumEntry", "50"); + App.PressEnter(); + App.ClearText("MaximumEntry"); + App.EnterText("MaximumEntry", "25"); + App.PressEnter(); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + Assert.That(App.FindElement("MinimumLabel").GetText(), Is.EqualTo("50.00")); + Assert.That(App.FindElement("MaximumLabel").GetText(), Is.EqualTo("50.00")); + } +#endif + + [Test] + public void Stepper_SetEnabledStateToFalse_VerifyVisualState() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("IsEnabledFalseRadio"); + App.Tap("IsEnabledFalseRadio"); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + App.IncreaseStepper("StepperControl"); + Assert.That(App.FindElement("ValueLabel").GetText(), Is.EqualTo("0.00")); + } + + [Test] + public void Stepper_SetVisibilityToFalse_VerifyVisualState() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("IsVisibleFalseRadio"); + App.Tap("IsVisibleFalseRadio"); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + App.WaitForNoElement("StepperControl"); + } + +#if TEST_FAILS_ON_IOS && TEST_FAILS_ON_CATALYST //Related Issue Link : https://github.com/dotnet/maui/issues/29704 + [Test] + public void Stepper_ChangeFlowDirection_RTL_VerifyVisualState() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("FlowDirectionRTLRadio"); + App.Tap("FlowDirectionRTLRadio"); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + VerifyScreenshot(); + } +#endif + [Test] + public void Stepper_AtMinimumValue_DecrementButtonDisabled() + { + App.WaitForElement("Options"); + App.Tap("Options"); + + App.WaitForElement("MinimumEntry"); + App.ClearText("MinimumEntry"); + App.EnterText("MinimumEntry", "10"); + App.PressEnter(); + + App.WaitForElement("ValueEntry"); + App.ClearText("ValueEntry"); + App.EnterText("ValueEntry", "10"); + App.PressEnter(); + + App.WaitForElement("Apply"); + App.Tap("Apply"); + + App.WaitForElement("Options"); + + var currentValue = App.FindElement("ValueLabel").GetText(); + Assert.That(currentValue, Is.EqualTo("10.00")); + + App.DecreaseStepper("StepperControl"); + + var newValue = App.FindElement("ValueLabel").GetText(); + Assert.That(newValue, Is.EqualTo("10.00")); + } + + [Test] + public void Stepper_AtMaximumValue_IncrementButtonDisabled() + { + App.WaitForElement("Options"); + App.Tap("Options"); + + App.WaitForElement("MaximumEntry"); + App.EnterText("MaximumEntry", "10"); + App.PressEnter(); + + App.WaitForElement("ValueEntry"); + App.EnterText("ValueEntry", "10"); + App.PressEnter(); + + App.WaitForElement("Apply"); + App.Tap("Apply"); + + App.WaitForElement("Options"); + + var currentValue = App.FindElement("ValueLabel").GetText(); + Assert.That(currentValue, Is.EqualTo("10.00")); + + App.IncreaseStepper("StepperControl"); + + var newValue = App.FindElement("ValueLabel").GetText(); + Assert.That(newValue, Is.EqualTo("10.00")); + } + + [Test] + public void Stepper_SetIncrementAndVerifyValueChange() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("IncrementEntry"); + App.EnterText("IncrementEntry", "5"); + App.PressEnter(); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + App.IncreaseStepper("StepperControl"); + Assert.That(App.FindElement("ValueLabel").GetText(), Is.EqualTo("5.00")); + App.IncreaseStepper("StepperControl"); + Assert.That(App.FindElement("ValueLabel").GetText(), Is.EqualTo("10.00")); + } + + + [Test] + public void Stepper_ResetToInitialState_VerifyDefaultValues() + { + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("MinimumEntry"); + App.EnterText("MinimumEntry", "10"); + App.PressEnter(); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + App.Tap("Options"); + App.WaitForElement("Apply"); + App.Tap("Apply"); + App.WaitForElement("Options"); + Assert.That(App.FindElement("MinimumLabel").GetText(), Is.EqualTo("0.00")); + Assert.That(App.FindElement("MaximumLabel").GetText(), Is.EqualTo("10.00")); + Assert.That(App.FindElement("ValueLabel").GetText(), Is.EqualTo("0.00")); + } + +#if TEST_FAILS_ON_WINDOWS // Related Issue Link : https://github.com/dotnet/maui/issues/29740 + [Test] + public void Stepper_IncrementDoesNotExceedMaximum() + { + App.WaitForElement("Options"); + App.Tap("Options"); + + App.WaitForElement("MaximumEntry"); + App.ClearText("MaximumEntry"); + App.EnterText("MaximumEntry", "10"); + App.PressEnter(); + + App.WaitForElement("IncrementEntry"); + App.ClearText("IncrementEntry"); + App.EnterText("IncrementEntry", "3"); + App.PressEnter(); + + App.WaitForElement("Apply"); + App.Tap("Apply"); + + App.WaitForElement("Options"); + + App.IncreaseStepper("StepperControl"); + App.IncreaseStepper("StepperControl"); + App.IncreaseStepper("StepperControl"); + App.IncreaseStepper("StepperControl"); + + var currentValue = App.FindElement("ValueLabel").GetText(); + Assert.That(currentValue, Is.EqualTo("10.00")); + } +#endif + + [Test] + public void Stepper_DecrementDoesNotGoBelowMinimum() + { + App.WaitForElement("Options"); + App.Tap("Options"); + + App.WaitForElement("MinimumEntry"); + App.ClearText("MinimumEntry"); + App.EnterText("MinimumEntry", "0"); + App.PressEnter(); + + App.WaitForElement("IncrementEntry"); + App.ClearText("IncrementEntry"); + App.EnterText("IncrementEntry", "2"); + App.PressEnter(); + + App.WaitForElement("ValueEntry"); + App.ClearText("ValueEntry"); + App.EnterText("ValueEntry", "2"); + App.PressEnter(); + + App.WaitForElement("Apply"); + App.Tap("Apply"); + + App.WaitForElement("Options"); + + App.DecreaseStepper("StepperControl"); + App.DecreaseStepper("StepperControl"); + + var currentValue = App.FindElement("ValueLabel").GetText(); + Assert.That(currentValue, Is.EqualTo("0.00")); + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Stepper_ChangeFlowDirection_RTL_VerifyVisualState.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Stepper_ChangeFlowDirection_RTL_VerifyVisualState.png new file mode 100644 index 000000000000..56f3f4511f18 Binary files /dev/null and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Stepper_ChangeFlowDirection_RTL_VerifyVisualState.png differ