diff --git a/.azure-devops-ios-tests.yml b/.azure-devops-ios-tests.yml index 43278eadca..e2c8af2924 100644 --- a/.azure-devops-ios-tests.yml +++ b/.azure-devops-ios-tests.yml @@ -2,14 +2,20 @@ jobs: - job: iOS_Tests + timeoutInMinutes: 120 + strategy: matrix: Automated: UITEST_SNAPSHOTS_ONLY: false - # Tests are failing, to be enabled in later PR - #Snapshots: - # UITEST_SNAPSHOTS_ONLY: true + Snapshots_Group00: + UITEST_SNAPSHOTS_ONLY: true + UITEST_SNAPSHOTS_GROUP: 00 + + Snapshots_Group01: + UITEST_SNAPSHOTS_ONLY: true + UITEST_SNAPSHOTS_GROUP: 01 variables: CI_Build: true @@ -47,12 +53,13 @@ jobs: BUILD_SOURCESDIRECTORY: "$(build.sourcesdirectory)" BUILD_ARTIFACTSTAGINGDIRECTORY: "$(build.artifactstagingdirectory)" UITEST_SNAPSHOTS_ONLY: "$(UITEST_SNAPSHOTS_ONLY)" + UITEST_SNAPSHOTS_GROUP: "$(UITEST_SNAPSHOTS_GROUP)" - task: PublishTestResults@2 condition: always() inputs: - testRunTitle: 'iOS Test Run' + testRunTitle: 'iOS Test Run ($(Agent.JobName ))' testResultsFormat: 'NUnit' testResultsFiles: '$(build.sourcesdirectory)/build/TestResult.xml' failTaskOnFailedTests: true diff --git a/build/ios-uitest-run.sh b/build/ios-uitest-run.sh index 16b3abcca5..15965a7d97 100755 --- a/build/ios-uitest-run.sh +++ b/build/ios-uitest-run.sh @@ -19,7 +19,14 @@ mono nuget/nuget.exe install NUnit.ConsoleRunner -Version 3.10.0 if [ "$UITEST_SNAPSHOTS_ONLY" == 'true' ]; then export SCREENSHOTS_FOLDERNAME=ios-Snap - export TEST_FILTERS="namespace == 'SamplesApp.UITests.Snap'" + + # CommandBar disabled: https://github.com/unoplatform/uno/issues/1955 + # runGroup is used to parallelize the snapshots tests on multiple agents + export TEST_FILTERS=" \ + namespace == 'SamplesApp.UITests.Snap' \ + and Description !~ 'automated:Uno.UI.Samples.Content.UITests.CommandBar.*' \ + and Description =~ 'runGroup:$UITEST_SNAPSHOTS_GROUP' \ + " else export SCREENSHOTS_FOLDERNAME=ios export TEST_FILTERS=" \ diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index fe65435a82..c18d0424f0 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -17,8 +17,8 @@ - - + + diff --git a/src/SamplesApp/SamplesApp.UITests.Generator/SnapShotTestGenerator.cs b/src/SamplesApp/SamplesApp.UITests.Generator/SnapShotTestGenerator.cs index 594fe888e6..ce4828dd5a 100644 --- a/src/SamplesApp/SamplesApp.UITests.Generator/SnapShotTestGenerator.cs +++ b/src/SamplesApp/SamplesApp.UITests.Generator/SnapShotTestGenerator.cs @@ -89,25 +89,29 @@ namespace Uno.Samples.UITest.Generator using (builder.BlockInvariant($"namespace {context.GetProjectInstance().GetPropertyValue("RootNamespace")}.Snap")) { - builder.AppendLineInvariant("[NUnit.Framework.TestFixture]"); + builder.AppendLineInvariant("[global::NUnit.Framework.TestFixture]"); + + // Required for https://github.com/unoplatform/uno/issues/1955 + builder.AppendLineInvariant("[global::SamplesApp.UITests.TestFramework.TestAppModeAttribute(cleanEnvironment: true, platform: Uno.UITest.Helpers.Queries.Platform.iOS)]"); using (builder.BlockInvariant($"public partial class {groupName} : SampleControlUITestBase")) { - foreach (var test in group.Symbols) // .Where(s => s.symbol.ToString()).Contains("Border_Simple"))) + foreach (var test in group.Symbols) { var info = GetSampleInfo(test.symbol, test.symbol.FindAttributeFlattened(_sampleControlInfoSymbol)); - builder.AppendLineInvariant("[NUnit.Framework.Test]"); + builder.AppendLineInvariant("[global::NUnit.Framework.Test]"); + builder.AppendLineInvariant($"[global::NUnit.Framework.Description(\"runGroup:{group.Index % 2:00}, automated:{test.symbol.ToDisplayString()}\")]"); if (info.ignoreInSnapshotTests) { - builder.AppendLineInvariant("[NUnit.Framework.Ignore(\"ignoreInSnapshotTests is set for attribute\")]"); + builder.AppendLineInvariant("[global::NUnit.Framework.Ignore(\"ignoreInSnapshotTests is set for attribute\")]"); } - builder.AppendLineInvariant("[SamplesApp.UITests.TestFramework.AutoRetry]"); + builder.AppendLineInvariant("[global::SamplesApp.UITests.TestFramework.AutoRetry]"); using (builder.BlockInvariant($"public void {Sanitize(test.category)}_{Sanitize(info.name)}()")) { - builder.AppendLineInvariant($"Run(\"{test.symbol}\");"); + builder.AppendLineInvariant($"Run(\"{test.symbol}\", waitForSampleControl: false);"); } } } diff --git a/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs b/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs index 91713df807..e84742b036 100644 --- a/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs +++ b/src/SamplesApp/SamplesApp.UITests/SampleControlUITestBase.cs @@ -15,11 +15,18 @@ namespace SamplesApp.UITests public class SampleControlUITestBase { protected IApp _app; + private static int _totalTestFixtureCount; public SampleControlUITestBase() { } + [OneTimeSetUp] + public void SingleSetup() + { + ValidateAppMode(); + } + static SampleControlUITestBase() { AppInitializer.TestEnvironment.AndroidAppName = Constants.AndroidAppName; @@ -38,6 +45,25 @@ namespace SamplesApp.UITests AppInitializer.ColdStartApp(); } + public void ValidateAppMode() + { + if(GetCurrentFixtureAttributes().FirstOrDefault() is TestAppModeAttribute testAppMode) + { + if( + _totalTestFixtureCount != 0 + && testAppMode.CleanEnvironment + && testAppMode.Platform == AppInitializer.GetLocalPlatform() + ) + { + // If this is not the first run, and the fixture requested a clean environment, request a cold start. + // If this is the first run, as the app is cold-started during the type constructor, we can skip this. + _app = AppInitializer.ColdStartApp(); + } + } + + _totalTestFixtureCount++; + } + [SetUp] [AutoRetry] public void BeforeEachTest() @@ -194,14 +220,25 @@ namespace SamplesApp.UITests private static void ValidateAutoRetry() { - var testType = Type.GetType(TestContext.CurrentContext.Test.ClassName); - var methodInfo = testType?.GetMethod(TestContext.CurrentContext.Test.MethodName); - if (methodInfo?.GetCustomAttributes(typeof(AutoRetryAttribute), true).Length == 0 && false) + if (GetCurrentTestAttributes().Length == 0) { Assert.Fail($"The AutoRetryAttribute is not defined for this test"); } } + private static T[] GetCurrentFixtureAttributes() where T : Attribute + { + var testType = Type.GetType(TestContext.CurrentContext.Test.ClassName); + return testType?.GetCustomAttributes(typeof(T), true) is T[] array ? array : new T[0]; + } + + private static T[] GetCurrentTestAttributes() where T : Attribute + { + var testType = Type.GetType(TestContext.CurrentContext.Test.ClassName); + var methodInfo = testType?.GetMethod(TestContext.CurrentContext.Test.MethodName); + return methodInfo?.GetCustomAttributes(typeof(T), true) is T[] array ? array : new T[0]; + } + private Platform[] GetActivePlatforms() { if (TestContext.CurrentContext.Test.Properties["ActivePlatforms"].FirstOrDefault() is Platform[] platforms) @@ -246,7 +283,7 @@ namespace SamplesApp.UITests { var result = _app.InvokeGeneric("browser:SampleRunner|IsTestDone", testRunId).ToString(); return bool.TryParse(result, out var testDone) && testDone; - }, retryFrequency: TimeSpan.FromMilliseconds(250)); + }, retryFrequency: TimeSpan.FromMilliseconds(50)); TakeScreenshot(metadataName.Replace(".", "_")); } diff --git a/src/SamplesApp/SamplesApp.UITests/TestFramework/TestAppMode.cs b/src/SamplesApp/SamplesApp.UITests/TestFramework/TestAppMode.cs new file mode 100644 index 0000000000..037c872243 --- /dev/null +++ b/src/SamplesApp/SamplesApp.UITests/TestFramework/TestAppMode.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Uno.UITest.Helpers.Queries; + +namespace SamplesApp.UITests.TestFramework +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple=true, Inherited = true)] + public class TestAppModeAttribute : Attribute + { + /// + /// Builds TestMode attribute + /// + /// + /// Determines if the app should be restarted to get a clean environment before the fixture tests are started. + /// + /// Determines the target platform to be used for this attribute + public TestAppModeAttribute(bool cleanEnvironment, Platform platform) + { + CleanEnvironment = cleanEnvironment; + Platform = platform; + } + + /// + /// Determines if the app should be restarted to get a clean environment before the fixture tests are started. + /// + public bool CleanEnvironment { get; } + + /// + /// Determines the target platform to be used for this attribute + /// + public Platform Platform { get; } + } +} diff --git a/src/SamplesApp/SamplesApp.UITests/Toolkit/UnoSamples_Tests.Elevation.cs b/src/SamplesApp/SamplesApp.UITests/Toolkit/UnoSamples_Tests.Elevation.cs index 344404e85a..53803b16d1 100644 --- a/src/SamplesApp/SamplesApp.UITests/Toolkit/UnoSamples_Tests.Elevation.cs +++ b/src/SamplesApp/SamplesApp.UITests/Toolkit/UnoSamples_Tests.Elevation.cs @@ -17,6 +17,7 @@ namespace SamplesApp.UITests.Toolkit { [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS)] // Android is disabled https://github.com/unoplatform/uno/issues/1635 public void Elevation_Validation() { diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_Devices/GyrometerTests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_Devices/GyrometerTests.cs index 17c14588bf..109371dccf 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_Devices/GyrometerTests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_Devices/GyrometerTests.cs @@ -14,6 +14,7 @@ namespace SamplesApp.UITests.Windows_Devices public class GyrometerTests : SampleControlUITestBase { [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void When_Gyrometer_Is_Retrived_With_GetDefault() { @@ -23,6 +24,7 @@ namespace SamplesApp.UITests.Windows_Devices } [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void When_Reading_Is_Attached() { @@ -51,6 +53,7 @@ namespace SamplesApp.UITests.Windows_Devices } [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void When_Reading_Is_Attached_And_Waits() { @@ -78,6 +81,7 @@ namespace SamplesApp.UITests.Windows_Devices } [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void When_Reading_Is_Attached_And_Detaches() { diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Automation/AutomationId_Tests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Automation/AutomationId_Tests.cs index 7309d16880..00920af971 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Automation/AutomationId_Tests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Automation/AutomationId_Tests.cs @@ -15,6 +15,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Automation public class AutomationId_Tests : SampleControlUITestBase { [Test] + [AutoRetry] public void TestSimple() { Run("UITests.Shared.Windows_UI.Xaml_Automation.AutomationProperties_AutomationId"); diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs index 5a33f883b3..b51af22d18 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs @@ -16,6 +16,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Controls.FlyoutTests public partial class Flyout_Tests : SampleControlUITestBase { [Test] + [AutoRetry] [Ignore("Not available yet")] public void FlyoutTest_BottomPlacement_WithSmallerAnchor_DoesntDefaultToFull() { @@ -36,6 +37,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Controls.FlyoutTests } [Test] + [AutoRetry] public void FlyoutTest_Target() { Run("Uno.UI.Samples.Content.UITests.Flyout.Flyout_Target"); @@ -94,6 +96,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Controls.FlyoutTests } [Test] + [AutoRetry] public void FlyoutTest_Unloaded() { Run("UITests.Shared.Windows_UI_Xaml_Controls.Flyout.Flyout_Unloaded"); diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ListViewTests/UnoSamples_Tests.ListView.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ListViewTests/UnoSamples_Tests.ListView.cs index 92ecd8cc19..4e76aada30 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ListViewTests/UnoSamples_Tests.ListView.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ListViewTests/UnoSamples_Tests.ListView.cs @@ -53,6 +53,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Controls.ListViewTests } [Test] + [AutoRetry] [ActivePlatforms(Platform.Android)] public void ListView_ItemPanel_HotSwapTest() { diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ToggleSwitchTests/UnoSamples_Tests.ToggleSwitch.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ToggleSwitchTests/UnoSamples_Tests.ToggleSwitch.cs index 6a2ed32695..6774d849ad 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ToggleSwitchTests/UnoSamples_Tests.ToggleSwitch.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/ToggleSwitchTests/UnoSamples_Tests.ToggleSwitch.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using NUnit.Framework; +using SamplesApp.UITests.TestFramework; using Uno.UITest.Helpers; using Uno.UITest.Helpers.Queries; @@ -12,6 +13,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Controls.ToggleSwitchTests public partial class ToggleSwitch_Tests : SampleControlUITestBase { [Test] + [AutoRetry] public void ToggleSwitch_TemplateReuseTest() { Run("UITests.Shared.Windows_UI_Xaml_Controls.ToggleSwitchControl.ToggleSwitch_TemplateReuse"); diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs index 2b5739a6b3..f874bdbea1 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Capture_Tests.cs @@ -13,24 +13,29 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input public class Capture_Tests : SampleControlUITestBase { [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS | Platform.Android)] // This fails with unit test public void TestSimple() => RunTest("Simple", TouchAndMoveOut); [Test] + [AutoRetry] public void TestVisibility() => RunTest("Visibility"); [Test] + [AutoRetry] public void TestNestedVisibility() => RunTest("NestedVisibility"); [Test] + [AutoRetry] [Ignore("Inconsistent behavior between manual and unit test")] public void TestIsEnabled() => RunTest("IsEnabled"); [Test] + [AutoRetry] [Ignore("Inconsistent behavior between manual and unit test")] [ActivePlatforms(Platform.Browser)] // The IsEnabled property is not inherited on other platforms yet. public void TestNestedIsEnabled() diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/DragCoordinates_Tests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/DragCoordinates_Tests.cs index 9de82aae44..45fd13e68c 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/DragCoordinates_Tests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/DragCoordinates_Tests.cs @@ -14,6 +14,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Controls.TimePickerTests public class DragCoordinates_Tests : SampleControlUITestBase { [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Browser)] // Android is disabled https://github.com/unoplatform/uno/issues/1257 public void DragBorder01() { diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/EventSequence_Tests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/EventSequence_Tests.cs index d23cd61e14..8a689a58ab 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/EventSequence_Tests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/EventSequence_Tests.cs @@ -13,26 +13,32 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input public class EventSequence_Tests : SampleControlUITestBase { [Test] + [AutoRetry] public void TestTap() => RunSequence("Tap"); [Test] + [AutoRetry] public void TestClick() => RunSequence("Click"); [Test] + [AutoRetry] public void TestTranslatedTap() => RunSequence("TranslatedTap", TranslateOverElement); [Test] + [AutoRetry] public void TestTranslatedClick() => RunSequence("TranslatedClick", TranslateOverElement); [Test] + [AutoRetry] public void TestHyperlink() => RunSequence("Hyperlink", TapSomewhereInElement); [Test] + [AutoRetry] public void TestListView() => RunSequence("ListView", TapSomewhereInElement); diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Manipulation_Tests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Manipulation_Tests.cs index 164dd6f337..4a5902ed4e 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Manipulation_Tests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/Manipulation_Tests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using NUnit.Framework; +using SamplesApp.UITests.TestFramework; using Uno.UITest.Helpers; using Uno.UITest.Helpers.Queries; @@ -12,6 +13,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input public class Manipulation_Tests : SampleControlUITestBase { [Test] + [AutoRetry] public void TestManipulation() { Run("UITests.Shared.Windows_UI_Input.GestureRecognizerTests.ManipulationEvents"); diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/VisualState_Tests.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/VisualState_Tests.cs index d784fdc175..ec074628af 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/VisualState_Tests.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Input/VisualState_Tests.cs @@ -16,6 +16,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input public class VisualState_Tests : SampleControlUITestBase { [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void TestButtonReleasedOut() => TestButtonReleasedOutState( "MyButton", @@ -24,6 +25,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input "CommonStates.Normal"); [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void TestIndeterminateToggleButtonReleasedOut() => TestButtonReleasedOutState( "MyIndeterminateToggleButton", @@ -32,6 +34,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input "CommonStates.Indeterminate"); [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void TestCheckedToggleButtonReleasedOut() => TestButtonReleasedOutState( "MyCheckedToggleButton", @@ -40,6 +43,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input "CommonStates.Checked"); [Test] + [AutoRetry] [Ignore("We get an invalid 'PointerOver' on release, a fix in pending in another PR")] public void TestUncheckedToggleButtonReleasedOut() => TestButtonReleasedOutState( "MyUncheckedToggleButton", @@ -48,6 +52,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input "CommonStates.Unchecked"); [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void TestRadioButtonReleasedOut() => TestButtonReleasedOutState( "MyRadioButton", @@ -56,6 +61,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input "CommonStates.Normal"); [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void TestHyperlinkButtonReleasedOut() => TestButtonReleasedOutState( "MyHyperlinkButton", @@ -64,6 +70,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input "CommonStates.Normal"); [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void TestIndeterminateCheckboxReleasedOut() => TestButtonReleasedOutState( "MyIndeterminateCheckbox", @@ -72,6 +79,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input "CombinedStates.IndeterminateNormal"); [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void TestCheckedCheckboxReleasedOut() => TestButtonReleasedOutState( "MyCheckedCheckbox", @@ -80,6 +88,7 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input "CombinedStates.CheckedNormal"); [Test] + [AutoRetry] [ActivePlatforms(Platform.iOS, Platform.Android)] public void TestUncheckedCheckboxReleasedOut() => TestButtonReleasedOutState( "MyUncheckedCheckbox", @@ -88,10 +97,12 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input "CombinedStates.UncheckedNormal"); [Test] + [AutoRetry] public void TestHyperlinkReleasedOut() => TestButtonReleasedOutState( "MyHyperlink"); // There is no "VisualState" for Hyperlink, only a hardcoded opacity of .5 (kind-of like UWP) [Test] + [AutoRetry] public void TestListViewReleasedOut() { Run("UITests.Shared.Windows_UI_Input.VisualStatesTests.ListViewItem"); @@ -107,12 +118,14 @@ namespace SamplesApp.UITests.Windows_UI_Xaml_Input } [Test] + [AutoRetry] public void TestTextBoxReleaseOut() => TestTextBoxReleasedOutState( "MyTextBox", "CommonStates.PointerOver", "CommonStates.Focused"); [Test] + [AutoRetry] public void TestTextBoxTap() => TestTextBoxTappedState( "MyTextBox", "CommonStates.PointerOver", diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml/UIElementTests/TransformToVisual_ScrollViewer.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml/UIElementTests/TransformToVisual_ScrollViewer.xaml.cs index be7c84a603..36e1b3ad21 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml/UIElementTests/TransformToVisual_ScrollViewer.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml/UIElementTests/TransformToVisual_ScrollViewer.xaml.cs @@ -9,7 +9,7 @@ using Uno.UI.Samples.Controls; namespace UITests.Shared.Windows_UI_Xaml.UIElementTests { - [SampleControlInfo("UIElement")] + [SampleControlInfo("UIElement", ignoreInSnapshotTests: true)] public sealed partial class TransformToVisual_ScrollViewer : Page { private readonly TestRunner _tests; diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ListView/ListView_CacheLength_Slow_Load.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ListView/ListView_CacheLength_Slow_Load.xaml.cs index 5efe516e3c..4dc214daa2 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ListView/ListView_CacheLength_Slow_Load.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ListView/ListView_CacheLength_Slow_Load.xaml.cs @@ -4,7 +4,7 @@ using Windows.UI.Xaml.Controls; namespace SamplesApp.Windows_UI_Xaml_Controls.ListView { - [SampleControlInfo("ListView", "ListView_CacheLength_Slow_Load", description: "ListView with slow-loading images, illustrating caching behaviour.")] + [SampleControlInfo("ListView", "ListView_CacheLength_Slow_Load", ignoreInSnapshotTests: true, description: "ListView with slow-loading images, illustrating caching behaviour.")] public sealed partial class ListView_CacheLength_Slow_Load : UserControl { public ListView_CacheLength_Slow_Load() diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Progress/ProgressRing.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Progress/ProgressRing.xaml.cs index 52cd2dca44..849b29640f 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Progress/ProgressRing.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Progress/ProgressRing.xaml.cs @@ -21,7 +21,7 @@ namespace SamplesApp.Samples.Progress /// /// An empty page that can be used on its own or navigated to within a Frame. /// - [SampleControlInfo("Progress", "ProgressRing")] + [SampleControlInfo("Progress", "ProgressRing", ignoreInSnapshotTests: true)] public sealed partial class ProgressRing : Page { public ProgressRing() diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Media/Transform/Transformed_Ancestor_And_UI_Blocked.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Media/Transform/Transformed_Ancestor_And_UI_Blocked.xaml.cs index 2c16776c0f..db5b0e5022 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Media/Transform/Transformed_Ancestor_And_UI_Blocked.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Media/Transform/Transformed_Ancestor_And_UI_Blocked.xaml.cs @@ -21,7 +21,7 @@ using Windows.UI.Xaml.Navigation; namespace UITests.Shared.Windows_UI_Xaml_Media.Transform { - [SampleControlInfo("Transform", "Transformed_Ancestor_And_UI_Blocked", description: "Animation in transformed hierarchy, under simulated heavy UI load. Animation should remain smooth on Android 8+ devices.")] + [SampleControlInfo("Transform", "Transformed_Ancestor_And_UI_Blocked", ignoreInSnapshotTests: true, description: "Animation in transformed hierarchy, under simulated heavy UI load. Animation should remain smooth on Android 8+ devices.")] public sealed partial class Transformed_Ancestor_And_UI_Blocked : UserControl { private bool _isLoaded; diff --git a/src/Uno.UI.TestComparer/Comparer/TestFilesComparer.cs b/src/Uno.UI.TestComparer/Comparer/TestFilesComparer.cs index f5da497836..ccfedcc104 100644 --- a/src/Uno.UI.TestComparer/Comparer/TestFilesComparer.cs +++ b/src/Uno.UI.TestComparer/Comparer/TestFilesComparer.cs @@ -147,10 +147,10 @@ namespace Uno.UI.TestComparer.Comparer var currentImage = DecodeImage(folderInfo.Path); var previousImage = DecodeImage(previousFolderInfo.Path); - var diff = DiffImages(currentImage.pixels, previousImage.pixels); + var diff = DiffImages(currentImage.pixels, previousImage.pixels, currentImage.frame.Format.BitsPerPixel / 8); var diffFilePath = Path.Combine(diffPath, $"{folderInfo.Id}-{folderInfo.CompareeId}.png"); - WriteImage(diffFilePath, diff, currentImage.frame); + WriteImage(diffFilePath, diff, currentImage.frame, currentImage.stride); compareResultFileRun.DiffResultImage = diffFilePath; @@ -220,7 +220,7 @@ namespace Uno.UI.TestComparer.Comparer } } - private void WriteImage(string diffPath, byte[] diff, BitmapFrame frameInfo) + private void WriteImage(string diffPath, byte[] diff, BitmapFrame frameInfo, int stride) { using (var stream = new FileStream(diffPath, FileMode.Create)) { @@ -229,14 +229,14 @@ namespace Uno.UI.TestComparer.Comparer encoder.Interlace = PngInterlaceOption.On; var frame = BitmapSource.Create( - pixelWidth: (int)frameInfo.Width, - pixelHeight: (int)frameInfo.Height, + pixelWidth: (int)frameInfo.PixelWidth, + pixelHeight: (int)frameInfo.PixelHeight, dpiX: frameInfo.DpiX, dpiY: frameInfo.DpiY, pixelFormat: frameInfo.Format, palette: frameInfo.Palette, pixels: diff, - stride: (int)(frameInfo.Width * 4) + stride: stride ); encoder.Frames.Add(BitmapFrame.Create(frame)); @@ -244,7 +244,7 @@ namespace Uno.UI.TestComparer.Comparer } } - private byte[] DiffImages(byte[] currentImage, byte[] previousImage) + private byte[] DiffImages(byte[] currentImage, byte[] previousImage, int pixelSize) { var result = new byte[currentImage.Length]; @@ -253,37 +253,34 @@ namespace Uno.UI.TestComparer.Comparer result[i] = (byte)(currentImage[i] ^ previousImage[i]); } - // Force result to be opaque - for (int i = 0; i < result.Length; i += 4) + if (pixelSize == 4) { - result[i+3] = 0xFF; + // Force result to be opaque + for (int i = 0; i < result.Length; i += 4) + { + result[i + 3] = 0xFF; + } } return result; } - private (BitmapFrame frame, byte[] pixels) DecodeImage(string path1) + private (BitmapFrame frame, byte[] pixels, int stride) DecodeImage(string path1) { - Stream imageStreamSource = new FileStream(@"\\?\" + path1, FileMode.Open, FileAccess.Read, FileShare.Read); - var decoder = new PngBitmapDecoder(imageStreamSource, BitmapCreateOptions.None, BitmapCacheOption.Default); - - var f = decoder.Frames[0]; - var sourceStride = f.PixelWidth * (f.Format.BitsPerPixel / 8); - sourceStride += (4 - sourceStride % 4); - - var image = new byte[sourceStride * (f.PixelHeight * 4)]; - decoder.Frames[0].CopyPixels(image, (int)sourceStride, 0); - - // Remove the stride - var targetImage = new byte[f.PixelWidth * f.PixelHeight * 4]; - var targetStride = f.PixelWidth * 4; - - for (int i = 0; i < f.PixelHeight; i++) + using (Stream imageStreamSource = new FileStream(@"\\?\" + path1, FileMode.Open, FileAccess.Read, FileShare.Read)) { - Buffer.BlockCopy(image, i * sourceStride, targetImage, i * targetStride, targetStride); - } + var decoder = new PngBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); - return (decoder.Frames[0], targetImage); + var f = decoder.Frames[0]; + var sourceBytesPerPixels = f.Format.BitsPerPixel / 8; + var sourceStride = f.PixelWidth * sourceBytesPerPixels; + sourceStride += (4 - sourceStride % 4); + + var image = new byte[sourceStride * (f.PixelHeight * sourceBytesPerPixels)]; + decoder.Frames[0].CopyPixels(image, (int)sourceStride, 0); + + return (decoder.Frames[0], image, sourceStride); + } } private static IEnumerable LogForeach(IEnumerable q, Action action) diff --git a/src/Uno.UI.TestComparer/Program.cs b/src/Uno.UI.TestComparer/Program.cs index 4303e72ac6..4b95708be0 100644 --- a/src/Uno.UI.TestComparer/Program.cs +++ b/src/Uno.UI.TestComparer/Program.cs @@ -166,7 +166,7 @@ namespace Umbrella.UI.TestComparer return; } - if (string.IsNullOrEmpty(githubPAT.Trim())) + if (string.IsNullOrEmpty(githubPAT.Trim()) || githubPAT.StartsWith("$(")) { Console.WriteLine($"No GitHub PAT, no PR comment will be posted."); return; diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.iOS.cs b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.iOS.cs index afa2ff522c..6bbdce9e6c 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.iOS.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.iOS.cs @@ -312,7 +312,7 @@ namespace Windows.UI.Xaml.Controls } else { - return _attributedString.GetBoundingRect(size, NSStringDrawingOptions.UsesLineFragmentOrigin, null).Size; + return _attributedString?.GetBoundingRect(size, NSStringDrawingOptions.UsesLineFragmentOrigin, null).Size ?? new CGSize(0,0); } } diff --git a/src/Uno.UI/UI/Xaml/Style/Generic/Generic.xaml b/src/Uno.UI/UI/Xaml/Style/Generic/Generic.xaml index 5cd171b17d..fb0cd606b9 100644 --- a/src/Uno.UI/UI/Xaml/Style/Generic/Generic.xaml +++ b/src/Uno.UI/UI/Xaml/Style/Generic/Generic.xaml @@ -773,6 +773,10 @@ + +