diff --git a/tests/Prism.Plugin.Popups.DryIoc.Tests/Prism.Plugin.Popups.DryIoc.Tests.csproj b/tests/Prism.Plugin.Popups.DryIoc.Tests/Prism.Plugin.Popups.DryIoc.Tests.csproj
index d363741..f8a59f6 100644
--- a/tests/Prism.Plugin.Popups.DryIoc.Tests/Prism.Plugin.Popups.DryIoc.Tests.csproj
+++ b/tests/Prism.Plugin.Popups.DryIoc.Tests/Prism.Plugin.Popups.DryIoc.Tests.csproj
@@ -16,7 +16,6 @@
all
runtime; build; native; contentfiles; analyzers
-
diff --git a/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/DelayedMessageBus.cs b/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/DelayedMessageBus.cs
new file mode 100644
index 0000000..21a2275
--- /dev/null
+++ b/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/DelayedMessageBus.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Xunit
+{
+ ///
+ /// Used to capture messages to potentially be forwarded later. Messages are forwarded by
+ /// disposing of the message bus.
+ ///
+ public class DelayedMessageBus : IMessageBus
+ {
+ private readonly IMessageBus innerBus;
+ private readonly List messages = new List();
+
+ public DelayedMessageBus(IMessageBus innerBus)
+ {
+ this.innerBus = innerBus;
+ }
+
+ public bool QueueMessage(IMessageSinkMessage message)
+ {
+ lock (messages)
+ messages.Add(message);
+
+ // No way to ask the inner bus if they want to cancel without sending them the message, so
+ // we just go ahead and continue always.
+ return true;
+ }
+
+ public void Dispose()
+ {
+ foreach (var message in messages)
+ innerBus.QueueMessage(message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/RetryAttribute.cs b/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/RetryAttribute.cs
new file mode 100644
index 0000000..955c677
--- /dev/null
+++ b/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/RetryAttribute.cs
@@ -0,0 +1,27 @@
+using Xunit;
+using Xunit.Sdk;
+
+namespace Xunit
+{
+ ///
+ /// Works just like [Fact] except that failures are retried (by default, 3 times).
+ ///
+#if DRYIOC
+ [XunitTestCaseDiscoverer("Xunit.RetryFactDiscoverer", "Prism.Plugin.Popups.DryIoc.Tests")]
+#else
+ [XunitTestCaseDiscoverer("Xunit.RetryFactDiscoverer", "Prism.Plugin.Popups.Unity.Tests")]
+#endif
+ public class RetryAttribute : FactAttribute
+ {
+ public RetryAttribute(int maxRetries = 3)
+ {
+ MaxRetries = maxRetries;
+ }
+
+ ///
+ /// Number of retries allowed for a failed test. If unset (or set less than 1), will
+ /// default to 3 attempts.
+ ///
+ public int MaxRetries { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/RetryFactDiscoverer.cs b/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/RetryFactDiscoverer.cs
new file mode 100644
index 0000000..f2b7798
--- /dev/null
+++ b/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/RetryFactDiscoverer.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Xunit
+{
+ public class RetryFactDiscoverer : IXunitTestCaseDiscoverer
+ {
+ readonly IMessageSink diagnosticMessageSink;
+
+ public RetryFactDiscoverer(IMessageSink diagnosticMessageSink)
+ {
+ this.diagnosticMessageSink = diagnosticMessageSink;
+ }
+
+ public IEnumerable Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
+ {
+ var maxRetries = factAttribute.GetNamedArgument("MaxRetries");
+ if (maxRetries < 1)
+ maxRetries = 3;
+
+ yield return new RetryTestCase(diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.All, testMethod, maxRetries);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/RetryTestCase.cs b/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/RetryTestCase.cs
new file mode 100644
index 0000000..787f7cd
--- /dev/null
+++ b/tests/Prism.Plugin.Popups.Tests.Shared/Helpers/RetryTestCase.cs
@@ -0,0 +1,79 @@
+using System;
+using System.ComponentModel;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Xunit
+{
+ [Serializable]
+ public class RetryTestCase : XunitTestCase
+ {
+ private int maxRetries;
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [Obsolete("Called by the de-serializer", true)]
+ public RetryTestCase() { }
+
+ //[Obsolete]
+ //public RetryTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay testMethodDisplay, ITestMethod testMethod, int maxRetries)
+ // : base(diagnosticMessageSink, testMethodDisplay, testMethod, testMethodArguments: null)
+ //{
+ // this.maxRetries = maxRetries;
+ //}
+
+ public RetryTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, int maxRetries, object[] testMethodArguments = null)
+ : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments)
+ {
+ this.maxRetries = maxRetries;
+ }
+
+ // This method is called by the xUnit test framework classes to run the test case. We will do the
+ // loop here, forwarding on to the implementation in XunitTestCase to do the heavy lifting. We will
+ // continue to re-run the test until the aggregator has an error (meaning that some internal error
+ // condition happened), or the test runs without failure, or we've hit the maximum number of tries.
+ public override async Task RunAsync(IMessageSink diagnosticMessageSink,
+ IMessageBus messageBus,
+ object[] constructorArguments,
+ ExceptionAggregator aggregator,
+ CancellationTokenSource cancellationTokenSource)
+ {
+ var runCount = 0;
+
+ while (true)
+ {
+ // This is really the only tricky bit: we need to capture and delay messages (since those will
+ // contain run status) until we know we've decided to accept the final result;
+ var delayedMessageBus = new DelayedMessageBus(messageBus);
+
+ var summary = await base.RunAsync(diagnosticMessageSink, delayedMessageBus, constructorArguments, aggregator, cancellationTokenSource);
+ if (aggregator.HasExceptions || summary.Failed == 0 || ++runCount >= maxRetries)
+ {
+ delayedMessageBus.Dispose(); // Sends all the delayed messages
+ return summary;
+ }
+
+ diagnosticMessageSink.OnMessage(new DiagnosticMessage("Execution of '{0}' failed (attempt #{1}), retrying...", DisplayName, runCount));
+ Xamarin.Forms.Mocks.MockForms.Init();
+ Prism.Navigation.PageNavigationRegistry.ClearRegistrationCache();
+ GC.Collect();
+ await Task.Delay(100);
+ }
+ }
+
+ public override void Serialize(IXunitSerializationInfo data)
+ {
+ base.Serialize(data);
+
+ data.AddValue("MaxRetries", maxRetries);
+ }
+
+ public override void Deserialize(IXunitSerializationInfo data)
+ {
+ base.Deserialize(data);
+
+ maxRetries = data.GetValue("MaxRetries");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Prism.Plugin.Popups.Tests.Shared/Mocks/AppMock.cs b/tests/Prism.Plugin.Popups.Tests.Shared/Mocks/AppMock.cs
index 9d3a349..2757d02 100644
--- a/tests/Prism.Plugin.Popups.Tests.Shared/Mocks/AppMock.cs
+++ b/tests/Prism.Plugin.Popups.Tests.Shared/Mocks/AppMock.cs
@@ -2,6 +2,7 @@
using Prism.Plugin.Popups.Tests.Mocks.Views;
using Prism.Navigation;
using Xamarin.Forms;
+using Prism.Logging;
#if AUTOFAC
using Prism.Autofac;
#elif DRYIOC
@@ -20,9 +21,13 @@ public AppMock(IPlatformInitializer platformInitializer)
}
- protected override void OnInitialized()
+ protected override async void OnInitialized()
{
- NavigationService.NavigateAsync("MainPage").ContinueWith(t => { });
+ var result = await NavigationService.NavigateAsync("MainPage");
+ if(!result.Success)
+ {
+ Container.Resolve().Log(result.Exception.ToString(), Category.Exception, Priority.High);
+ }
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
diff --git a/tests/Prism.Plugin.Popups.Tests.Shared/Prism.Plugin.Popups.Tests.Shared.projitems b/tests/Prism.Plugin.Popups.Tests.Shared/Prism.Plugin.Popups.Tests.Shared.projitems
index c29901d..a5f6ed7 100644
--- a/tests/Prism.Plugin.Popups.Tests.Shared/Prism.Plugin.Popups.Tests.Shared.projitems
+++ b/tests/Prism.Plugin.Popups.Tests.Shared/Prism.Plugin.Popups.Tests.Shared.projitems
@@ -9,6 +9,10 @@
Prism.Plugin.Popups.Tests
+
+
+
+
diff --git a/tests/Prism.Plugin.Popups.Tests.Shared/Tests/NavigationServiceFixture.cs b/tests/Prism.Plugin.Popups.Tests.Shared/Tests/NavigationServiceFixture.cs
index 2512841..3b894f2 100644
--- a/tests/Prism.Plugin.Popups.Tests.Shared/Tests/NavigationServiceFixture.cs
+++ b/tests/Prism.Plugin.Popups.Tests.Shared/Tests/NavigationServiceFixture.cs
@@ -11,6 +11,7 @@
using Xunit;
using Xunit.Abstractions;
using Prism.Navigation;
+using Prism.Common;
#if AUTOFAC
namespace Prism.Plugin.Popups.Autofac.Tests
@@ -27,11 +28,13 @@ public NavigationServiceFixture(ITestOutputHelper testOutputHelper)
{
}
- public void PopupNavigationService_SetsStandardPages()
[Retry]
+ public async Task PopupNavigationService_SetsStandardPages()
{
var app = GetApp();
Assert.Empty(PopupNavigation.Instance.PopupStack);
+ await Task.Delay(150);
+
Assert.NotNull(app.MainPage);
Assert.IsType(app.MainPage);
}
diff --git a/tests/Prism.Plugin.Popups.Tests.Shared/Tests/RegistrationFixture.cs b/tests/Prism.Plugin.Popups.Tests.Shared/Tests/RegistrationFixture.cs
index 29d0abf..2e93c95 100644
--- a/tests/Prism.Plugin.Popups.Tests.Shared/Tests/RegistrationFixture.cs
+++ b/tests/Prism.Plugin.Popups.Tests.Shared/Tests/RegistrationFixture.cs
@@ -10,6 +10,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
@@ -67,10 +68,12 @@ public void Application_Has_PopupNavigationService()
Assert.IsType(app.GetNavigationService());
}
- public void MainPage_Has_PopupNavigationService()
[Retry]
+ public async Task MainPage_Has_PopupNavigationService()
{
var app = GetApp();
+ await Task.Delay(150);
+
var vm = app.MainPage.BindingContext as MainPageViewModel;
Assert.NotNull(vm);
Assert.NotNull(vm.NavigationService);
diff --git a/tests/Prism.Plugin.Popups.Unity.Tests/Prism.Plugin.Popups.Unity.Tests.csproj b/tests/Prism.Plugin.Popups.Unity.Tests/Prism.Plugin.Popups.Unity.Tests.csproj
index 51b264e..0bb3f3b 100644
--- a/tests/Prism.Plugin.Popups.Unity.Tests/Prism.Plugin.Popups.Unity.Tests.csproj
+++ b/tests/Prism.Plugin.Popups.Unity.Tests/Prism.Plugin.Popups.Unity.Tests.csproj
@@ -16,7 +16,6 @@
all
runtime; build; native; contentfiles; analyzers
-