From 8e73179fe528c49936cecfadadc509121320c77c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Mon, 25 Mar 2024 12:51:48 +0100 Subject: [PATCH 01/27] Just added a couple of tests --- Microsoft.Maui.sln | 41 +++- ...ntrolGallery.Android.Appium.UITests.csproj | 46 +++++ .../PlatformSpecificSampleTest.cs | 16 ++ .../AppiumServerHelper.cs | 33 ++++ .../BaseViewContainerRemote.cs | 42 +++++ ...ontrolGallery.Shared.Appium.UITests.csproj | 36 ++++ .../EventViewContainerRemote.cs | 19 ++ .../Shared.Appium.UITests/GalleryQueries.cs | 30 +++ .../Shared.Appium.UITests/IssuesUITest.cs | 63 +++++++ .../StateViewContainerRemote.cs | 23 +++ .../Shared.Appium.UITests/TestAttributes.cs | 71 +++++++ .../TestContextSetupFixture.cs | 17 ++ .../test/Shared.Appium.UITests/TestDevice.cs | 10 + .../Tests/Issues/Issue10744.cs | 22 +++ .../Tests/Issues/Issue11853.cs | 30 +++ .../test/Shared.Appium.UITests/UITest.cs | 168 +++++++++++++++++ .../test/Shared.Appium.UITests/UITestBase.cs | 175 ++++++++++++++++++ .../Shared.Appium.UITests/UITestCategories.cs | 68 +++++++ .../UITestContextBase.cs | 91 +++++++++ .../Shared.Appium.UITests/UITestExtensions.cs | 90 +++++++++ .../UITestIgnoreAttributes.cs | 112 +++++++++++ .../ViewContainerRemote.cs | 10 + .../test/Shared.Appium.UITests/ViewUITest.cs | 160 ++++++++++++++++ .../VisualTestContext.cs | 11 ++ .../Windows.Appium.UITests/AppiumSetup.cs | 46 +++++ ...ntrolGallery.Windows.Appium.UITests.csproj | 42 +++++ .../PlatformSpecificSampleTest.cs | 16 ++ .../ControlGallery.iOS.Appium.UITests.csproj | 42 +++++ .../PlatformSpecificSampleTest.cs | 16 ++ .../test/macOS.Appium.UITests/AppiumSetup.cs | 50 +++++ ...ControlGallery.macOS.Appium.UITests.csproj | 42 +++++ .../PlatformSpecificSampleTest.cs | 16 ++ .../src/UITest.Appium/HelperExtensions.cs | 5 + 33 files changed, 1656 insertions(+), 3 deletions(-) create mode 100644 src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj create mode 100644 src/Compatibility/ControlGallery/test/Android.Appium.UITests/PlatformSpecificSampleTest.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/AppiumServerHelper.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/BaseViewContainerRemote.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ControlGallery.Shared.Appium.UITests.csproj create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/EventViewContainerRemote.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/GalleryQueries.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/IssuesUITest.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/StateViewContainerRemote.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestAttributes.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestContextSetupFixture.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestDevice.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITest.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestBase.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestCategories.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestContextBase.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestExtensions.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestIgnoreAttributes.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewContainerRemote.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewUITest.cs create mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/VisualTestContext.cs create mode 100644 src/Compatibility/ControlGallery/test/Windows.Appium.UITests/AppiumSetup.cs create mode 100644 src/Compatibility/ControlGallery/test/Windows.Appium.UITests/ControlGallery.Windows.Appium.UITests.csproj create mode 100644 src/Compatibility/ControlGallery/test/Windows.Appium.UITests/PlatformSpecificSampleTest.cs create mode 100644 src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj create mode 100644 src/Compatibility/ControlGallery/test/iOS.Appium.UITests/PlatformSpecificSampleTest.cs create mode 100644 src/Compatibility/ControlGallery/test/macOS.Appium.UITests/AppiumSetup.cs create mode 100644 src/Compatibility/ControlGallery/test/macOS.Appium.UITests/ControlGallery.macOS.Appium.UITests.csproj create mode 100644 src/Compatibility/ControlGallery/test/macOS.Appium.UITests/PlatformSpecificSampleTest.cs diff --git a/Microsoft.Maui.sln b/Microsoft.Maui.sln index 3ae8942ce0ec..aaa287f93c27 100644 --- a/Microsoft.Maui.sln +++ b/Microsoft.Maui.sln @@ -249,11 +249,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Xaml.UnitTests.Int EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Sample.UITests", "src\Controls\samples\Controls.Sample.UITests\Controls.Sample.UITests.csproj", "{F39F75DC-671B-4649-8005-1929797B3217}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UITest.Core", "src\TestUtils\src\UITest.Core\UITest.Core.csproj", "{352C2381-1DEC-4487-819D-340D1EA98FBE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UITest.Core", "src\TestUtils\src\UITest.Core\UITest.Core.csproj", "{352C2381-1DEC-4487-819D-340D1EA98FBE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UITest.Appium", "src\TestUtils\src\UITest.Appium\UITest.Appium.csproj", "{8C8CD467-11F9-4A14-8AF3-047B2CFD19A7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UITest.Appium", "src\TestUtils\src\UITest.Appium\UITest.Appium.csproj", "{8C8CD467-11F9-4A14-8AF3-047B2CFD19A7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UITest.NUnit", "src\TestUtils\src\UITest.NUnit\UITest.NUnit.csproj", "{8050448A-E08F-4972-9B47-16042A5DFE82}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UITest.NUnit", "src\TestUtils\src\UITest.NUnit\UITest.NUnit.csproj", "{8050448A-E08F-4972-9B47-16042A5DFE82}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlGallery.Android.Appium.UITests", "src\Compatibility\ControlGallery\test\Android.Appium.UITests\ControlGallery.Android.Appium.UITests.csproj", "{F748974F-A8E4-4659-801C-804B739D6326}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlGallery.iOS.Appium.UITests", "src\Compatibility\ControlGallery\test\iOS.Appium.UITests\ControlGallery.iOS.Appium.UITests.csproj", "{5923B35B-EA24-4B86-A384-9DAF9F2AFD56}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlGallery.macOS.Appium.UITests", "src\Compatibility\ControlGallery\test\macOS.Appium.UITests\ControlGallery.macOS.Appium.UITests.csproj", "{A30BB319-A580-457D-9DDD-C964FF8FA8D9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlGallery.Windows.Appium.UITests", "src\Compatibility\ControlGallery\test\Windows.Appium.UITests\ControlGallery.Windows.Appium.UITests.csproj", "{D3648B58-415C-4C1D-BA73-8200738EBF14}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlGallery.Shared.Appium.UITests", "src\Compatibility\ControlGallery\test\Shared.Appium.UITests\ControlGallery.Shared.Appium.UITests.csproj", "{07D8D4B5-C89D-4BE3-A14A-17668358587C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -644,6 +654,26 @@ Global {8050448A-E08F-4972-9B47-16042A5DFE82}.Debug|Any CPU.Build.0 = Debug|Any CPU {8050448A-E08F-4972-9B47-16042A5DFE82}.Release|Any CPU.ActiveCfg = Release|Any CPU {8050448A-E08F-4972-9B47-16042A5DFE82}.Release|Any CPU.Build.0 = Release|Any CPU + {F748974F-A8E4-4659-801C-804B739D6326}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F748974F-A8E4-4659-801C-804B739D6326}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F748974F-A8E4-4659-801C-804B739D6326}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F748974F-A8E4-4659-801C-804B739D6326}.Release|Any CPU.Build.0 = Release|Any CPU + {5923B35B-EA24-4B86-A384-9DAF9F2AFD56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5923B35B-EA24-4B86-A384-9DAF9F2AFD56}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5923B35B-EA24-4B86-A384-9DAF9F2AFD56}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5923B35B-EA24-4B86-A384-9DAF9F2AFD56}.Release|Any CPU.Build.0 = Release|Any CPU + {A30BB319-A580-457D-9DDD-C964FF8FA8D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A30BB319-A580-457D-9DDD-C964FF8FA8D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A30BB319-A580-457D-9DDD-C964FF8FA8D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A30BB319-A580-457D-9DDD-C964FF8FA8D9}.Release|Any CPU.Build.0 = Release|Any CPU + {D3648B58-415C-4C1D-BA73-8200738EBF14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3648B58-415C-4C1D-BA73-8200738EBF14}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3648B58-415C-4C1D-BA73-8200738EBF14}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3648B58-415C-4C1D-BA73-8200738EBF14}.Release|Any CPU.Build.0 = Release|Any CPU + {07D8D4B5-C89D-4BE3-A14A-17668358587C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {07D8D4B5-C89D-4BE3-A14A-17668358587C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {07D8D4B5-C89D-4BE3-A14A-17668358587C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {07D8D4B5-C89D-4BE3-A14A-17668358587C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -762,6 +792,11 @@ Global {352C2381-1DEC-4487-819D-340D1EA98FBE} = {7AC28763-9C68-4BF9-A1BA-25CBFFD2D15C} {8C8CD467-11F9-4A14-8AF3-047B2CFD19A7} = {7AC28763-9C68-4BF9-A1BA-25CBFFD2D15C} {8050448A-E08F-4972-9B47-16042A5DFE82} = {7AC28763-9C68-4BF9-A1BA-25CBFFD2D15C} + {F748974F-A8E4-4659-801C-804B739D6326} = {DDBA9144-36FC-429E-99E1-2A64825434C1} + {5923B35B-EA24-4B86-A384-9DAF9F2AFD56} = {DDBA9144-36FC-429E-99E1-2A64825434C1} + {A30BB319-A580-457D-9DDD-C964FF8FA8D9} = {DDBA9144-36FC-429E-99E1-2A64825434C1} + {D3648B58-415C-4C1D-BA73-8200738EBF14} = {DDBA9144-36FC-429E-99E1-2A64825434C1} + {07D8D4B5-C89D-4BE3-A14A-17668358587C} = {DDBA9144-36FC-429E-99E1-2A64825434C1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0B8ABEAD-D2B5-4370-A187-62B5ABE4EE50} diff --git a/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj new file mode 100644 index 000000000000..ce69273bfc0c --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj @@ -0,0 +1,46 @@ + + + + $(_MauiDotNetTfm) + enable + enable + true + UITests + + + + $(DefineConstants);ANDROID + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Android.Appium.UITests/PlatformSpecificSampleTest.cs b/src/Compatibility/ControlGallery/test/Android.Appium.UITests/PlatformSpecificSampleTest.cs new file mode 100644 index 000000000000..98435f47f3e8 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Android.Appium.UITests/PlatformSpecificSampleTest.cs @@ -0,0 +1,16 @@ +using NUnit.Framework; + +namespace UITests; + +public class PlatformSpecificSampleTest : UITest +{ + public PlatformSpecificSampleTest(TestDevice testDevice) : base(testDevice) + { + } + + [Test] + public void SampleTest() + { + Driver?.GetScreenshot().SaveAsFile($"{nameof(SampleTest)}.png"); + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/AppiumServerHelper.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/AppiumServerHelper.cs new file mode 100644 index 000000000000..6165a3e9a341 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/AppiumServerHelper.cs @@ -0,0 +1,33 @@ +using OpenQA.Selenium.Appium.Service; + +namespace UITests; + +public static class AppiumServerHelper +{ + static AppiumLocalService? AppiumLocalService; + + public const string DefaultHostAddress = "127.0.0.1"; + public const int DefaultHostPort = 4723; + + public static void StartAppiumLocalServer(string host = DefaultHostAddress, + int port = DefaultHostPort) + { + if (AppiumLocalService is not null) + { + return; + } + + var builder = new AppiumServiceBuilder() + .WithIPAddress(host) + .UsingPort(port); + + // Start the server with the builder + AppiumLocalService = builder.Build(); + AppiumLocalService.Start(); + } + + public static void DisposeAppiumLocalServer() + { + AppiumLocalService?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/BaseViewContainerRemote.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/BaseViewContainerRemote.cs new file mode 100644 index 000000000000..44166439b533 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/BaseViewContainerRemote.cs @@ -0,0 +1,42 @@ +using System.Runtime.CompilerServices; +using UITest.Appium; +using UITest.Core; + +namespace UITests +{ + internal abstract partial class BaseViewContainerRemote + { + protected IApp App { get; private set; } + + public string ViewQuery { get; private set; } + public string EventLabelQuery { get; set; } + + public string StateLabelQuery { get; private set; } + + public string StateButtonQuery { get; private set; } + + protected BaseViewContainerRemote(IApp app, Enum type) + { + App = app; + + ViewQuery = string.Format("{0}VisualElement", type); + EventLabelQuery = string.Format("{0}EventLabel", type); + StateLabelQuery = string.Format("{0}StateLabel", type); + StateButtonQuery = string.Format("{0}StateButton", type); + } + + public virtual void GoTo([CallerMemberName] string callerMemberName = "") + { + App.WaitForElement("TargetViewContainer"); + App.Tap("TargetViewContainer"); + string text = callerMemberName.Replace("_", "", StringComparison.CurrentCultureIgnoreCase) + "VisualElement"; + App.EnterText("TargetViewContainer", text); + App.Tap("GoButton"); + } + + public void TapView() + { + App.Tap(ViewQuery); + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ControlGallery.Shared.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ControlGallery.Shared.Appium.UITests.csproj new file mode 100644 index 000000000000..6b68d869a109 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ControlGallery.Shared.Appium.UITests.csproj @@ -0,0 +1,36 @@ + + + + $(_MauiDotNetTfm) + False + False + UITests + + + + + + + + + + + + + + + + + + $(DefineConstants);ANDROID + + + + $(DefineConstants);IOS + + + + $(DefineConstants);WINDOWS + + + \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/EventViewContainerRemote.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/EventViewContainerRemote.cs new file mode 100644 index 000000000000..a7a571ef20b3 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/EventViewContainerRemote.cs @@ -0,0 +1,19 @@ +using UITest.Appium; +using UITest.Core; + +namespace UITests +{ + internal sealed class EventViewContainerRemote : BaseViewContainerRemote + { + public EventViewContainerRemote(IApp app, Enum type) + : base(app, type) + { + } + + public IUIElement GetEventLabel() + { + App.WaitForElement(EventLabelQuery); + return App.FindElement(EventLabelQuery); + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/GalleryQueries.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/GalleryQueries.cs new file mode 100644 index 000000000000..889551735add --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/GalleryQueries.cs @@ -0,0 +1,30 @@ +namespace UITests +{ + internal static class GalleryQueries + { + public const string ActivityIndicatorGallery = "ActivityIndicator Gallery"; + public const string BoxViewGallery = "BoxView Gallery"; + public const string ButtonGallery = "Button Gallery"; + public const string CheckBoxGallery = "CheckBox Gallery"; + public const string CollectionViewGallery = "CollectionView Gallery"; + public const string CarouselViewGallery = "CarouselView Gallery"; + public const string DatePickerGallery = "DatePicker Gallery"; + public const string EditorGallery = "Editor Gallery"; + public const string EntryGallery = "Entry Gallery"; + public const string FrameGallery = "Frame Gallery"; + public const string ImageGallery = "Image Gallery"; + public const string ImageButtonGallery = "Image Button Gallery"; + public const string LabelGallery = "Label Gallery"; + public const string ListViewGallery = "ListView Gallery"; + public const string PickerGallery = "Picker Gallery"; + public const string ProgressBarGallery = "ProgressBar Gallery"; + public const string RadioButtonGallery = "RadioButton Core Gallery"; + public const string ScrollViewGallery = "ScrollView Gallery"; + public const string SearchBarGallery = "SearchBar Gallery"; + public const string SliderGallery = "Slider Gallery"; + public const string StepperGallery = "Stepper Gallery"; + public const string SwitchGallery = "Switch Gallery"; + public const string TimePickerGallery = "TimePicker Gallery"; + public const string WebViewGallery = "WebView Gallery"; + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/IssuesUITest.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/IssuesUITest.cs new file mode 100644 index 000000000000..b8931ebf2c4e --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/IssuesUITest.cs @@ -0,0 +1,63 @@ +using NUnit.Framework; +using UITest.Appium; + +namespace UITests +{ + public abstract class IssuesUITest : UITest + { + public IssuesUITest(TestDevice device) : base(device) { } + + protected override void FixtureSetup() + { + int retries = 0; + while (true) + { + try + { + base.FixtureSetup(); + NavigateToIssue(Issue); + break; + } + catch (Exception e) + { + TestContext.Error.WriteLine($">>>>> {DateTime.Now} The FixtureSetup threw an exception. Attempt {retries}/{SetupMaxRetries}.{Environment.NewLine}Exception details: {e}"); + if (retries++ < SetupMaxRetries) + { + Reset(); + } + else + { + throw; + } + } + } + } + + protected override void FixtureTeardown() + { + base.FixtureTeardown(); + try + { + this.Back(); + RunningApp.Tap("GoBackToGalleriesButton"); + } + catch (Exception e) + { + var name = TestContext.CurrentContext.Test.MethodName ?? TestContext.CurrentContext.Test.Name; + TestContext.Error.WriteLine($">>>>> {DateTime.Now} The FixtureTeardown threw an exception during {name}.{Environment.NewLine}Exception details: {e}"); + } + } + + public abstract string Issue { get; } + + private void NavigateToIssue(string issue) + { + RunningApp.NavigateToIssues(); + + RunningApp.EnterText("SearchBarGo", issue); + + RunningApp.WaitForElement("SearchButton"); + RunningApp.Tap("SearchButton"); + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/StateViewContainerRemote.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/StateViewContainerRemote.cs new file mode 100644 index 000000000000..fb307473fe37 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/StateViewContainerRemote.cs @@ -0,0 +1,23 @@ +using UITest.Appium; +using UITest.Core; + +namespace UITests +{ + internal sealed class StateViewContainerRemote : BaseViewContainerRemote + { + public StateViewContainerRemote(IApp app, Enum type) + : base(app, type) + { + } + + public void TapStateButton() + { + App.Tap(StateButtonQuery); + } + + public IUIElement GetStateLabel() + { + return App.FindElement(StateLabelQuery); + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestAttributes.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestAttributes.cs new file mode 100644 index 000000000000..39b219bf0846 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestAttributes.cs @@ -0,0 +1,71 @@ +namespace UITests +{ + public static class Test + { + public enum Button + { + Clicked, + Command, + Text, + TextColor, + Font, + BorderWidth, + BorderColor, + BorderRadius, + Image, + Padding, + Pressed, + LineBreakMode + } + + public enum ImageButton + { + Source, + Aspect, + IsOpaque, + IsLoading, + AspectFill, + AspectFit, + Fill, + BorderColor, + CornerRadius, + BorderWidth, + Clicked, + Command, + Image, + Pressed, + Padding + } + + public enum VisualElement + { + IsEnabled, + Navigation, + InputTransparent, + Layout, + X, + Y, + AnchorX, + AnchorY, + TranslationX, + TranslationY, + Width, + Height, + Bounds, + Rotation, + RotationX, + RotationY, + Scale, + IsVisible, + Opacity, + BackgroundColor, + Background, + IsFocused, + Focus, + Unfocus, + Focused, + Unfocused, + Default + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestContextSetupFixture.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestContextSetupFixture.cs new file mode 100644 index 000000000000..b8631bc9026f --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestContextSetupFixture.cs @@ -0,0 +1,17 @@ +using UITest.Appium; + +// SetupFixture runs once for all tests under the same namespace, if placed outside the namespace it will run once for all tests in the assembly +namespace UITests +{ + public class TestContextSetupFixture : UITestContextSetupFixture + { + AppiumServerContext? _appiumServerContext; + + public override void Initialize() + { + _appiumServerContext = new AppiumServerContext(); + _appiumServerContext.CreateAndStartServer(); + _serverContext = _appiumServerContext; + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestDevice.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestDevice.cs new file mode 100644 index 000000000000..bb0f09240ac1 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/TestDevice.cs @@ -0,0 +1,10 @@ +namespace UITests +{ + public enum TestDevice + { + Windows, + Android, + iOS, + Mac + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs new file mode 100644 index 000000000000..d769c154825b --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs @@ -0,0 +1,22 @@ +using NUnit.Framework; +using UITest.Appium; + +namespace UITests +{ + public class Issue10744 : IssuesUITest + { + public Issue10744(TestDevice testDevice) : base(testDevice) + { + } + + public override string Issue => "[Android] WebView.Eval crashes on Android with long string\""; + + [Test] + [Category(UITestCategories.WebView)] + [Category(UITestCategories.RequiresInternetConnection)] + public void WebViewEvalCrashesOnAndroidWithLongString() + { + RunningApp.WaitForElement("navigatedLabel"); + } + } +} diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs new file mode 100644 index 000000000000..68c5459438e0 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs @@ -0,0 +1,30 @@ +using NUnit.Framework; +using UITest.Appium; + +namespace UITests +{ + public class Issue11853 : IssuesUITest + { + const string Run = "Run"; + + public Issue11853(TestDevice testDevice) : base(testDevice) + { + } + + public override string Issue => "[Bug][iOS] Concurrent issue leading to crash in SemaphoreSlim.Release in ObservableItemsSource"; + + [Test] + [Category(UITestCategories.CollectionView)] + public void JustWhalingAwayOnTheCollectionViewWithAddsAndClearsShouldNotCrash() + { + RunningApp.WaitForElement(Run); + RunningApp.Tap(Run); + Task.Delay(5000).Wait(); + RunningApp.Tap(Run); + Task.Delay(5000).Wait(); + + // If we can still find the button, then we didn't crash + RunningApp.WaitForElement(Run); + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITest.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITest.cs new file mode 100644 index 000000000000..8abf9b623951 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITest.cs @@ -0,0 +1,168 @@ +using NUnit.Framework; +using UITest.Core; +using VisualTestUtils; +using VisualTestUtils.MagickNet; + +namespace UITests +{ +#if ANDROID + [TestFixture(TestDevice.Android)] +#elif IOSUITEST + [TestFixture(TestDevice.iOS)] +#elif MACUITEST + [TestFixture(TestDevice.Mac)] +#elif WINTEST + [TestFixture(TestDevice.Windows)] +#else + [TestFixture(TestDevice.iOS)] + [TestFixture(TestDevice.Mac)] + [TestFixture(TestDevice.Windows)] + [TestFixture(TestDevice.Android)] +#endif + public abstract class UITest : UITestBase + { + protected const int SetupMaxRetries = 1; + readonly VisualRegressionTester _visualRegressionTester; + readonly IImageEditorFactory _imageEditorFactory; + readonly VisualTestContext _visualTestContext; + + protected UITest(TestDevice testDevice) : base(testDevice) + { + string? ciArtifactsDirectory = Environment.GetEnvironmentVariable("BUILD_ARTIFACTSTAGINGDIRECTORY"); + if (ciArtifactsDirectory != null) + ciArtifactsDirectory = Path.Combine(ciArtifactsDirectory, "Controls.AppiumTests"); + + string assemblyDirectory = Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory)!; + string projectRootDirectory = Path.GetFullPath(Path.Combine(assemblyDirectory, "..", "..", "..")); + _visualRegressionTester = new VisualRegressionTester(testRootDirectory: projectRootDirectory, + visualComparer: new MagickNetVisualComparer(), + visualDiffGenerator: new MagickNetVisualDiffGenerator(), + ciArtifactsDirectory: ciArtifactsDirectory); + + _imageEditorFactory = new MagickNetImageEditorFactory(); + _visualTestContext = new VisualTestContext(); + } + + public override IConfig GetTestConfig() + { + IConfig config = new Config(); + config.SetProperty("AppId", "com.microsoft.mauicompatibilitygallery"); + + switch (_testDevice) + { + case TestDevice.Android: + config.SetProperty("DeviceName", Environment.GetEnvironmentVariable("DEVICE_SKIN") ?? ""); + config.SetProperty("PlatformVersion", Environment.GetEnvironmentVariable("PLATFORM_VERSION") ?? ""); + config.SetProperty("Udid", Environment.GetEnvironmentVariable("DEVICE_UDID") ?? ""); + break; + case TestDevice.iOS: + config.SetProperty("DeviceName", Environment.GetEnvironmentVariable("DEVICE_NAME") ?? "iPhone 15 Pro"); + config.SetProperty("PlatformVersion", Environment.GetEnvironmentVariable("PLATFORM_VERSION") ?? "17.2"); + break; + } + + return config; + } + + public void VerifyScreenshot(string? name = null) + { + string deviceName = GetTestConfig().GetProperty("DeviceName") ?? string.Empty; + // Remove the XHarness suffix if present + deviceName = deviceName.Replace(" - created by XHarness", "", StringComparison.Ordinal); + + /* + Determine the environmentName, used as the directory name for visual testing snaphots. Here are the rules/conventions: + - Names are lower case, no spaces. + - By default, the name matches the platform (android, ios, windows, or mac). + - Each platform has a default device (or set of devices) - if the snapshot matches the default no suffix is needed (e.g. just ios). + - If tests are run on secondary devices that produce different snapshots, the device name is used as suffix (e.g. ios-iphonex). + - If tests are run on secondary devices with multiple OS versions that produce different snapshots, both device name and os version are + used as a suffix (e.g. ios-iphonex-16_4). We don't have any cases of this today but may eventually. The device name comes first here, + before os version, because most visual testing differences come from different sceen size (a device thing), not OS version differences, + but both can happen. + */ + string environmentName = string.Empty; + + switch (_testDevice) + { + case TestDevice.Android: + if (deviceName == "Nexus 5X") + { + environmentName = "android"; + } + else + { + Assert.Fail($"Android visual tests should be run on an Nexus 5X (API 30) emulator image, but the current device is '{deviceName}'. Follow the steps on the MAUI UI testing wiki."); + } + break; + + case TestDevice.iOS: + if (deviceName == "iPhone Xs (iOS 17.2)") + { + environmentName = "ios"; + } + else if (deviceName == "iPhone X (iOS 16.4)") + { + environmentName = "ios-iphonex"; + } + else + { + Assert.Fail($"iOS visual tests should be run on iPhone Xs (iOS 17.2) or iPhone X (iOS 16.4) simulator images, but the current device is '{deviceName}'. Follow the steps on the MAUI UI testing wiki."); + } + break; + + case TestDevice.Windows: + environmentName = "windows"; + break; + + case TestDevice.Mac: + // For now, ignore visual tests on Mac Catalyst since the Appium screenshot on Mac (unlike Windows) + // is of the entire screen, not just the app. Later when xharness relay support is in place to + // send a message to the MAUI app to get the screenshot, we can use that to just screenshot + // the app. + Assert.Ignore("MacCatalyst isn't supported yet for visual tests"); + break; + + default: + throw new NotImplementedException($"Unknown device type {_testDevice}"); + } + + name ??= TestContext.CurrentContext.Test.MethodName ?? TestContext.CurrentContext.Test.Name; + + byte[] screenshotPngBytes = RunningApp.Screenshot() ?? throw new InvalidOperationException("Failed to get screenshot"); + + var actualImage = new ImageSnapshot(screenshotPngBytes, ImageSnapshotFormat.PNG); + + // For Android and iOS, crop off the OS status bar at the top since it's not part of the + // app itself and contains the time, which always changes. For WinUI, crop off the title + // bar at the top as it varies slightly based on OS theme and is also not part of the app. + int cropFromTop = _testDevice switch + { + TestDevice.Android => 60, + TestDevice.iOS => environmentName == "ios-iphonex" ? 90 : 110, + TestDevice.Windows => 32, + _ => 0, + }; + + // For Android also crop the 3 button nav from the bottom, since it's not part of the + // app itself and the button color can vary (the buttons change clear briefly when tapped) + int cropFromBottom = _testDevice switch + { + TestDevice.Android => 125, + _ => 0, + }; + + if (cropFromTop > 0 || cropFromBottom > 0) + { + IImageEditor imageEditor = _imageEditorFactory.CreateImageEditor(actualImage); + (int width, int height) = imageEditor.GetSize(); + + imageEditor.Crop(0, cropFromTop, width, height - cropFromTop - cropFromBottom); + + actualImage = imageEditor.GetUpdatedImage(); + } + + _visualRegressionTester.VerifyMatchesSnapshot(name!, actualImage, environmentName: environmentName, testContext: _visualTestContext); + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestBase.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestBase.cs new file mode 100644 index 000000000000..936e5a1f7780 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestBase.cs @@ -0,0 +1,175 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using NUnit.Framework; +using NUnit.Framework.Interfaces; +using UITest.Core; + +namespace UITests +{ + public abstract class UITestBase : UITestContextBase + { + public UITestBase(TestDevice testDevice) + : base(testDevice) + { + } + + [SetUp] + public void RecordTestSetup() + { + var name = TestContext.CurrentContext.Test.MethodName ?? TestContext.CurrentContext.Test.Name; + TestContext.Progress.WriteLine($">>>>> {DateTime.Now} {name} Start"); + } + + [TearDown] + public void RecordTestTeardown() + { + var name = TestContext.CurrentContext.Test.MethodName ?? TestContext.CurrentContext.Test.Name; + TestContext.Progress.WriteLine($">>>>> {DateTime.Now} {name} Stop"); + } + + protected virtual void FixtureSetup() + { + var name = TestContext.CurrentContext.Test.MethodName ?? TestContext.CurrentContext.Test.Name; + TestContext.Progress.WriteLine($">>>>> {DateTime.Now} {nameof(FixtureSetup)} for {name}"); + } + + protected virtual void FixtureTeardown() + { + var name = TestContext.CurrentContext.Test.MethodName ?? TestContext.CurrentContext.Test.Name; + TestContext.Progress.WriteLine($">>>>> {DateTime.Now} {nameof(FixtureTeardown)} for {name}"); + } + + [TearDown] + public void UITestBaseTearDown() + { + if (App.AppState == ApplicationState.NotRunning) + { + SaveDeviceDiagnosticInfo(); + + Reset(); + FixtureSetup(); + + // Assert.Fail will immediately exit the test which is desirable as the app is not + // running anymore so we can't capture any UI structures or any screenshots + Assert.Fail("The app was expected to be running still, investigate as possible crash"); + } + + var testOutcome = TestContext.CurrentContext.Result.Outcome; + if (testOutcome == ResultState.Error || + testOutcome == ResultState.Failure) + { + SaveDeviceDiagnosticInfo(); + SaveUIDiagnosticInfo(); + } + } + + [OneTimeSetUp] + public void OneTimeSetup() + { + InitialSetup(UITestContextSetupFixture.ServerContext); + try + { + FixtureSetup(); + } + catch + { + SaveDeviceDiagnosticInfo(); + SaveUIDiagnosticInfo(); + throw; + } + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + var outcome = TestContext.CurrentContext.Result.Outcome; + + // We only care about setup failures as regular test failures will already do logging + if (outcome.Status == ResultState.SetUpFailure.Status && + outcome.Site == ResultState.SetUpFailure.Site) + { + SaveDeviceDiagnosticInfo(); + SaveUIDiagnosticInfo(); + } + + FixtureTeardown(); + } + + void SaveDeviceDiagnosticInfo([CallerMemberName] string? note = null) + { + var types = App.GetLogTypes().ToArray(); + TestContext.Progress.WriteLine($">>>>> {DateTime.Now} Log types: {string.Join(", ", types)}"); + + foreach (var logType in new[] { "logcat" }) + { + if (!types.Contains(logType, StringComparer.InvariantCultureIgnoreCase)) + continue; + + var logsPath = GetGeneratedFilePath($"AppLogs-{logType}.log", note); + if (logsPath is not null) + { + var entries = App.GetLogEntries(logType); + File.WriteAllLines(logsPath, entries); + + AddTestAttachment(logsPath, Path.GetFileName(logsPath)); + } + } + } + + void SaveUIDiagnosticInfo([CallerMemberName] string? note = null) + { + var screenshotPath = GetGeneratedFilePath("ScreenShot.png", note); + if (screenshotPath is not null) + { + _ = RunningApp.Screenshot(screenshotPath); + + AddTestAttachment(screenshotPath, Path.GetFileName(screenshotPath)); + } + + var pageSourcePath = GetGeneratedFilePath("PageSource.txt", note); + if (pageSourcePath is not null) + { + File.WriteAllText(pageSourcePath, App.ElementTree); + + AddTestAttachment(pageSourcePath, Path.GetFileName(pageSourcePath)); + } + } + + string? GetGeneratedFilePath(string filename, string? note = null) + { + // App could be null if UITestContext was not able to connect to the test process (e.g. port already in use etc...) + if (UITestContext is null) + return null; + + if (string.IsNullOrEmpty(note)) + note = "-"; + else + note = $"-{note}-"; + + filename = $"{Path.GetFileNameWithoutExtension(filename)}-{Guid.NewGuid().ToString("N")}{Path.GetExtension(filename)}"; + + var logDir = + Path.GetDirectoryName(Environment.GetEnvironmentVariable("APPIUM_LOG_FILE") ?? + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))!; + + var name = + TestContext.CurrentContext.Test.MethodName ?? + TestContext.CurrentContext.Test.Name; + + return Path.Combine(logDir, $"{name}-{_testDevice}{note}{filename}"); + } + + void AddTestAttachment(string filePath, string? description = null) + { + try + { + TestContext.AddTestAttachment(filePath, description); + } + catch (FileNotFoundException e) when (e.Message == "Test attachment file path could not be found.") + { + // Add the file path to better troubleshoot when these errors occur + throw new FileNotFoundException($"Test attachment file path could not be found: '{filePath}' {description}", e); + } + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestCategories.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestCategories.cs new file mode 100644 index 000000000000..aa8c41a63837 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestCategories.cs @@ -0,0 +1,68 @@ +namespace UITests +{ + internal static class UITestCategories + { + public const string ViewBaseTests = "ViewBaseTests"; + public const string ActionSheet = "ActionSheet"; + public const string ActivityIndicator = "ActivityIndicator"; + public const string Animation = "Animation"; + public const string AutomationId = "AutomationID"; + public const string BoxView = "BoxView"; + public const string Button = "Button"; + public const string CarouselView = "CarouselView"; + public const string Cells = "Cells"; + public const string CheckBox = "CheckBox"; + public const string CollectionView = "CollectionView"; + public const string ContextActions = "ContextActions"; + public const string DatePicker = "DatePicker"; + public const string DragAndDrop = "DragAndDrop"; + public const string DisplayAlert = "DisplayAlert"; + public const string Editor = "Editor"; + public const string Entry = "Entry"; + public const string Frame = "Frame"; + public const string Image = "Image"; + public const string ImageButton = "ImageButton"; + public const string Label = "Label"; + public const string Layout = "Layout"; + public const string ListView = "ListView"; + public const string UwpIgnore = "UwpIgnore"; + public const string LifeCycle = "Lifecycle"; + public const string FlyoutPage = "FlyoutPage"; + public const string Picker = "Picker"; + public const string ProgressBar = "ProgressBar"; + public const string RequiresInternetConnection = "RequiresInternetConnection"; + public const string RootGallery = "RootGallery"; + public const string ScrollView = "ScrollView"; + public const string SearchBar = "SearchBar"; + public const string Slider = "Slider"; + public const string Stepper = "Stepper"; + public const string Switch = "Switch"; + public const string SwipeView = "SwipeView"; + public const string TableView = "TableView"; + public const string TimePicker = "TimePicker"; + public const string ToolbarItem = "ToolbarItem"; + public const string WebView = "WebView"; + public const string Maps = "Maps"; + public const string InputTransparent = "InputTransparent"; + public const string IsEnabled = "IsEnabled"; + public const string Gestures = "Gestures"; + public const string Navigation = "Navigation"; + public const string Effects = "Effects"; + public const string Focus = "Focus"; + public const string ManualReview = "ManualReview"; + public const string Performance = "Performance"; + public const string AppLinks = "AppLinks"; + public const string Shell = "Shell"; + public const string TabbedPage = "TabbedPage"; + public const string CustomHandlers = "CustomHandlers"; + public const string Page = "Page"; + public const string RefreshView = "RefreshView"; + public const string TitleView = "TitleView"; + public const string DisplayPrompt = "DisplayPrompt"; + public const string IndicatorView = "IndicatorView"; + public const string RadioButton = "RadioButton"; + public const string Shape = "Shape"; + public const string Accessibility = "Accessibility"; + public const string Brush = "Brush"; + } +} diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestContextBase.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestContextBase.cs new file mode 100644 index 000000000000..68f0a129e5dd --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestContextBase.cs @@ -0,0 +1,91 @@ +using OpenQA.Selenium.Appium; +using UITest.Appium; +using UITest.Core; + +namespace UITests +{ + public abstract class UITestContextBase + { + static IUIClientContext? UiTestContext; + IServerContext? _context; + protected TestDevice _testDevice; + + public UITestContextBase(TestDevice testDevice) + { + _testDevice = testDevice; + } + + public static IUIClientContext? UITestContext { get { return UiTestContext; } } + + protected AppiumDriver? Driver + { + get + { + if (App is AppiumApp app) + { + return app.Driver; + } + + return null; + } + } + + public TestDevice Device + { + get + { + return UITestContext == null + ? throw new InvalidOperationException($"Call {nameof(InitialSetup)} before accessing the {nameof(Device)} property.") + : UITestContext.Config.GetProperty("TestDevice"); + } + } + + public IApp App + { + get + { + return UITestContext == null + ? throw new InvalidOperationException($"Call {nameof(InitialSetup)} before accessing the {nameof(App)} property.") + : UITestContext.App; + } + } + + internal IApp RunningApp => App; + + public abstract IConfig GetTestConfig(); + + public void InitialSetup(IServerContext context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + InitialSetup(context, false); + } + + public void Reset() + { + if (_context == null) + { + throw new InvalidOperationException($"Cannot {nameof(Reset)} if {nameof(InitialSetup)} has not been called."); + } + + InitialSetup(_context, true); + } + + private void InitialSetup(IServerContext context, bool reset) + { + var testConfig = GetTestConfig(); + testConfig.SetProperty("TestDevice", _testDevice); + + // Check to see if we have a context already from a previous test and re-use it as creating the driver is expensive + if (reset || UiTestContext == null) + { + UiTestContext?.Dispose(); + UiTestContext = context.CreateUIClientContext(testConfig); + } + + if (UiTestContext == null) + { + throw new InvalidOperationException("Failed to get the driver."); + } + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestExtensions.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestExtensions.cs new file mode 100644 index 000000000000..c1b1b1461e67 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestExtensions.cs @@ -0,0 +1,90 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; +using System.Drawing; + +namespace UITests +{ + public static class UITestExtensions + { + const string GoToTestButtonId = "GoToTestButton"; + + public static void Back(this UITestContextBase testBase) + { + if (testBase.Device == TestDevice.Android) + { + var query = testBase.App.Query.ByAccessibilityId("Navigate up").First(); + query.Click(); + } + else if (testBase.Device == TestDevice.iOS || testBase.Device == TestDevice.Mac) + { + // Get the first NavigationBar we can find and the first button in it (the back button), index starts at 1 + var queryBy = testBase.App.Query.ByClass("XCUIElementTypeNavigationBar").First().ByClass("XCUIElementTypeButton").First(); + queryBy.Click(); + } + else + { + testBase.RunningApp.FindElement("NavigationViewBackButton").Click(); + } + } + + public static void NavigateToGallery(this IApp app, string page) + { + app.WaitForElement(GoToTestButtonId, "Timed out waiting for Go To Test button to appear", TimeSpan.FromMinutes(2)); + NavigateTo(app, page); + } + + public static void NavigateTo(this IApp app, string text) + { + app.WaitForElement("SearchBar"); + app.ClearText("SearchBar"); + if (!string.IsNullOrWhiteSpace(text)) + { + app.EnterText("SearchBar", text); + } + app.Tap(GoToTestButtonId); + + app.WaitForNoElement(GoToTestButtonId, "Timed out waiting for Go To Test button to disappear", TimeSpan.FromMinutes(1)); + } + + public static void NavigateToIssues(this IApp app) + { + app.WaitForElement(GoToTestButtonId, "Timed out waiting for Go To Test button to appear", TimeSpan.FromMinutes(2)); + + app.WaitForElement("SearchBar"); + app.ClearText("SearchBar"); + + app.Tap(GoToTestButtonId); + app.WaitForElement("TestCasesIssueList"); + } + + public static void IgnoreIfPlatforms(this UITestBase? test, IEnumerable devices, string? message = null) + { + foreach (var device in devices) + { + test?.IgnoreIfPlatform(device, message); + } + } + + public static void IgnoreIfPlatform(this UITestBase? test, TestDevice device, string? message = null) + { + if (test != null && test.Device == device) + { + if (string.IsNullOrEmpty(message)) + Assert.Ignore(); + else + Assert.Ignore(message); + } + } + + public static int CenterX(this Rectangle rect) + { + return rect.X + rect.Width / 2; + } + + public static int CenterY(this Rectangle rect) + { + return rect.Y + rect.Height / 2; + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestIgnoreAttributes.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestIgnoreAttributes.cs new file mode 100644 index 000000000000..4113ca8aaa5e --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITestIgnoreAttributes.cs @@ -0,0 +1,112 @@ +using NUnit.Framework; + +namespace UITests +{ + public class IgnoredDuringMoveToAppium : IgnoreAttribute + { + public IgnoredDuringMoveToAppium() : base(nameof(IgnoredDuringMoveToAppium)) + { + } + public IgnoredDuringMoveToAppium(string reason) : base(reason) + { + } + } + + public class FailsOnAllPlatforms : IgnoreAttribute + { + public FailsOnAllPlatforms() : base(nameof(FailsOnAndroid)) + { + } + public FailsOnAllPlatforms(string reason) : base(reason) + { + } + } + +#if ANDROID + public class FailsOnAndroid : IgnoreAttribute + { + public FailsOnAndroid() : base(nameof(FailsOnAndroid)) + { + } + public FailsOnAndroid(string reason) : base(reason) + { + } + } +#else + public class FailsOnAndroid : CategoryAttribute + { + public FailsOnAndroid() : base(nameof(FailsOnAndroid)) + { + } + public FailsOnAndroid(string name) : base(name) + { + } + } +#endif + +#if IOS + public class FailsOnIOS : IgnoreAttribute + { + public FailsOnIOS() : base(nameof(FailsOnIOS)) + { + } + public FailsOnIOS(string reason) : base(reason) + { + } + } +#else + public class FailsOnIOS : CategoryAttribute + { + public FailsOnIOS() : base(nameof(FailsOnIOS)) + { + } + public FailsOnIOS(string name) : base(name) + { + } + } +#endif + +#if MACCATALYST + public class FailsOnMac : IgnoreAttribute + { + public FailsOnMac() : base(nameof(FailsOnMac)) + { + } + public FailsOnMac(string reason) : base(reason) + { + } + } +#else + public class FailsOnMac : CategoryAttribute + { + public FailsOnMac() : base(nameof(FailsOnMac)) + { + } + public FailsOnMac(string name) : base(name) + { + } + } +#endif + +#if WINDOWS + public class FailsOnWindows : IgnoreAttribute + { + public FailsOnWindows() : base(nameof(FailsOnWindows)) + { + } + public FailsOnWindows(string reason) : base(reason) + { + } + } +#else + public class FailsOnWindows : CategoryAttribute + { + public FailsOnWindows() : base(nameof(FailsOnWindows)) + { + } + public FailsOnWindows(string name) : base(name) + { + } + } +#endif +} diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewContainerRemote.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewContainerRemote.cs new file mode 100644 index 000000000000..a8e120935237 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewContainerRemote.cs @@ -0,0 +1,10 @@ +using UITest.Core; + +namespace UITests +{ + internal sealed class ViewContainerRemote : BaseViewContainerRemote + { + public ViewContainerRemote(IApp app, Enum type) + : base(app, type) { } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewUITest.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewUITest.cs new file mode 100644 index 000000000000..3ec6405b5a25 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewUITest.cs @@ -0,0 +1,160 @@ +using NUnit.Framework; +using NUnit.Framework.Legacy; +using UITest.Appium; + +namespace UITests +{ + public abstract class ViewUITest : UITest + { + public ViewUITest(TestDevice device) : base(device) { } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + [Category(UITestCategories.ManualReview)] + public virtual void Focus() + { + var remote = new ViewContainerRemote(App, Test.VisualElement.Focus); + remote.GoTo(); + } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + [Category(UITestCategories.ManualReview)] + public virtual void UnFocus() + { + var remote = new ViewContainerRemote(App, Test.VisualElement.Unfocus); + remote.GoTo(); + } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + [Category(UITestCategories.ManualReview)] + public virtual void InputTransparent() + { + var remote = new ViewContainerRemote(App, Test.VisualElement.InputTransparent); + remote.GoTo(); + } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + public virtual void IsEnabled() + { + var remote = new StateViewContainerRemote(App, Test.VisualElement.IsEnabled); + remote.GoTo(); + + var isEnabled = remote.GetStateLabel().GetText(); + ClassicAssert.AreEqual("True", isEnabled); + + remote.TapStateButton(); + + var isDisabled = remote.GetStateLabel().GetText(); + ClassicAssert.AreEqual("False", isDisabled); + } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + [Category(UITestCategories.ManualReview)] + public virtual void Opacity() + { + var remote = new ViewContainerRemote(App, Test.VisualElement.Opacity); + remote.GoTo(); + } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + [Category(UITestCategories.ManualReview)] + public virtual void Rotation() + { + var remote = new ViewContainerRemote(App, Test.VisualElement.Rotation); + remote.GoTo(); + } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + [Category(UITestCategories.ManualReview)] + public virtual void RotationX() + { + var remote = new ViewContainerRemote(App, Test.VisualElement.RotationX); + remote.GoTo(); + } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + [Category(UITestCategories.ManualReview)] + public virtual void RotationY() + { + var remote = new ViewContainerRemote(App, Test.VisualElement.RotationY); + remote.GoTo(); + } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + [Category(UITestCategories.ManualReview)] + public virtual void Scale() + { + var remote = new ViewContainerRemote(App, Test.VisualElement.Scale); + remote.GoTo(); + } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + [Category(UITestCategories.ManualReview)] + public virtual void TranslationX() + { + var remote = new ViewContainerRemote(App, Test.VisualElement.TranslationX); + remote.GoTo(); + } + + [Test] + [Category(UITestCategories.ViewBaseTests)] + [Category(UITestCategories.ManualReview)] + public virtual void TranslationY() + { + var remote = new ViewContainerRemote(App, Test.VisualElement.TranslationY); + remote.GoTo(); + } + + protected override void FixtureSetup() + { + int retries = 0; + while (true) + { + try + { + base.FixtureSetup(); + NavigateToGallery(); + break; + } + catch (Exception e) + { + TestContext.Error.WriteLine($">>>>> {DateTime.Now} The FixtureSetup threw an exception. Attempt {retries}/{SetupMaxRetries}.{Environment.NewLine}Exception details: {e}"); + if (retries++ < SetupMaxRetries) + { + Reset(); + } + else + { + throw; + } + } + } + } + + protected override void FixtureTeardown() + { + base.FixtureTeardown(); + + try + { + this.Back(); + } + catch (Exception e) + { + var name = TestContext.CurrentContext.Test.MethodName ?? TestContext.CurrentContext.Test.Name; + TestContext.Error.WriteLine($">>>>> {DateTime.Now} The FixtureTeardown threw an exception during {name}.{Environment.NewLine}Exception details: {e}"); + } + } + + protected abstract void NavigateToGallery(); + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/VisualTestContext.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/VisualTestContext.cs new file mode 100644 index 000000000000..38598c27c489 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/VisualTestContext.cs @@ -0,0 +1,11 @@ +using NUnit.Framework; +using VisualTestUtils; + +namespace UITests +{ + public class VisualTestContext : ITestContext + { + public void AddTestAttachment(string filePath, string? description = null) => + TestContext.AddTestAttachment(filePath, description); + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/AppiumSetup.cs b/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/AppiumSetup.cs new file mode 100644 index 000000000000..d57d22e782dc --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/AppiumSetup.cs @@ -0,0 +1,46 @@ +/* +using NUnit.Framework; +using OpenQA.Selenium.Appium; +using OpenQA.Selenium.Appium.Windows; + +namespace UITests; + +[SetUpFixture] +public class AppiumSetup +{ + static AppiumDriver? Driver; + + public static AppiumDriver App => Driver ?? throw new NullReferenceException("AppiumDriver is null"); + + [OneTimeSetUp] + public void RunBeforeAnyTests() + { + // If you started an Appium server manually, make sure to comment out the next line + // This line starts a local Appium server for you as part of the test run + AppiumServerHelper.StartAppiumLocalServer(); + + var windowsOptions = new AppiumOptions + { + // Specify windows as the driver, typically don't need to change this + AutomationName = "windows", + // Always Windows for Windows + PlatformName = "Windows", + // The identifier of the deployed application to test + App = "com.microsoft.maui.controls.devicetests_9zz4h110yvjzm!App", + }; + + // Note there are many more options that you can use to influence the app under test according to your needs + + Driver = new WindowsDriver(windowsOptions); + } + + [OneTimeTearDown] + public void RunAfterAnyTests() + { + Driver?.Quit(); + + // If an Appium server was started locally above, make sure we clean it up here + AppiumServerHelper.DisposeAppiumLocalServer(); + } +} +*/ \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/ControlGallery.Windows.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/ControlGallery.Windows.Appium.UITests.csproj new file mode 100644 index 000000000000..dee601942ef2 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/ControlGallery.Windows.Appium.UITests.csproj @@ -0,0 +1,42 @@ + + + + $(_MauiDotNetTfm) + enable + enable + true + UITests + + + + $(DefineConstants);WINDOWS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/PlatformSpecificSampleTest.cs b/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/PlatformSpecificSampleTest.cs new file mode 100644 index 000000000000..98435f47f3e8 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/PlatformSpecificSampleTest.cs @@ -0,0 +1,16 @@ +using NUnit.Framework; + +namespace UITests; + +public class PlatformSpecificSampleTest : UITest +{ + public PlatformSpecificSampleTest(TestDevice testDevice) : base(testDevice) + { + } + + [Test] + public void SampleTest() + { + Driver?.GetScreenshot().SaveAsFile($"{nameof(SampleTest)}.png"); + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj new file mode 100644 index 000000000000..e0c629da9c16 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj @@ -0,0 +1,42 @@ + + + + $(_MauiDotNetTfm) + enable + enable + true + UITests + + + + $(DefineConstants);IOS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/PlatformSpecificSampleTest.cs b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/PlatformSpecificSampleTest.cs new file mode 100644 index 000000000000..98435f47f3e8 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/PlatformSpecificSampleTest.cs @@ -0,0 +1,16 @@ +using NUnit.Framework; + +namespace UITests; + +public class PlatformSpecificSampleTest : UITest +{ + public PlatformSpecificSampleTest(TestDevice testDevice) : base(testDevice) + { + } + + [Test] + public void SampleTest() + { + Driver?.GetScreenshot().SaveAsFile($"{nameof(SampleTest)}.png"); + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/AppiumSetup.cs b/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/AppiumSetup.cs new file mode 100644 index 000000000000..df76d454d535 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/AppiumSetup.cs @@ -0,0 +1,50 @@ +/* +using NUnit.Framework; +using OpenQA.Selenium.Appium; +using OpenQA.Selenium.Appium.Enums; +using OpenQA.Selenium.Appium.Mac; + +namespace UITests; + +[SetUpFixture] +public class AppiumSetup +{ + static AppiumDriver? Driver; + + public static AppiumDriver App => Driver ?? throw new NullReferenceException("AppiumDriver is null"); + + [OneTimeSetUp] + public void RunBeforeAnyTests() + { + // If you started an Appium server manually, make sure to comment out the next line + // This line starts a local Appium server for you as part of the test run + AppiumServerHelper.StartAppiumLocalServer(); + + var macOptions = new AppiumOptions + { + // Specify mac2 as the driver, typically don't need to change this + AutomationName = "mac2", + // Always Mac for Mac + PlatformName = "Mac", + // The full path to the .app file to test + App = "/path/to/MauiApp/bin/Debug/net8.0-maccatalyst/maccatalyst-x64/BasicAppiumSample.app", + }; + + // Setting the Bundle ID is required, else the automation will run on Finder + macOptions.AddAdditionalAppiumOption(IOSMobileCapabilityType.BundleId, "com.companyname.basicappiumsample"); + + // Note there are many more options that you can use to influence the app under test according to your needs + + Driver = new MacDriver(macOptions); + } + + [OneTimeTearDown] + public void RunAfterAnyTests() + { + Driver?.Quit(); + + // If an Appium server was started locally above, make sure we clean it up here + AppiumServerHelper.DisposeAppiumLocalServer(); + } +} +*/ \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/ControlGallery.macOS.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/ControlGallery.macOS.Appium.UITests.csproj new file mode 100644 index 000000000000..02e7d6e2a876 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/ControlGallery.macOS.Appium.UITests.csproj @@ -0,0 +1,42 @@ + + + + $(_MauiDotNetTfm) + enable + enable + true + UITests + + + + $(DefineConstants);MACCATALYST + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/PlatformSpecificSampleTest.cs b/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/PlatformSpecificSampleTest.cs new file mode 100644 index 000000000000..98435f47f3e8 --- /dev/null +++ b/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/PlatformSpecificSampleTest.cs @@ -0,0 +1,16 @@ +using NUnit.Framework; + +namespace UITests; + +public class PlatformSpecificSampleTest : UITest +{ + public PlatformSpecificSampleTest(TestDevice testDevice) : base(testDevice) + { + } + + [Test] + public void SampleTest() + { + Driver?.GetScreenshot().SaveAsFile($"{nameof(SampleTest)}.png"); + } +} \ No newline at end of file diff --git a/src/TestUtils/src/UITest.Appium/HelperExtensions.cs b/src/TestUtils/src/UITest.Appium/HelperExtensions.cs index 37f9663f0719..6be0173554a4 100644 --- a/src/TestUtils/src/UITest.Appium/HelperExtensions.cs +++ b/src/TestUtils/src/UITest.Appium/HelperExtensions.cs @@ -23,6 +23,11 @@ public static void Click(this IApp app, string element) app.FindElement(element).Click(); } + public static void Tap(this IApp app, string element) + { + app.FindElement(element).Click(); + } + public static string? GetText(this IUIElement element) { var response = element.Command.Execute("getText", new Dictionary() From f035badf8e206adeb6fcb8d289f75bd1eb9f4093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Mon, 25 Mar 2024 13:30:56 +0100 Subject: [PATCH 02/27] Focus on Android and iOS (for now) --- Microsoft.Maui.sln | 14 ------ .../Windows.Appium.UITests/AppiumSetup.cs | 46 ----------------- ...ntrolGallery.Windows.Appium.UITests.csproj | 42 ---------------- .../PlatformSpecificSampleTest.cs | 16 ------ .../test/macOS.Appium.UITests/AppiumSetup.cs | 50 ------------------- ...ControlGallery.macOS.Appium.UITests.csproj | 42 ---------------- .../PlatformSpecificSampleTest.cs | 16 ------ 7 files changed, 226 deletions(-) delete mode 100644 src/Compatibility/ControlGallery/test/Windows.Appium.UITests/AppiumSetup.cs delete mode 100644 src/Compatibility/ControlGallery/test/Windows.Appium.UITests/ControlGallery.Windows.Appium.UITests.csproj delete mode 100644 src/Compatibility/ControlGallery/test/Windows.Appium.UITests/PlatformSpecificSampleTest.cs delete mode 100644 src/Compatibility/ControlGallery/test/macOS.Appium.UITests/AppiumSetup.cs delete mode 100644 src/Compatibility/ControlGallery/test/macOS.Appium.UITests/ControlGallery.macOS.Appium.UITests.csproj delete mode 100644 src/Compatibility/ControlGallery/test/macOS.Appium.UITests/PlatformSpecificSampleTest.cs diff --git a/Microsoft.Maui.sln b/Microsoft.Maui.sln index aaa287f93c27..b0454362fc6e 100644 --- a/Microsoft.Maui.sln +++ b/Microsoft.Maui.sln @@ -259,10 +259,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlGallery.Android.Appi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlGallery.iOS.Appium.UITests", "src\Compatibility\ControlGallery\test\iOS.Appium.UITests\ControlGallery.iOS.Appium.UITests.csproj", "{5923B35B-EA24-4B86-A384-9DAF9F2AFD56}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlGallery.macOS.Appium.UITests", "src\Compatibility\ControlGallery\test\macOS.Appium.UITests\ControlGallery.macOS.Appium.UITests.csproj", "{A30BB319-A580-457D-9DDD-C964FF8FA8D9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlGallery.Windows.Appium.UITests", "src\Compatibility\ControlGallery\test\Windows.Appium.UITests\ControlGallery.Windows.Appium.UITests.csproj", "{D3648B58-415C-4C1D-BA73-8200738EBF14}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlGallery.Shared.Appium.UITests", "src\Compatibility\ControlGallery\test\Shared.Appium.UITests\ControlGallery.Shared.Appium.UITests.csproj", "{07D8D4B5-C89D-4BE3-A14A-17668358587C}" EndProject Global @@ -662,14 +658,6 @@ Global {5923B35B-EA24-4B86-A384-9DAF9F2AFD56}.Debug|Any CPU.Build.0 = Debug|Any CPU {5923B35B-EA24-4B86-A384-9DAF9F2AFD56}.Release|Any CPU.ActiveCfg = Release|Any CPU {5923B35B-EA24-4B86-A384-9DAF9F2AFD56}.Release|Any CPU.Build.0 = Release|Any CPU - {A30BB319-A580-457D-9DDD-C964FF8FA8D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A30BB319-A580-457D-9DDD-C964FF8FA8D9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A30BB319-A580-457D-9DDD-C964FF8FA8D9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A30BB319-A580-457D-9DDD-C964FF8FA8D9}.Release|Any CPU.Build.0 = Release|Any CPU - {D3648B58-415C-4C1D-BA73-8200738EBF14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D3648B58-415C-4C1D-BA73-8200738EBF14}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D3648B58-415C-4C1D-BA73-8200738EBF14}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D3648B58-415C-4C1D-BA73-8200738EBF14}.Release|Any CPU.Build.0 = Release|Any CPU {07D8D4B5-C89D-4BE3-A14A-17668358587C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {07D8D4B5-C89D-4BE3-A14A-17668358587C}.Debug|Any CPU.Build.0 = Debug|Any CPU {07D8D4B5-C89D-4BE3-A14A-17668358587C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -794,8 +782,6 @@ Global {8050448A-E08F-4972-9B47-16042A5DFE82} = {7AC28763-9C68-4BF9-A1BA-25CBFFD2D15C} {F748974F-A8E4-4659-801C-804B739D6326} = {DDBA9144-36FC-429E-99E1-2A64825434C1} {5923B35B-EA24-4B86-A384-9DAF9F2AFD56} = {DDBA9144-36FC-429E-99E1-2A64825434C1} - {A30BB319-A580-457D-9DDD-C964FF8FA8D9} = {DDBA9144-36FC-429E-99E1-2A64825434C1} - {D3648B58-415C-4C1D-BA73-8200738EBF14} = {DDBA9144-36FC-429E-99E1-2A64825434C1} {07D8D4B5-C89D-4BE3-A14A-17668358587C} = {DDBA9144-36FC-429E-99E1-2A64825434C1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/AppiumSetup.cs b/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/AppiumSetup.cs deleted file mode 100644 index d57d22e782dc..000000000000 --- a/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/AppiumSetup.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* -using NUnit.Framework; -using OpenQA.Selenium.Appium; -using OpenQA.Selenium.Appium.Windows; - -namespace UITests; - -[SetUpFixture] -public class AppiumSetup -{ - static AppiumDriver? Driver; - - public static AppiumDriver App => Driver ?? throw new NullReferenceException("AppiumDriver is null"); - - [OneTimeSetUp] - public void RunBeforeAnyTests() - { - // If you started an Appium server manually, make sure to comment out the next line - // This line starts a local Appium server for you as part of the test run - AppiumServerHelper.StartAppiumLocalServer(); - - var windowsOptions = new AppiumOptions - { - // Specify windows as the driver, typically don't need to change this - AutomationName = "windows", - // Always Windows for Windows - PlatformName = "Windows", - // The identifier of the deployed application to test - App = "com.microsoft.maui.controls.devicetests_9zz4h110yvjzm!App", - }; - - // Note there are many more options that you can use to influence the app under test according to your needs - - Driver = new WindowsDriver(windowsOptions); - } - - [OneTimeTearDown] - public void RunAfterAnyTests() - { - Driver?.Quit(); - - // If an Appium server was started locally above, make sure we clean it up here - AppiumServerHelper.DisposeAppiumLocalServer(); - } -} -*/ \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/ControlGallery.Windows.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/ControlGallery.Windows.Appium.UITests.csproj deleted file mode 100644 index dee601942ef2..000000000000 --- a/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/ControlGallery.Windows.Appium.UITests.csproj +++ /dev/null @@ -1,42 +0,0 @@ - - - - $(_MauiDotNetTfm) - enable - enable - true - UITests - - - - $(DefineConstants);WINDOWS - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/PlatformSpecificSampleTest.cs b/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/PlatformSpecificSampleTest.cs deleted file mode 100644 index 98435f47f3e8..000000000000 --- a/src/Compatibility/ControlGallery/test/Windows.Appium.UITests/PlatformSpecificSampleTest.cs +++ /dev/null @@ -1,16 +0,0 @@ -using NUnit.Framework; - -namespace UITests; - -public class PlatformSpecificSampleTest : UITest -{ - public PlatformSpecificSampleTest(TestDevice testDevice) : base(testDevice) - { - } - - [Test] - public void SampleTest() - { - Driver?.GetScreenshot().SaveAsFile($"{nameof(SampleTest)}.png"); - } -} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/AppiumSetup.cs b/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/AppiumSetup.cs deleted file mode 100644 index df76d454d535..000000000000 --- a/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/AppiumSetup.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* -using NUnit.Framework; -using OpenQA.Selenium.Appium; -using OpenQA.Selenium.Appium.Enums; -using OpenQA.Selenium.Appium.Mac; - -namespace UITests; - -[SetUpFixture] -public class AppiumSetup -{ - static AppiumDriver? Driver; - - public static AppiumDriver App => Driver ?? throw new NullReferenceException("AppiumDriver is null"); - - [OneTimeSetUp] - public void RunBeforeAnyTests() - { - // If you started an Appium server manually, make sure to comment out the next line - // This line starts a local Appium server for you as part of the test run - AppiumServerHelper.StartAppiumLocalServer(); - - var macOptions = new AppiumOptions - { - // Specify mac2 as the driver, typically don't need to change this - AutomationName = "mac2", - // Always Mac for Mac - PlatformName = "Mac", - // The full path to the .app file to test - App = "/path/to/MauiApp/bin/Debug/net8.0-maccatalyst/maccatalyst-x64/BasicAppiumSample.app", - }; - - // Setting the Bundle ID is required, else the automation will run on Finder - macOptions.AddAdditionalAppiumOption(IOSMobileCapabilityType.BundleId, "com.companyname.basicappiumsample"); - - // Note there are many more options that you can use to influence the app under test according to your needs - - Driver = new MacDriver(macOptions); - } - - [OneTimeTearDown] - public void RunAfterAnyTests() - { - Driver?.Quit(); - - // If an Appium server was started locally above, make sure we clean it up here - AppiumServerHelper.DisposeAppiumLocalServer(); - } -} -*/ \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/ControlGallery.macOS.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/ControlGallery.macOS.Appium.UITests.csproj deleted file mode 100644 index 02e7d6e2a876..000000000000 --- a/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/ControlGallery.macOS.Appium.UITests.csproj +++ /dev/null @@ -1,42 +0,0 @@ - - - - $(_MauiDotNetTfm) - enable - enable - true - UITests - - - - $(DefineConstants);MACCATALYST - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/PlatformSpecificSampleTest.cs b/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/PlatformSpecificSampleTest.cs deleted file mode 100644 index 98435f47f3e8..000000000000 --- a/src/Compatibility/ControlGallery/test/macOS.Appium.UITests/PlatformSpecificSampleTest.cs +++ /dev/null @@ -1,16 +0,0 @@ -using NUnit.Framework; - -namespace UITests; - -public class PlatformSpecificSampleTest : UITest -{ - public PlatformSpecificSampleTest(TestDevice testDevice) : base(testDevice) - { - } - - [Test] - public void SampleTest() - { - Driver?.GetScreenshot().SaveAsFile($"{nameof(SampleTest)}.png"); - } -} \ No newline at end of file From 60ff9e878682305d77edc9b61f2ac890de56d237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Mon, 25 Mar 2024 13:31:59 +0100 Subject: [PATCH 03/27] Added legacy tests to the pipeline --- eng/pipelines/common/ui-tests.yml | 69 +++++++++++++++++++++++++++++++ eng/pipelines/ui-tests.yml | 21 ++++++++++ 2 files changed, 90 insertions(+) diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index 639c8de45dfc..995ed07fa289 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -10,6 +10,7 @@ parameters: provisionatorChannel: 'latest' agentPoolAccessToken: '' runCompatibilityTests: false + runLegacyTests: true projects: - name: name desc: Human Description @@ -22,6 +23,10 @@ parameters: compatibilityAndroidTestProject: /optional/path/to/android.csproj compatibilityiOSTestProject: /optional/path/to/ios.csproj compatibilityiOSApp: /optional/path/to/app.csproj + legacyAndroidApp: /optional/path/to/app.csproj + legacyAndroidTestProject: /optional/path/to/android.csproj + legacyiOSTestProject: /optional/path/to/ios.csproj + legacyiOSApp: /optional/path/to/app.csproj stages: @@ -206,3 +211,67 @@ stages: device: ios-simulator-64_${{ version }} provisionatorChannel: ${{ parameters.provisionatorChannel }} agentPoolAccessToken: ${{ parameters.agentPoolAccessToken }} + - ${{ if eq(parameters.runLegacyTests, true) }}: + - stage: android_legacy_ui_tests + displayName: Android Legacy UITests + dependsOn: [] + jobs: + - ${{ each project in parameters.projects }}: + - ${{ if ne(project.android, '') }}: + - ${{ each api in parameters.androidApiLevels }}: + - ${{ if not(containsValue(project.androidApiLevelsExclude, api)) }}: + - job: android_legacy_ui_tests_${{ project.name }}_${{ api }} + timeoutInMinutes: 240 + workspace: + clean: all + displayName: ${{ coalesce(project.desc, project.name) }} (API ${{ api }}) + pool: ${{ parameters.androidLegacyPool }} + variables: + REQUIRED_XCODE: $(DEVICETESTS_REQUIRED_XCODE) + steps: + - template: ui-tests-steps.yml + parameters: + platform: android + version: ${{ api }} + path: ${{ project.legacyAndroidTestProject }} + app: ${{ project.legacyAndroidApp }} + ${{ if eq(api, 27) }}: + device: android-emulator-32_${{ api }} + ${{ if not(eq(api, 27)) }}: + device: android-emulator-64_${{ api }} + provisionatorChannel: ${{ parameters.provisionatorChannel }} + agentPoolAccessToken: ${{ parameters.agentPoolAccessToken }} + + + - stage: ios_legacy_ui_tests + displayName: iOS Legacy UITests + dependsOn: [] + jobs: + - ${{ each project in parameters.projects }}: + - ${{ if ne(project.ios, '') }}: + - ${{ each version in parameters.iosVersions }}: + - ${{ if not(containsValue(project.iosVersionsExclude, version)) }}: + - job: ios_legacy_ui_tests_${{ project.name }}_${{ replace(version, '.', '_') }} + timeoutInMinutes: 240 + workspace: + clean: all + displayName: ${{ coalesce(project.desc, project.name) }} (v${{ version }}) + pool: ${{ parameters.iosLegacyPool }} + variables: + REQUIRED_XCODE: $(DEVICETESTS_REQUIRED_XCODE) + steps: + - template: ui-tests-steps.yml + parameters: + platform: ios + ${{ if eq(version, 'latest') }}: + version: 16.4 + ${{ if ne(version, 'latest') }}: + version: ${{ version }} + path: ${{ project.legacyiOSTestProject }} + app: ${{ project.legacyiOSApp }} + ${{ if eq(version, 'latest') }}: + device: ios-simulator-64 + ${{ if ne(version, 'latest') }}: + device: ios-simulator-64_${{ version }} + provisionatorChannel: ${{ parameters.provisionatorChannel }} + agentPoolAccessToken: ${{ parameters.agentPoolAccessToken }} \ No newline at end of file diff --git a/eng/pipelines/ui-tests.yml b/eng/pipelines/ui-tests.yml index c2269ed23e66..b0ad680af3af 100644 --- a/eng/pipelines/ui-tests.yml +++ b/eng/pipelines/ui-tests.yml @@ -109,6 +109,23 @@ parameters: - macOS.Name -equals Ventura - macOS.Architecture -equals x64 + - name: androidLegacyPool + type: object + default: + name: $(androidTestsVmPool) + vmImage: $(androidTestsVmImage) + demands: + - macOS.Name -equals Ventura + - macOS.Architecture -equals x64 + + - name: iosLegacyPool + type: object + default: + name: $(iosTestsVmPool) + vmImage: $(iosTestsVmImage) + demands: + - macOS.Name -equals Ventura + - macOS.Architecture -equals x64 resources: repositories: @@ -153,4 +170,8 @@ stages: compatibilityAndroidTestProject: $(System.DefaultWorkingDirectory)/src/Compatibility/ControlGallery/test/Android.UITests/Compatibility.ControlGallery.Android.UITests.csproj compatibilityiOSApp: $(System.DefaultWorkingDirectory)/src/Compatibility/ControlGallery/src/iOS/Compatibility.ControlGallery.iOS.csproj compatibilityiOSTestProject: $(System.DefaultWorkingDirectory)/src/Compatibility/ControlGallery/test/iOS.UITests/Compatibility.ControlGallery.iOS.UITests.csproj + legacyAndroidApp: $(System.DefaultWorkingDirectory)/src/Compatibility/ControlGallery/src/Android/Compatibility.ControlGallery.Android.csproj + legacyAndroidTestProject: $(System.DefaultWorkingDirectory)/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj + legacyiOSApp: $(System.DefaultWorkingDirectory)/src/Compatibility/ControlGallery/src/iOS/Compatibility.ControlGallery.iOS.csproj + legacyiOSTestProject: $(System.DefaultWorkingDirectory)/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj From db7768f4fb6fbe08fe9ee87f281304391a67b11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Mon, 8 Apr 2024 16:32:19 +0200 Subject: [PATCH 04/27] More changes --- .../tests/CustomAttributes/Controls.CustomAttributes.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj b/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj index caa9fefa2c06..f5356ca4fbbb 100644 --- a/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj +++ b/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.0; net8.0 From ce091b58c51314a6c30b00702536a58cda2ebd28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Tue, 9 Apr 2024 15:39:27 +0200 Subject: [PATCH 05/27] More changes --- eng/pipelines/common/ui-tests.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index 995ed07fa289..08f880893878 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -175,7 +175,6 @@ stages: provisionatorChannel: ${{ parameters.provisionatorChannel }} agentPoolAccessToken: ${{ parameters.agentPoolAccessToken }} - - stage: ios_compatibility_ui_tests displayName: iOS Compatibility UITests dependsOn: [] @@ -242,7 +241,6 @@ stages: provisionatorChannel: ${{ parameters.provisionatorChannel }} agentPoolAccessToken: ${{ parameters.agentPoolAccessToken }} - - stage: ios_legacy_ui_tests displayName: iOS Legacy UITests dependsOn: [] From bec656ff849e7b735efa9a7293499f3e4a7f4a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Wed, 10 Apr 2024 09:44:26 +0200 Subject: [PATCH 06/27] Fixed build --- eng/pipelines/common/ui-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index 08f880893878..ec5b1f7ad38f 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -5,6 +5,8 @@ parameters: macosPool: { } androidCompatibilityPool: { } iosCompatibilityPool: { } + androidLegacyPool: { } + iosLegacyPool: { } androidApiLevels: [ 30 ] iosVersions: [ 'latest' ] provisionatorChannel: 'latest' From 715a6116589c6f1fe69a30f92621b77c7b4789fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Wed, 10 Apr 2024 12:07:48 +0200 Subject: [PATCH 07/27] Created ui-tests-legacy-steps.yml --- .../common/ui-tests-legacy-steps.yml | 145 ++++++++++++++++++ eng/pipelines/common/ui-tests.yml | 4 +- 2 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 eng/pipelines/common/ui-tests-legacy-steps.yml diff --git a/eng/pipelines/common/ui-tests-legacy-steps.yml b/eng/pipelines/common/ui-tests-legacy-steps.yml new file mode 100644 index 000000000000..40123cbf9e68 --- /dev/null +++ b/eng/pipelines/common/ui-tests-legacy-steps.yml @@ -0,0 +1,145 @@ +parameters: + platform: '' # [ android, ios, windows, catalyst ] + path: '' # path to csproj + device: '' # the xharness device to use + cakeArgs: '' # additional cake args + app: '' #path to app to test + version: '' #the iOS version' + provisionatorChannel: 'latest' + agentPoolAccessToken: '' + configuration : "Release" + +steps: + - ${{ if eq(parameters.platform, 'ios')}}: + - bash: | + chmod +x $(System.DefaultWorkingDirectory)/eng/scripts/clean-bot.sh + $(System.DefaultWorkingDirectory)/eng/scripts/clean-bot.sh + displayName: 'Clean bot' + continueOnError: true + timeoutInMinutes: 60 + + - template: provision.yml + parameters: + skipProvisioning: ${{ eq(parameters.platform, 'windows') }} + skipAndroidSdks: ${{ ne(parameters.platform, 'android') }} + skipXcode: ${{ or(eq(parameters.platform, 'android'), eq(parameters.platform, 'windows')) }} + provisionatorChannel: ${{ parameters.provisionatorChannel }} + + - task: PowerShell@2 + condition: ne('${{ parameters.platform }}' , 'windows') + inputs: + targetType: 'inline' + script: | + defaults write -g NSAutomaticCapitalizationEnabled -bool false + defaults write -g NSAutomaticTextCompletionEnabled -bool false + defaults write -g NSAutomaticSpellingCorrectionEnabled -bool false + displayName: "Modify defaults" + continueOnError: true + + # AzDO hosted agents default to 1024x768; set something bigger for Windows UI tests + - task: ScreenResolutionUtility@1 + condition: eq('${{ parameters.platform }}' , 'windows') + inputs: + displaySettings: 'specific' + width: '1920' + height: '1080' + displayName: "Set screen resolution" + + - task: UseNode@1 + inputs: + version: "20.3.1" + displayName: "Install node" + + - bash: | + echo "##[group]Running ls -al $(npm root -g)" + ls -al $(npm root -g) + echo "##[endgroup]" + + echo "##[group]Running ls -al $(npm root -g)/appium" + ls -al $(npm root -g)/appium + echo "##[endgroup]" + + echo "##[group]Running ls -al $(npm root -g)/.appium-????????" + ls -al $(npm root -g)/.appium-???????? + echo "##[endgroup]" + + echo "##[group]Running ls -al $(npm root -g)/appium-doctor" + ls -al $(npm root -g)/appium-doctor + echo "##[endgroup]" + + echo "##[group]Running ls -al $(npm root -g)/.appium-doctor-????????" + ls -al $(npm root -g)/.appium-doctor-???????? + echo "##[endgroup]" + + echo "##[group]Running ps aux" + ps aux + echo "##[endgroup]" + displayName: "Debugging output" + continueOnError: true + condition: startsWith(variables['Agent.Name'], 'XAMBOT') + + # Clean up any leftover cached folders of appium and appium-doctor node modules + - bash: | + rm -rf $(npm root -g)/.appium-???????? + rm -rf $(npm root -g)/.appium-doctor-???????? + displayName: "Delete temp .appium-???????? and .appium-doctor-???????? folders" + continueOnError: true + + - pwsh: ./eng/scripts/appium-install.ps1 + displayName: "Install Appium (Drivers)" + continueOnError: false + retryCountOnTaskFailure: 1 + + - pwsh: ./build.ps1 --target=dotnet --configuration="${{ parameters.configuration }}" --verbosity=diagnostic + displayName: 'Install .NET' + retryCountOnTaskFailure: 2 + env: + DOTNET_TOKEN: $(dotnetbuilds-internal-container-read-token) + PRIVATE_BUILD: $(PrivateBuild) + + - pwsh: echo "##vso[task.prependpath]$(DotNet.Dir)" + displayName: 'Add .NET to PATH' + + - pwsh: ./build.ps1 --target=dotnet-buildtasks --configuration="${{ parameters.configuration }}" + displayName: 'Build the MSBuild Tasks' + + - pwsh: ./build.ps1 --target=dotnet-samples --configuration="${{ parameters.configuration }}" --${{ parameters.platform }} --verbosity=diagnostic --usenuget=false + displayName: 'Build the samples' + + - bash: | + if [ -f "$HOME/Library/Logs/CoreSimulator/*" ]; then rm -r $HOME/Library/Logs/CoreSimulator/*; fi + if [ -f "$HOME/Library/Logs/DiagnosticReports/*" ]; then rm -r $HOME/Library/Logs/DiagnosticReports/*; fi + displayName: Delete Old Simulator Logs + condition: ${{ eq(parameters.platform, 'ios') }} + continueOnError: true + + - pwsh: ./build.ps1 -Script eng/devices/${{ parameters.platform }}.cake --target=uitest --project="${{ parameters.path }}" --appproject="${{ parameters.app }}" --device="${{ parameters.device }}" --apiversion="${{ parameters.version }}" --configuration="${{ parameters.configuration }}" --results="$(TestResultsDirectory)" --binlog="$(LogDirectory)" ${{ parameters.cakeArgs }} --verbosity=diagnostic + displayName: $(Agent.JobName) + ${{ if ne(parameters.platform, 'android')}}: + retryCountOnTaskFailure: 1 + + - bash: | + suffix=$(date +%Y%m%d%H%M%S) + zip -9r "$(LogDirectory)/CoreSimulatorLog_${suffix}.zip" "$HOME/Library/Logs/CoreSimulator/" + zip -9r "$(LogDirectory)/DiagnosticReports_${suffix}.zip" "$HOME/Library/Logs/DiagnosticReports/" + displayName: Zip Simulator Logs + condition: ${{ eq(parameters.platform, 'ios') }} + continueOnError: true + + - task: PublishTestResults@2 + displayName: Publish the $(System.PhaseName) test results + condition: always() + inputs: + testResultsFormat: VSTest + testResultsFiles: '$(TestResultsDirectory)/*.trx' + testRunTitle: '$(System.PhaseName)' + failTaskOnFailedTests: true + + - task: PublishBuildArtifacts@1 + condition: always() + displayName: publish artifacts + + # This must always be placed as the last step in the job + - template: agent-rebooter/mac.v1.yml@yaml-templates + parameters: + AgentPoolAccessToken: ${{ parameters.agentPoolAccessToken }} diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index ec5b1f7ad38f..603cb25801da 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -230,7 +230,7 @@ stages: variables: REQUIRED_XCODE: $(DEVICETESTS_REQUIRED_XCODE) steps: - - template: ui-tests-steps.yml + - template: ui-tests-legacy-steps.yml parameters: platform: android version: ${{ api }} @@ -260,7 +260,7 @@ stages: variables: REQUIRED_XCODE: $(DEVICETESTS_REQUIRED_XCODE) steps: - - template: ui-tests-steps.yml + - template: ui-tests-legacy-steps.yml parameters: platform: ios ${{ if eq(version, 'latest') }}: From 656a11c3291ed5e16344a9350e7101aae256e6c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Wed, 10 Apr 2024 12:32:30 +0200 Subject: [PATCH 08/27] More changes --- eng/pipelines/common/ui-tests-legacy-steps.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/common/ui-tests-legacy-steps.yml b/eng/pipelines/common/ui-tests-legacy-steps.yml index 40123cbf9e68..45f154de55a4 100644 --- a/eng/pipelines/common/ui-tests-legacy-steps.yml +++ b/eng/pipelines/common/ui-tests-legacy-steps.yml @@ -7,6 +7,7 @@ parameters: version: '' #the iOS version' provisionatorChannel: 'latest' agentPoolAccessToken: '' + targetSample: "dotnet-legacy-controlgallery" configuration : "Release" steps: @@ -103,8 +104,8 @@ steps: - pwsh: ./build.ps1 --target=dotnet-buildtasks --configuration="${{ parameters.configuration }}" displayName: 'Build the MSBuild Tasks' - - pwsh: ./build.ps1 --target=dotnet-samples --configuration="${{ parameters.configuration }}" --${{ parameters.platform }} --verbosity=diagnostic --usenuget=false - displayName: 'Build the samples' + - pwsh: ./build.ps1 --target=${{ parameters.targetSample }} --configuration="${{ parameters.configuration }}" --${{ parameters.platform }} --verbosity=diagnostic --usenuget=false + displayName: 'Build the Legacy ControlGallery' - bash: | if [ -f "$HOME/Library/Logs/CoreSimulator/*" ]; then rm -r $HOME/Library/Logs/CoreSimulator/*; fi From d749eea1712c65b1302695b68069e40322ce2e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Wed, 10 Apr 2024 12:35:54 +0200 Subject: [PATCH 09/27] More changes --- eng/pipelines/common/ui-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index 603cb25801da..8865a818f0fa 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -236,6 +236,7 @@ stages: version: ${{ api }} path: ${{ project.legacyAndroidTestProject }} app: ${{ project.legacyAndroidApp }} + targetSample: "dotnet-legacy-controlgallery-android" ${{ if eq(api, 27) }}: device: android-emulator-32_${{ api }} ${{ if not(eq(api, 27)) }}: @@ -269,6 +270,7 @@ stages: version: ${{ version }} path: ${{ project.legacyiOSTestProject }} app: ${{ project.legacyiOSApp }} + targetSample: "dotnet-legacy-controlgallery-ios" ${{ if eq(version, 'latest') }}: device: ios-simulator-64 ${{ if ne(version, 'latest') }}: From 668332b009bbb00f661a878d30c2b0f39064bea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Wed, 10 Apr 2024 14:36:55 +0200 Subject: [PATCH 10/27] Updated Appium to RC7 --- .../ControlGallery.Android.Appium.UITests.csproj | 2 +- .../iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj index ce69273bfc0c..329257401c13 100644 --- a/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj +++ b/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj index e0c629da9c16..0f75fbb7bdaf 100644 --- a/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj +++ b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj @@ -13,7 +13,7 @@ - + From 781621c6bbe8c2daf0bc492f3aa7015311a30182 Mon Sep 17 00:00:00 2001 From: Gerald Versluis Date: Wed, 10 Apr 2024 17:08:40 +0200 Subject: [PATCH 11/27] Update ui-tests.yml --- eng/pipelines/ui-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eng/pipelines/ui-tests.yml b/eng/pipelines/ui-tests.yml index b0ad680af3af..46d4de15c7de 100644 --- a/eng/pipelines/ui-tests.yml +++ b/eng/pipelines/ui-tests.yml @@ -145,6 +145,8 @@ stages: macosPool: ${{ parameters.macosPool }} androidCompatibilityPool: ${{ parameters.androidCompatibilityPool }} iosCompatibilityPool: ${{ parameters.iosCompatibilityPool }} + iosLegacyPool: ${{ parameters.iosLegacyPool }} + androidLegacyPool: ${{ parameters.androidLegacyPool }} agentPoolAccessToken: $(AgentPoolAccessToken) ${{ if or(parameters.BuildEverything, and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'devdiv'))) }}: androidApiLevels: [ 30 ] From 5b5c7e9d06edbc9cdb26fdcba1562dde2cb4c33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 11 Apr 2024 08:50:29 +0200 Subject: [PATCH 12/27] Fixed test on Android --- .../ControlGallery/src/Android/FormsAppCompatActivity.cs | 2 ++ .../test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Compatibility/ControlGallery/src/Android/FormsAppCompatActivity.cs b/src/Compatibility/ControlGallery/src/Android/FormsAppCompatActivity.cs index 2ec5edd2c0f9..0d555a4dbc19 100644 --- a/src/Compatibility/ControlGallery/src/Android/FormsAppCompatActivity.cs +++ b/src/Compatibility/ControlGallery/src/Android/FormsAppCompatActivity.cs @@ -4,6 +4,7 @@ using Android.Content; using Android.Content.PM; using Android.OS; +using Android.Runtime; using Java.Interop; using Microsoft.Maui.Controls.Compatibility.Platform.Android; using Microsoft.Maui.Controls.ControlGallery; @@ -28,6 +29,7 @@ namespace Microsoft.Maui.Controls.ControlGallery.Android DataScheme = "http", DataHost = App.AppName, DataPathPrefix = "/gallery/" ) ] + [Register("com.microsoft.mauicompatibilitygallery.MainActivity")] public partial class Activity1 : MauiAppCompatActivity { App App => Microsoft.Maui.Controls.Application.Current as App; diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs index d769c154825b..df92af07cd4a 100644 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs @@ -9,11 +9,12 @@ public Issue10744(TestDevice testDevice) : base(testDevice) { } - public override string Issue => "[Android] WebView.Eval crashes on Android with long string\""; + public override string Issue => "[Android] WebView.Eval crashes on Android with long string"; [Test] [Category(UITestCategories.WebView)] [Category(UITestCategories.RequiresInternetConnection)] + [FailsOnAndroid] public void WebViewEvalCrashesOnAndroidWithLongString() { RunningApp.WaitForElement("navigatedLabel"); From a4b5f6d672fe8fe02eb16d0b24c3287b756d2d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 11 Apr 2024 08:52:51 +0200 Subject: [PATCH 13/27] Fixed test --- src/Controls/tests/UITests/Tests/Issues/Issue19509.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Controls/tests/UITests/Tests/Issues/Issue19509.cs b/src/Controls/tests/UITests/Tests/Issues/Issue19509.cs index 403f54373b73..1c80ca2fa80c 100644 --- a/src/Controls/tests/UITests/Tests/Issues/Issue19509.cs +++ b/src/Controls/tests/UITests/Tests/Issues/Issue19509.cs @@ -13,13 +13,15 @@ public Issue19509(TestDevice device) : base(device) public override string Issue => "Entry TextColor property not working when the Text value is bound after some time"; [Test] - public void Issue19509Test() + public async Task Issue19509Test() { App.WaitForElement("WaitForStubControl"); // 1. Click a button to update the text App.Click("button"); + await Task.Delay(1000); // Wait to complete Ripple Effect animation. + // 2. Verify that the Entry TextColor is correct (Green). VerifyScreenshot(); } From c7a5fb581bdca74c7552702a4b6f4602fbbf1044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 11 Apr 2024 08:59:04 +0200 Subject: [PATCH 14/27] More changes --- .../test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs index df92af07cd4a..456224707bd8 100644 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs @@ -17,6 +17,8 @@ public Issue10744(TestDevice testDevice) : base(testDevice) [FailsOnAndroid] public void WebViewEvalCrashesOnAndroidWithLongString() { + this.IgnoreIfPlatforms([TestDevice.iOS]); + RunningApp.WaitForElement("navigatedLabel"); } } From 0ebe13560c489c0819beadbf48ae1c4036bc1b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 11 Apr 2024 09:06:42 +0200 Subject: [PATCH 15/27] More changes --- .../ControlGallery/test/Shared.Appium.UITests/UITest.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITest.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITest.cs index 8abf9b623951..f129ab406969 100644 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITest.cs +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/UITest.cs @@ -56,8 +56,9 @@ public override IConfig GetTestConfig() config.SetProperty("Udid", Environment.GetEnvironmentVariable("DEVICE_UDID") ?? ""); break; case TestDevice.iOS: - config.SetProperty("DeviceName", Environment.GetEnvironmentVariable("DEVICE_NAME") ?? "iPhone 15 Pro"); - config.SetProperty("PlatformVersion", Environment.GetEnvironmentVariable("PLATFORM_VERSION") ?? "17.2"); + config.SetProperty("DeviceName", Environment.GetEnvironmentVariable("DEVICE_NAME") ?? "iPhone X"); + config.SetProperty("PlatformVersion", Environment.GetEnvironmentVariable("PLATFORM_VERSION") ?? "17.0"); + config.SetProperty("Udid", Environment.GetEnvironmentVariable("DEVICE_UDID") ?? ""); break; } From fa49de78278f5d50f2416807152d87fa0ed4863a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 11 Apr 2024 09:19:30 +0200 Subject: [PATCH 16/27] Updated snapshot --- .../snapshots/android/Issue19509Test.png | Bin 52656 -> 52812 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/Controls/tests/UITests/snapshots/android/Issue19509Test.png b/src/Controls/tests/UITests/snapshots/android/Issue19509Test.png index f1205a7e5a525ca861b385684740130d1713d8ff..aea052fb4a09868fbdf591347f8598dff7e72bac 100644 GIT binary patch delta 14897 zcmZv@c|4SB_&=_r<+PC`Wj&>mgd|&IIThx#aXMm>tw@q}Y{LwmI!@VVib~n0s8mA8 zK1`i3_944rMh1f!rm@Um%*^k8&gb*`{qg;N|0#N&dFH;a`?}uO`~AM2K4nU`XGuT0 z`|Gw{2ls8<{OepvFdqli7uDFVOAr@np^WMJKYeCwwEXX%ef8(>kF3w^`scB=l@(?G zfRidY2ARG3VKHQ>;N)7^#!U?y&a{sIrs1&b%&w!(ueLk;Z1?if^6$~PocVfHbR~pj zj7!U$?6Dvcw#Wu&PK<;E2H4I=W>Z(QBF64-QHlz17w7mf>doh?Sy0Xqq<-dt}@Qe?ac%3B9KD!|WK z8KhYBPvftKg@uiT)BJgyGU}8FSL{}oYe%$zZ-|eNn0n!@6m9ULfJ7p7d~?~dW8bb2 zR%eH>a-^zfIGa9_cca7gL$OYOLPKaY{rycHpAL4p?JGCg2X2lH^z79K z+ZCr=GlIHao+S2-H)>=Ls&xicnRP&wc@|7fWuZ>7Av9KPjUQ4!v) z4r|S&*EyU0GSo-NGp$BzcyR9|J?mxA9j;zI^{a{=>E~HKdVca&K|z5ht-`;=cc5q* z8Y=VNpQFwf55hcL=rKsCqa=d^3jiNC*FI>3b0k&|(%`K-= z1g-pt^JH~q^S;W)d>Wdg&yUtJD`){wTdkF_UTmH)C=@K$u#4J+!r^>7;y!b1=#yv9 zn%KqUoI3R=UZWzDVkt&PtuxgFm+Hb_x!e6NI2aU~dpXm{OTBU`7`v>XpkRobseG!9 znzDYl-{5wGPk#1Z4J5u@eC?w<*+LCu9!Hi{42jtL%p!tnZGuB5MExn7p_!h1yY@_D zy{6>-@^v^tCnC`(W_`tEsp}kbGTj|tA1$1!lbhaw<8xXNXH5e}sy4fq-R{V!TJCo) zqaoEIZ)IU;-w$;^$jHcun0$&F??iBuQ zbmPnpbqlk^#6%Cl{3ve$YSW|C3Fx%(nUi1#Lt6WUcZWaw>=ZY%#4gtneh9%kq$n?M z&Ow4HGDP^zb!QCtTHSP)ec@EC7Mh-@2VxH(sc81~kg#(=V02!FC!R!zmg8|q93nd^mgX0vB0-C1iIipP!} zyFRk2t)=y^(#``?QkQ=_Z*}Hs%l3`S1H}QjtKOW!l9CwFTExU-SLs~6w-n@y-lcnHQmGh7UyfGunz{r1iPl03MFsnPE z!>R1{Wh;)kb;#GhH|d9S29N6M;z9VYfq!0K8z6VudVwR!_xS$$der24) z*sJF@GS>TWVPOGYbhvQPlaL}C^D|c8qamKNIu9ybC4BHEFTpM<_cE)w0y&>q-(UZ= z(|qA7^c)JqO{#hMQhh*ezZvj7@Ly_0gHuQ%K-~Nw&l*-SaPc@||E2g`KJJDsL zLQvGBPl}@a9Z)FNCcJV$)d97bl^>gF#T}W(lvr7deT=pK$^{#8XgZ}k6=WspWq0q) z!{x~UHkg1rJdE-;oMTpJb&ZuNa|82aPW_wV0V znvoW}<5a`1(WynRUmpVCpuoz(1@HsyEJdNQSL(lrslVcFpVXE)Oy4YQd#2MyzXwVm z(P<&%9FahG6crR2UwG&2r&>y)o}{NEt*x!iL`yyX8I`#P^Mdt7Y9KE(XMB9z)-=!< zb@}pT_#&E>jkzr`LXS6W4kMsLYilQ&hD?R`VHsLqs>{ zWlRG*dB4GtH33)s>C>mYHFmK#ITJp!MWV#)!o`cspWkG;Mufb>V5jj$ooweph#px4xh^2Y`E{DrQ7Z4)<*-%QOUJv)mO|SJh&&7#rRg52~ucE@mNZ zWkS<(zlKfn^iNjt$B)P1lBiZaE?qm zj_c23Lz`t(_T>{}u<9 zo&+1cRuy!UZx90zNjW)2_disDHiFc^xvrfhZ)h<`h0sZnI^tK_Ag-&6EJ|_AazXqc zZfpCd?Rz{%k?9(P8*ZYJA;~T%EcEYt z!~_|ATXVNBAS929=KIjwOD|G4;SXPY*1)5vGbX6$p0}6Lf>8`h1UZWs zgpn2}c1}8g^+q9GP`{blR#058WIPgd4unnv^dpb%Tx;}@S9(~hjPTwD>G9ko-9+O0 zgyv8@skOCrGwlIrVTQGf0}c;mREPbiq~F^&&-I8uoBOoP_7#+^>VY#JoPLuOC!?wa zcS=RKhy!=;-i0#+4Yli2_DqO{%j|)1-iavt+wgJjIOeX3{GbAv-#pKa6CE%I>B+in5ETeSO4j* zSG+fR(OUh5&Wg3+b9Y1I@-SRFdYwn1fS{EYoSqvj$?M2t*0g^1>G4=!;SJe}b)d?T z-RW*vpV**Eu)&o^y_mdR z+Hn8OsgJ`bJ@R_+2%4fAN${R%e%xId$Qbm`AWsQa1972iZxsFX}pR^WT4L zFfzWrzInO12m3!d$vamDKq)X%!z=|5F!YZHis8fYg7w87{ipYiAM1n)czfY;TY?RsY3sSQ+d+gIA<&iZ5=gO&6Z#lUw zs-b^AdGh2I!`aQP-Y#&kW;UiaQx;nJrXRhwWJ8$lgYa$;cIM4qs!kE4>kHs$3G|S! z$xQfzD9fe4wU;u>Mqa(v$<`RzzikzJbfR>)KqJmq@dD1>`S9Vxg-Vyh0js5OhRVto z$G5ARoW^c>3(&FCl$Ev8O^De83I(PTDz`;FS4kC3yT2F5@0?E zmnE$-kl@w!%$k~G&V)cM&3>2OIO-$pl{-CKUHI-@bM3~vA&VrKUjVeutEoBdhMOyo z5G@ZN!emNE3R25M8!Mu_zcbQ6kB9(Z=Gl>92y;RJvIJ0%qycBwM;m1>{dXdVK0HF2 zvGoed1Ahe%^Zase!;t#lZ#xaR0Roy69x)G9*-$M3ZYO63)MyDkuRA#OO$1G@A@!7N zH%DEZeRc(MdSG%EWpCdz)i$c2sA&BBxG{$ErW{dM?T%``IBGp1=`<9WBqb$fs=VO! z+S^Uey)H*0>(z$KKH@)-$rTwPy;qQ4_dQ2z!b-x}{eIr24=DP8;lo`!wXz2ygRqej zWHtEsCX?k}duAqM{dPsbvYmaqt3b>C?dOOZ+bdVDsGu9Jc~cs}ij;aWB5EZ*sp!j8Zg`JQ~pE^sNUk8gYHnQ*<=-SGhZ4_GbL3rD#XGr0WA znR`(#XlpuovUBVA;iHdmy+vJVn92IBE!lc+>OrS4k*qH&i(KX#ist$r7sv6B7ie&} z#f4M7#C;(`{@f5g`WS)Pbxt;g8a*GvYt|q%q#nMwaCT{Fric056QA%Nvd^D#O~j5= zp?8X9CIa%W*J`{FuGcMgA|i>}ON#;^vTw82?Vg`_HDuof1m*b0vd%=1yp2V!wd0M7 z?#YI}{h>a8yfg6m{+bg!BZrHUC?+^#COR7ifa1bV)=3eum&7bqtY=D`~ zh*Y}5|3J=PU88Q!9q%nO`~hn`Z-IxU3lLt)tgH}QKU#$j*oJ(xkl#VuJLz^%2x9I3 zDS6}*V_4&DH37Xi)p5nyIWv3rpVKVvn{>BUiyYIC+exqLA&D49K|ko9P5{0&)?@L5 z2%e|wShJ`)^uc_6^emnn2au&LbHEQ&PUMD?!$6+$#*_4nuzgSQk7`}Db#&&sy1n3g zl9adaJszKCd-{D#Lccn8`apWz1L@~*$l{b79UYsL14$)zti6GQpAN(T0qWZ9Og7Bb5H(kQ*U{-xb!P_}zI()~H+gU5EAz!-AKB61~$4 z%UwBMVgHCk<$YOe$l{RVD=j^#hMj&D z!4T31#!P2{mtjQ0%?+3P=lod?A93h(m)|o9ETEh4sMsUZk56OCUYYim}&s;kfB2pxCc?@dxD)*Z$gp&{=l(|S^1`J(?GA@ zXCWM-8sXlL#mDP7S4@m{nqMCojX@4G3oGe~lWpn9209VriE3@$DRi#z^XcoWnRRbD zgnC6Jj}X0l?HrnSUduMEym&Df(rckTTggV`ey+=Zz6UG(O!l+O_{-HbyW@?V9JlHIO1t>%xDVRtK?WkXJeYB+ z$f@jYqlRZ#{#|R1>H=+8o5yJjd4}8cH{9XRwbh>eA91~{X12T!CQ0SKD8E7I(*ZgV z1bd4&UcoTJ0DsNEe6Fk&;XgY7dcMApPHqp-yY}g2ceV&L*hyCy^41@Gw6EQk=Ft*%t35rqueY}$Q9-+umg0K7;_$NF&buAaMsI2Zi8VCtkJhK! zWrA4Po&mNOl2IS+3@tMn666g(InA|M{>aUE(Ar7e20HJHiaHU|n@xWH zs*>&3nPocE)eOL{id|HDJ?!-@kSCEy*{RO#Ou;JfxK0WqCR?BCi0|V7{qSf>Jv=lw zb;Qxv7Bw1(K?A>Ns;;{l6thxPM>kSETc9$zIp-~O+>K;1U(2oET%7X4zY+ zG6VKo_F7c3n)zvN{2a*m{)qwLV`!>HPCVuSz$-&ckfuO)o|wBa8aCh>iFn!Z9-65> zdvt>R>QUS5JP0xHJof;o=nRnX2#{YmvJjMt7`O`)qnP>bruh{_X)&;hcSE2yLX0$f zpX+;Om@l(|b<$x`FA)nfN1b4siH^qx^v=Zt1UNVYl8V&0$ae>1h}1T23tG}SBD)_8 zHnu?5xb)(r7cu>@GS0|v@R4!q+j`*ekp?0?YZm$MYei~P4+Vfrb9yGxz-t(Pmxph~ z$@oQZ-0`5Q7Ku%o_j->fl8bMn1ED%YIQlYmOJ32y9!s{jGdHXi!PfTW-Fr&}q@@wn z*Kh+hUCVv@_J~^4&#$nEU7s>0CjfK2>}zQ-AyLPr>QlGzL745{>CTM+lo&Br9X}|v zIfQxgU0T*`m!0|Y)mTc6H#MgUoIl*Q+r>J9o!7H*^H8;B{le4Y1{C-tc1Gw&E*OGiBL2c)Jt%e%X8}>(y=@A;R8NAYosZZOvAL0TU=MwSb zK?lAe(;^zXcQ^2u6u?cMc__o{4yfZ zVQ?ZXD_h1y#YQ5xm2})Kgn2PIrg0Eiyt`-?HAGeqZa(0@O$GL&5!rWvoK3OaQ46F& z6~t>&&fNK%+$c`in=N+qAFVOe3;OIOlL89VTOG8_S3|#cr2@`Z1!f>j;Eee%E&jJn za0Ekh^0p?gT1>Iq4hwkZD`T;+1lVj@01&w$8$;hOU_cO^%<7zxR@qlWZOPm6=)HY@ zQzR=pU94|&7x5CmI%uzd*_nPxbbt_tf{AQUF*5}uny29sFkT%XYD{2c7vkFK>w zj>T@O@WITL4>SRERZG*fgB@}kfK{=1N5Srr%cvH$t}Fupr2S4Hdg~l-%eH`Y;N+jz z%`2m=pFhgQ>v{MLc^LId5@P!q-;2R)>fZU!qpG%T+GQOE@% z1a^R7(B?OhQN?bs$4U|cZy-@nFQ_X4rrThNClc)caJ@vtrGPw#6)vCw1Xz`L=R_WX zKM!C$JLYu^05UjKoTHpVsFJP(R|1TOM2lz-z-LNswWN}+?9n7f1?Qb}@x6PuG^C0a zVs-cD*jIF;0;+);!!LssE}UX;m_e)HdQ7#yfSc`fUjgc>gF_?e&7MHz?L6BD*yRhs zk%Irt*uVa49_X+4Gqy?ICkGaFy8@E01~qf7J}MG06>Zp)hm{(J9tkKTpbxgW@$n#} z2=2QGq!}Ln8F&`3^X>tBPFQhmrlrDk5ERtN_{^@x#zr(flGO+-PvyzUN%)5Uq$ePO zNwBK{OHaTJ{_BO^Xh3ez{Z5c~*b4gwkY#8v6=>=(W~j*Fia#tA21aWGT>sC02Xm#y z&TNDyFgzpEf5M)hfGiR1v~APsH7e)?^_gLudsq--6i6Q#OI-w$qNMG5q#&X$%`G2P zJo?|Qnhm+uNx&P!b6{Two|(XdI&gO5DaH`J8DaR!bTnGn>ne8a>+qB>!OW*tByUqX z9eU?d_G!cI1geG54|uR89n=m$&d0Y{uAG5mb;LGnAK<+yun!3PUjnQO=!N+t#%cbb zC$og2*5=WeVocu$=cvAClNE4s{YI)vS}xXLmj9{!oh5Hl(@ctl7UAg~>_t&vJ_Rr? z2MiBxlfCChs?nfEj7`6~!fFl7-O%j9%G<0HdVuYd}1;s79U2k<@I*g@rafW7A=;m7hN# z-YePYqk+HrXUEE%K5DV>n9#61;7+W2b-nb~dHQ?HFm@O)zF-@)dqS=S|EG(KilS@i z6?gzSq;*l-@#CGP%UG+11kIemTc6wd==+R-jk?mHX(2~mpVTW010{Yj>Dxzm5~;rO zWy`kR#7~|c*(n(v>*oeh;gG{qc#d$Hv zZH1sGbq`ztLrV|w`fACIuYZ#?#2x#Ai|+zT;y;{zrsJFos6mUyXxN$3_j&(5h!Mk1 zIGmFdRg4v=ZzG>j`-igXYQTQGnXGJFG(>TUzXy>)0y|PIPk47`{YR4x^_szE_7&H! z-L1$Y0b|d`t_~g-sD$-i;j!H%HA9nOtT}tkin9YSKkUqSR^h_wJVL-?Lpj{;V*+4| z$O5d+zvjYd^J5K9FrehsGDJn)g1upzK^WjEM!rix)ZnL^=$6A!dc$So(I?h;V1m8> z>Qe&{0*hLX~_wVuByi!!dsF{TMIu9fOOusxkp)Au)&f&h7 zL8c$E%gGXzxPlQ5Jg$k<|KLuJ;Q<@z)H7XIC4!|mB9Ger<-W8hoSDFHGZZ#WjK#|0 zVP%b$hy)bSx}RctbAg71F*ZLd_yRm>oF_}fwmU&p>&ZpTyh(2YUIOzmQq3o{Gs&mt zZ6mZ*GwTsXCMx5d%f8)ZSBk`JUEyAaLE>6#`)I&!(cI}cL2l! zjAxI0G>7M;pw^NAT9$tG(E)=y^x)07M)1_G@jFRp&GC3gz{f>v%Sk`J#ZltrG+U4mf>vYo5-rv@D?mO`tjBemNpePb(tcBNaW9SxP%Zv|euRfa}h;DtN1-FiOz;*>^}_VMw76H6bAT~@&4gz=kAUp5xgs+AwQ@?NVNP6y&zZ~plGEoyg`?sdu`Rpj8Y z6Rfj9VU!j-0g%rEQx_dK(Y8ToPhWVxPoX?i9z5B~+3hMP#{eB&5V;==^ufSf4K|lt zYr|oW4t8<%!Gwl%v2w1U(76&8eq~;KE`xloh(YfY)B=XISslvYc4E5&!ytjZE=pS&j5>_a~atll>Z{@w4 ztr+kh6@O--L!SUjBvbo37;r@X`qL**tU#|F2bR=bsOPMTBdYtTgK}{3NS9J}NyqFZfJyKucOMuppGl|v z?}kyc3^J6T^{`YA09?-j4ek4)*e~51f;CUg4wdEKM0ahj4*A|rv?RaGH{7r%!@vK2 z3pM-f5Xb_f^Zxev)L(SU6y~MeAwW;d2$oB)WG7vZ?7TDdaHley!13{Q@;PrJ8fC}6 z+{_HSu@I8~2o?~2r7|raGS8QTAJ-^ z8$tj6eWQ$&l+R&D@>UAs9ycY$!GqVmufnd!Gtr_LK#$rg%k+gCFRlH3~3X)2AZsFw-B}yWu zB*-^~Eq^#!&D-+<3_>1w-09fp@xJl=pw_mJy5yURHrCzn=k{mj}PyKo#4RZp4SLFy$}SU=_eK z2ML2zKg9h!Rkv%^ZwpZ1=6j-eQG12F$?#2PQ-^CE*pw6p$?>kp{?aWo#Q?v(d<6fN z#;Z(+-niENBK14v`AMI%QFBC#%u(^Yp=DB>I#g4D+Aj6-+^;H9DqZ*-LyfnWGIoK< zA-}h&12a-)$AG>LaT7}2%ry><_YE)-EzS5>QI@YSITgDNc_zj0>ms|Oig!!>9w%oa zW%4pR{5zWWYOympzG4%e>JoN-hnmT62f^!Owqtpt$AYA!RQ>>I@bZR?X@sAO0qZA+ zKT3`~QNevTJqzX`BAF)?DJj)6V^UJvZucj@=QUEJ&1yv}Jr`^HIx!e`vh<|B)bGe3 z1%)(Tl{{o>BK0zsBuP$VR#lgQN5ZT&IY)75Ng+FlrC_&h#dkQ45a z6}3L{+~lUqj%kM8g^L&9n@BbMj)+@4$N()g7g&2u7Hwt-8mVpy(p&h1`1qUWwy>h- zd(>+Wg`*sRf5;9jB1l$vmoL*LpI*f>b3>@fo>MAnc}STgpr;2b{E?*k`MHRtgu}cf ziCgcqsPc8e02hiDGlvdi3&K&2#zkT@=iT7YgeZ#t;iBi#yC1l~-u@=wAco;wB06U_ zMedOLWGN2^L&a#h%Y;3uX=T+AAN#POwa=G%5n4>xXYO&0KCpAY*$Ejnl5rh)pEq36*ny_?(iTi(8^Vu=ZN3F7RzV?4#@1}OtYrHs%G30y-#~XbcyPQVKPTmBfx9-;>wHw z(4yKRUsa(59TIsJHE>H}6x050MW83~kEPJNhihX7!~_3E+@9G!G`F2m3`^1wX3Tiu8XnqpPmJ#KQfzpm zNYYD8O3Jh2maeS3$C#+OtzW9hD$^5QeX@sZemi(dYmwPzdUH}51x4v9rvNi}^oFW# z-B>ibWtH23GqWU#`y<94H_FMuYhM`y;GwN&YPq(go3ueBY*YjhsG4R%1GB7p#7D*e z8FzVoN$5_nsB6pp_z|_4UW}{@{|LU42$c!=K(rw*`@(9 zJPh$!u* zX12~J^lC*TiRt5|>>8a#F!Q+1=cQ4L;wSZr{K6ykKDvx@SdvMaWWQ!M&N?e} zUI9JiF0n6j7tRhFdwO@OsK<&!tqBm{ODt`mbjM0 zxJ%~COUg=59^~V9tu9e?6BawM7?qHTc8+gMDAQkut|-;@=*tGFQLC`9%g0+@BnSUn z)jdRE+7Oa&o{PIxNsPGdlV8jLT(^{P@xq1S@{js?HVswX8f7#)T_^gu0Qwlgd&*(n zmtJdpa$f#4rzE_0O$S1ItuOUk60yNwg|Eo zWU==z%xUWbDn?!&bf#$xG|w@Ky1tlq63gd2#^9FXe{6!(PJ4=Cf<~#HV*L=0rrz`2 z1t{u1x^H0BFevwW{;2OSQg@W^OH0)}zB~z8SikxF`OxN_)9RDXm4;P*9GbGR0>?rx zN;1PMx!6g#0@eKE@4e6DH_4v#NTg~Bwe8N#G5ygs83-$VC2an+ z>a}ti+$E_`WcaL=-+yQ&w|jHxUU1bcaUM%FaRWu8o2torQB$61-j>c*8|~iy{-%ub zz@}m2e(Tl#!bo-qe@4@qs%AcnMMch9=2RTj@n`s)bghoz`W+)Af_E3blmv(#%HYgE z1?)0`0N?2A7e~4!WEt$fURX6v%@3OBywdF`S`)9HdIU7h;LrTWO0;0zQ6)M3PxN?v zg$cV?esR2M-1}LRMD!!&vaK6-t%ag^Jm_lw_EYXFmW%|T%;tJdx?S%>=c%5?io`Qz z>PcUvw@ip=jHrc$i1nE_aM8q>>q-qm#H}!AstBMxj&=cZ1nv{Y19hXbTy9V8abX0F zuUaUsf19jk3epnU*a`gYg!uTK+zDdp$(!rXBd{}zb2Y_DbO^iG*bVD-`9A;}bw|>w z-kWj5t*yPxNGmUFtGPvPWLc7+*JP$DPeS5kKZWT`@;;+ekeJtlYO-8!tE^r7A^m%* zi}j{^(!&q2AxM9S4JbN?;aEzpoKc75ZzPk`ohvmn|L<>J-M<1%6I)&Xcz4RnLzGKpv zIq6V*yOI&|9o+_e;~;nD1&5)!xIDi*&z+_ z@^)gPn`!zPox~>1<3p|vPcgOCrU)^vTRM`!;)-WAx>NNeBKJlpikYPUj_zQ4y+C__ zEAq}#(NvYN?CoP>D3V)plg^e^7MWe;^H-mqHQOv@@(AYSKVz19+#7Pt%jM*N>ERP4 zf})LzYL@;csX}Wm>T6$|c#vdLy>!(W5FTcn@yIYI8lHfHZ2bm^xDr7Hk_@0GI@*3N zg=mi_9Bu=Rm5-ZGLb*fQwb6ZV6dN9JE$hCP+U!tPvRvy=_XLb7!!@53ViT`o?rRez zmQOd_rx3jKaX(tr=bpsG=R6f~y-ZP(=5okq@fnF0!cw76h#0{G#fvuQ;oiw35bI03 zSeL&whiwJFPraUC*gNfVDdcnkM2$SZ%DkN1~Iu^y~z-4-M zepprG;m#CO$ROXE3tsClECjSivQo@QkW_Q2d1q}+e>`95B(Hn!QIxFu(p|_0++2mX zd%@%vXamphwM{IYyv|}SRMp*bqOBF%7>gNw)JPn4aNtd(PL@_)M-LwCuM^q2MD#J5rWOk4 zusft)d(XsT!k3R7dOxAFP95(FxJbO(GOS=s#L+skx> z(_Ju_NLDsDdBo1l1S`-@$_ylHa@odyBYW&1^V)-W^V#@mMsZ+;jJ<3$O2v@<>A9ij z-AkaOW5qtb4L~07iW#d{MwZ!(@)_2M0vp4}*(Mg~np@)V(4x??$yW~uKzBR+3WT^_r$<-YU{N$JvRIjcd9z#<%Cew`>}!kiUuRF`%2jDuj#^#CRE=g?gh!1i0ipRqYZ_R1HDkZJu= ziX@(4z8+D=uI4;=${R^kWV&u4q`(3;8VXlC9gz{0{ z(6VI%trc)<0vC=wOZJUiQG&_G=QGB|c$dK{FsI^tNk z(KRxXcx^Y_C(p^Kr5oor!|`$74)u+(2LcE80mdqQ<@#T{HR9BJrx)veF%D*H4XG;( z3177G&C{-&%^GiahJ?lZo9%gX8! zc3|ZiKo_{w|I2Lau{+B7?>@%@y$HxV-O%E#UCzGP&GV`^uhe@vAIJTeytX{cE?g6j z*k1+WK}jYhZ9By*Bns%l7H(fU$R57rAih;&ByQIZdkds4%&vRz`Hb@N?S6}i&R9!j_%%BHT zCrkX9dtmRx3Hp5Qd`Z46u#o;OAr6J-REO_79U6ox{sr78loP)2*9`jn4R~(*ODn}8uVwtf_RY+LT@DibL-5Np!#+{KCQjmJ$-%-Vz;iujwxUJvccj^-a z8(ZMT`tY@OhxCReE%{okA-Mj>Ao!7KfO7o~ytGsI^Q7v9RcB{sTAy}_Wi^m*<29Mw_zZI# zxB|Xv`t1c|ViGe?5&Ghzwdqh$=)DCU+IWsoEgAR_hk(0w#3*3ocm%jp<;#V{B+u!t zulix%|1p`LcH+_P6`%k4`OE)$nNwx@wM}wmzg2lk?@c_ITTy_51NhQh3_aRvr)TUv z@iI-OLq$RV#8rKx(*~zbpES@uapLre6Jw+Oo@ti9!Q< delta 14743 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 From b8c6711b3f46357e0b08bd61e41d7b54f6826bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 11 Apr 2024 10:29:34 +0200 Subject: [PATCH 17/27] More fixes --- .../test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs index 456224707bd8..99d1bcf420b9 100644 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs @@ -3,7 +3,7 @@ namespace UITests { - public class Issue10744 : IssuesUITest + public class Issue10744 : IssuesUITest { public Issue10744(TestDevice testDevice) : base(testDevice) { @@ -15,11 +15,10 @@ public Issue10744(TestDevice testDevice) : base(testDevice) [Category(UITestCategories.WebView)] [Category(UITestCategories.RequiresInternetConnection)] [FailsOnAndroid] + [FailsOnIOS] public void WebViewEvalCrashesOnAndroidWithLongString() { - this.IgnoreIfPlatforms([TestDevice.iOS]); - RunningApp.WaitForElement("navigatedLabel"); } } -} +} \ No newline at end of file From 381ae62094e47a1d33479f7af63f59633721c73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 11 Apr 2024 13:57:26 +0200 Subject: [PATCH 18/27] Clean code --- .../BaseViewContainerRemote.cs | 42 ----- .../EventViewContainerRemote.cs | 19 --- .../StateViewContainerRemote.cs | 23 --- .../ViewContainerRemote.cs | 10 -- .../test/Shared.Appium.UITests/ViewUITest.cs | 160 ------------------ 5 files changed, 254 deletions(-) delete mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/BaseViewContainerRemote.cs delete mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/EventViewContainerRemote.cs delete mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/StateViewContainerRemote.cs delete mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewContainerRemote.cs delete mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewUITest.cs diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/BaseViewContainerRemote.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/BaseViewContainerRemote.cs deleted file mode 100644 index 44166439b533..000000000000 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/BaseViewContainerRemote.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Runtime.CompilerServices; -using UITest.Appium; -using UITest.Core; - -namespace UITests -{ - internal abstract partial class BaseViewContainerRemote - { - protected IApp App { get; private set; } - - public string ViewQuery { get; private set; } - public string EventLabelQuery { get; set; } - - public string StateLabelQuery { get; private set; } - - public string StateButtonQuery { get; private set; } - - protected BaseViewContainerRemote(IApp app, Enum type) - { - App = app; - - ViewQuery = string.Format("{0}VisualElement", type); - EventLabelQuery = string.Format("{0}EventLabel", type); - StateLabelQuery = string.Format("{0}StateLabel", type); - StateButtonQuery = string.Format("{0}StateButton", type); - } - - public virtual void GoTo([CallerMemberName] string callerMemberName = "") - { - App.WaitForElement("TargetViewContainer"); - App.Tap("TargetViewContainer"); - string text = callerMemberName.Replace("_", "", StringComparison.CurrentCultureIgnoreCase) + "VisualElement"; - App.EnterText("TargetViewContainer", text); - App.Tap("GoButton"); - } - - public void TapView() - { - App.Tap(ViewQuery); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/EventViewContainerRemote.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/EventViewContainerRemote.cs deleted file mode 100644 index a7a571ef20b3..000000000000 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/EventViewContainerRemote.cs +++ /dev/null @@ -1,19 +0,0 @@ -using UITest.Appium; -using UITest.Core; - -namespace UITests -{ - internal sealed class EventViewContainerRemote : BaseViewContainerRemote - { - public EventViewContainerRemote(IApp app, Enum type) - : base(app, type) - { - } - - public IUIElement GetEventLabel() - { - App.WaitForElement(EventLabelQuery); - return App.FindElement(EventLabelQuery); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/StateViewContainerRemote.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/StateViewContainerRemote.cs deleted file mode 100644 index fb307473fe37..000000000000 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/StateViewContainerRemote.cs +++ /dev/null @@ -1,23 +0,0 @@ -using UITest.Appium; -using UITest.Core; - -namespace UITests -{ - internal sealed class StateViewContainerRemote : BaseViewContainerRemote - { - public StateViewContainerRemote(IApp app, Enum type) - : base(app, type) - { - } - - public void TapStateButton() - { - App.Tap(StateButtonQuery); - } - - public IUIElement GetStateLabel() - { - return App.FindElement(StateLabelQuery); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewContainerRemote.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewContainerRemote.cs deleted file mode 100644 index a8e120935237..000000000000 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewContainerRemote.cs +++ /dev/null @@ -1,10 +0,0 @@ -using UITest.Core; - -namespace UITests -{ - internal sealed class ViewContainerRemote : BaseViewContainerRemote - { - public ViewContainerRemote(IApp app, Enum type) - : base(app, type) { } - } -} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewUITest.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewUITest.cs deleted file mode 100644 index 3ec6405b5a25..000000000000 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ViewUITest.cs +++ /dev/null @@ -1,160 +0,0 @@ -using NUnit.Framework; -using NUnit.Framework.Legacy; -using UITest.Appium; - -namespace UITests -{ - public abstract class ViewUITest : UITest - { - public ViewUITest(TestDevice device) : base(device) { } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - [Category(UITestCategories.ManualReview)] - public virtual void Focus() - { - var remote = new ViewContainerRemote(App, Test.VisualElement.Focus); - remote.GoTo(); - } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - [Category(UITestCategories.ManualReview)] - public virtual void UnFocus() - { - var remote = new ViewContainerRemote(App, Test.VisualElement.Unfocus); - remote.GoTo(); - } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - [Category(UITestCategories.ManualReview)] - public virtual void InputTransparent() - { - var remote = new ViewContainerRemote(App, Test.VisualElement.InputTransparent); - remote.GoTo(); - } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - public virtual void IsEnabled() - { - var remote = new StateViewContainerRemote(App, Test.VisualElement.IsEnabled); - remote.GoTo(); - - var isEnabled = remote.GetStateLabel().GetText(); - ClassicAssert.AreEqual("True", isEnabled); - - remote.TapStateButton(); - - var isDisabled = remote.GetStateLabel().GetText(); - ClassicAssert.AreEqual("False", isDisabled); - } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - [Category(UITestCategories.ManualReview)] - public virtual void Opacity() - { - var remote = new ViewContainerRemote(App, Test.VisualElement.Opacity); - remote.GoTo(); - } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - [Category(UITestCategories.ManualReview)] - public virtual void Rotation() - { - var remote = new ViewContainerRemote(App, Test.VisualElement.Rotation); - remote.GoTo(); - } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - [Category(UITestCategories.ManualReview)] - public virtual void RotationX() - { - var remote = new ViewContainerRemote(App, Test.VisualElement.RotationX); - remote.GoTo(); - } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - [Category(UITestCategories.ManualReview)] - public virtual void RotationY() - { - var remote = new ViewContainerRemote(App, Test.VisualElement.RotationY); - remote.GoTo(); - } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - [Category(UITestCategories.ManualReview)] - public virtual void Scale() - { - var remote = new ViewContainerRemote(App, Test.VisualElement.Scale); - remote.GoTo(); - } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - [Category(UITestCategories.ManualReview)] - public virtual void TranslationX() - { - var remote = new ViewContainerRemote(App, Test.VisualElement.TranslationX); - remote.GoTo(); - } - - [Test] - [Category(UITestCategories.ViewBaseTests)] - [Category(UITestCategories.ManualReview)] - public virtual void TranslationY() - { - var remote = new ViewContainerRemote(App, Test.VisualElement.TranslationY); - remote.GoTo(); - } - - protected override void FixtureSetup() - { - int retries = 0; - while (true) - { - try - { - base.FixtureSetup(); - NavigateToGallery(); - break; - } - catch (Exception e) - { - TestContext.Error.WriteLine($">>>>> {DateTime.Now} The FixtureSetup threw an exception. Attempt {retries}/{SetupMaxRetries}.{Environment.NewLine}Exception details: {e}"); - if (retries++ < SetupMaxRetries) - { - Reset(); - } - else - { - throw; - } - } - } - } - - protected override void FixtureTeardown() - { - base.FixtureTeardown(); - - try - { - this.Back(); - } - catch (Exception e) - { - var name = TestContext.CurrentContext.Test.MethodName ?? TestContext.CurrentContext.Test.Name; - TestContext.Error.WriteLine($">>>>> {DateTime.Now} The FixtureTeardown threw an exception during {name}.{Environment.NewLine}Exception details: {e}"); - } - } - - protected abstract void NavigateToGallery(); - } -} \ No newline at end of file From e63d0a06d37a055d0902f93f31c421df48067168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 11 Apr 2024 13:57:38 +0200 Subject: [PATCH 19/27] Run test only on iOS --- .../test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs index 68c5459438e0..424bdea0be32 100644 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs @@ -17,6 +17,8 @@ public Issue11853(TestDevice testDevice) : base(testDevice) [Category(UITestCategories.CollectionView)] public void JustWhalingAwayOnTheCollectionViewWithAddsAndClearsShouldNotCrash() { + this.IgnoreIfPlatforms([[TestDevice.Android, TestDevice.Mac, TestDevice.Windows]); + RunningApp.WaitForElement(Run); RunningApp.Tap(Run); Task.Delay(5000).Wait(); From ffb72b71a6c97ee3ccaebdd495e1c24f046b4603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 11 Apr 2024 14:00:14 +0200 Subject: [PATCH 20/27] Added pending constant --- .../iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj index 0f75fbb7bdaf..d87cd4e63602 100644 --- a/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj +++ b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj @@ -9,7 +9,7 @@ - $(DefineConstants);IOS + $(DefineConstants);IOS; IOSUITEST From 4967b79c624108501545cc93fde04d6a82220a19 Mon Sep 17 00:00:00 2001 From: Gerald Versluis Date: Thu, 11 Apr 2024 14:46:57 +0200 Subject: [PATCH 21/27] Fix build error --- .../test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs index 424bdea0be32..24b9af1d34cc 100644 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs @@ -17,7 +17,7 @@ public Issue11853(TestDevice testDevice) : base(testDevice) [Category(UITestCategories.CollectionView)] public void JustWhalingAwayOnTheCollectionViewWithAddsAndClearsShouldNotCrash() { - this.IgnoreIfPlatforms([[TestDevice.Android, TestDevice.Mac, TestDevice.Windows]); + this.IgnoreIfPlatforms([TestDevice.Android, TestDevice.Mac, TestDevice.Windows]); RunningApp.WaitForElement(Run); RunningApp.Tap(Run); From b5e9b40cde86ca7fd1efb39c9a162154b1eb085c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 11 Apr 2024 13:37:04 +0200 Subject: [PATCH 22/27] More changes --- .../Tests/Issues/Issue10744.cs | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100644 src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs deleted file mode 100644 index 99d1bcf420b9..000000000000 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue10744.cs +++ /dev/null @@ -1,24 +0,0 @@ -using NUnit.Framework; -using UITest.Appium; - -namespace UITests -{ - public class Issue10744 : IssuesUITest - { - public Issue10744(TestDevice testDevice) : base(testDevice) - { - } - - public override string Issue => "[Android] WebView.Eval crashes on Android with long string"; - - [Test] - [Category(UITestCategories.WebView)] - [Category(UITestCategories.RequiresInternetConnection)] - [FailsOnAndroid] - [FailsOnIOS] - public void WebViewEvalCrashesOnAndroidWithLongString() - { - RunningApp.WaitForElement("navigatedLabel"); - } - } -} \ No newline at end of file From ff2fa4fa84605c466c111e1338bd72b84cf81179 Mon Sep 17 00:00:00 2001 From: Gerald Versluis Date: Fri, 12 Apr 2024 08:57:50 +0200 Subject: [PATCH 23/27] Update ControlGallery.iOS.Appium.UITests.csproj --- .../iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj index d87cd4e63602..55611e16459a 100644 --- a/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj +++ b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj @@ -9,7 +9,7 @@ - $(DefineConstants);IOS; IOSUITEST + $(DefineConstants);IOS;IOSUITEST From b94a42176e9da446fc3d8aab60f6b53f9d194657 Mon Sep 17 00:00:00 2001 From: Gerald Versluis Date: Fri, 12 Apr 2024 13:13:10 +0200 Subject: [PATCH 24/27] Update ControlGallery.Shared.Appium.UITests.csproj --- .../ControlGallery.Shared.Appium.UITests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ControlGallery.Shared.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ControlGallery.Shared.Appium.UITests.csproj index 6b68d869a109..5c5de9da4a79 100644 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ControlGallery.Shared.Appium.UITests.csproj +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/ControlGallery.Shared.Appium.UITests.csproj @@ -26,11 +26,11 @@ - $(DefineConstants);IOS + $(DefineConstants);IOS;IOSUITEST - $(DefineConstants);WINDOWS + $(DefineConstants);WINDOWS;WINTEST \ No newline at end of file From 7d2852a27899b61f3fa683e6fc9b648efc083096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Fri, 12 Apr 2024 13:50:25 +0200 Subject: [PATCH 25/27] Trying to run only on iOS --- .../test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs index 24b9af1d34cc..1aa0f8291d18 100644 --- a/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs +++ b/src/Compatibility/ControlGallery/test/Shared.Appium.UITests/Tests/Issues/Issue11853.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +#if IOS +using NUnit.Framework; using UITest.Appium; namespace UITests @@ -17,8 +18,6 @@ public Issue11853(TestDevice testDevice) : base(testDevice) [Category(UITestCategories.CollectionView)] public void JustWhalingAwayOnTheCollectionViewWithAddsAndClearsShouldNotCrash() { - this.IgnoreIfPlatforms([TestDevice.Android, TestDevice.Mac, TestDevice.Windows]); - RunningApp.WaitForElement(Run); RunningApp.Tap(Run); Task.Delay(5000).Wait(); @@ -29,4 +28,5 @@ public void JustWhalingAwayOnTheCollectionViewWithAddsAndClearsShouldNotCrash() RunningApp.WaitForElement(Run); } } -} \ No newline at end of file +} +#endif \ No newline at end of file From f80965ffcceb728bf9ee4484069cfb477a6b2f6c Mon Sep 17 00:00:00 2001 From: Gerald Versluis Date: Fri, 12 Apr 2024 14:46:40 +0200 Subject: [PATCH 26/27] This is the fix, I feel it --- .../ControlGallery.Android.Appium.UITests.csproj | 3 --- .../ControlGallery.iOS.Appium.UITests.csproj | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj index 329257401c13..5d66c158ad15 100644 --- a/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj +++ b/src/Compatibility/ControlGallery/test/Android.Appium.UITests/ControlGallery.Android.Appium.UITests.csproj @@ -6,9 +6,6 @@ enable true UITests - - - $(DefineConstants);ANDROID diff --git a/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj index 55611e16459a..4558c59d5333 100644 --- a/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj +++ b/src/Compatibility/ControlGallery/test/iOS.Appium.UITests/ControlGallery.iOS.Appium.UITests.csproj @@ -6,9 +6,6 @@ enable true UITests - - - $(DefineConstants);IOS;IOSUITEST From e9f95ab697fdbada6d86afd1b04ed5076b53da5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Tue, 16 Apr 2024 16:11:56 +0200 Subject: [PATCH 27/27] Fix merge error --- src/Controls/tests/UITests/Tests/Issues/Issue19509.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Controls/tests/UITests/Tests/Issues/Issue19509.cs b/src/Controls/tests/UITests/Tests/Issues/Issue19509.cs index cbef845792d4..fef68ee04db2 100644 --- a/src/Controls/tests/UITests/Tests/Issues/Issue19509.cs +++ b/src/Controls/tests/UITests/Tests/Issues/Issue19509.cs @@ -22,8 +22,6 @@ public async Task EntryTextColorStopsWorkingAfterPropertyIsUpdatedFromBinding() await Task.Yield(); - await Task.Delay(1000); // Wait to complete Ripple Effect animation. - // 2. Verify that the Entry TextColor is correct (Green). VerifyScreenshot(); }