Browse Source

Add a unit test for ViewModelViewHost

artyom 6 years ago
parent
commit
97b44c02d2

+ 16 - 11
src/Avalonia.ReactiveUI/ViewModelViewHost.cs

@@ -1,6 +1,8 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System;
+using System.Reactive.Disposables;
 using ReactiveUI;
 using Splat;
 
@@ -18,7 +20,20 @@ namespace Avalonia.ReactiveUI
         /// </summary>
         public static readonly AvaloniaProperty<object> ViewModelProperty =
             AvaloniaProperty.Register<ViewModelViewHost, object>(nameof(ViewModel));
-        
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ViewModelViewHost"/> class.
+        /// </summary>
+        public ViewModelViewHost()
+        {
+            this.WhenActivated(disposables =>
+            {
+                this.WhenAnyValue(x => x.ViewModel)
+                    .Subscribe(NavigateToViewModel)
+                    .DisposeWith(disposables);
+            });
+        }
+
         /// <summary>
         /// Gets or sets the ViewModel to display.
         /// </summary>
@@ -33,16 +48,6 @@ namespace Avalonia.ReactiveUI
         /// </summary>
         public IViewLocator ViewLocator { get; set; }
 
-        /// <summary>
-        /// Updates the Content when ViewModel changes.
-        /// </summary>
-        /// <param name="e">Property changed event arguments.</param>
-        protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
-        {
-            if (e.Property.Name == nameof(ViewModel)) NavigateToViewModel(e.NewValue);
-            base.OnPropertyChanged(e);
-        }
-        
         /// <summary>
         /// Invoked when ReactiveUI router navigates to a view model.
         /// </summary>

+ 6 - 0
tests/Avalonia.ReactiveUI.UnitTests/Attributes.cs

@@ -0,0 +1,6 @@
+using Xunit;
+
+// Required to avoid InvalidOperationException sometimes thrown
+// from Splat.MemoizingMRUCache.cs which is not thread-safe.
+// Thrown when trying to access WhenActivated concurrently.
+[assembly: CollectionBehavior(DisableTestParallelization = true)]

+ 1 - 1
tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs

@@ -13,7 +13,7 @@ using Splat;
 using Avalonia.Markup.Xaml;
 using Avalonia.ReactiveUI;
 
-namespace Avalonia 
+namespace Avalonia.ReactiveUI.UnitTests
 {
     public class AvaloniaActivationForViewFetcherTest
     {

+ 1 - 1
tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs

@@ -16,7 +16,7 @@ using System.Threading.Tasks;
 using System.Reactive;
 using Avalonia.ReactiveUI;
 
-namespace Avalonia
+namespace Avalonia.ReactiveUI.UnitTests
 {
     public class RoutedViewHostTest
     {

+ 72 - 0
tests/Avalonia.ReactiveUI.UnitTests/ViewModelViewHostTest.cs

@@ -0,0 +1,72 @@
+using Avalonia.Controls;
+using Avalonia.UnitTests;
+using ReactiveUI;
+using Splat;
+using Xunit;
+
+namespace Avalonia.ReactiveUI.UnitTests
+{
+    public class ViewModelViewHostTest
+    {
+        public class FirstViewModel { }
+
+        public class FirstView : ReactiveUserControl<FirstViewModel> { }
+
+        public class SecondViewModel : ReactiveObject { }
+
+        public class SecondView : ReactiveUserControl<SecondViewModel> { }
+
+        public ViewModelViewHostTest()
+        {
+            Locator.CurrentMutable.RegisterConstant(new AvaloniaActivationForViewFetcher(), typeof(IActivationForViewFetcher));
+            Locator.CurrentMutable.Register(() => new FirstView(), typeof(IViewFor<FirstViewModel>));
+            Locator.CurrentMutable.Register(() => new SecondView(), typeof(IViewFor<SecondViewModel>));
+        }
+
+        [Fact]
+        public void ViewModelViewHost_View_Should_Stay_In_Sync_With_ViewModel() 
+        {
+            var defaultContent = new TextBlock();
+            var host = new ViewModelViewHost 
+            {
+                DefaultContent = defaultContent,
+                FadeOutAnimation = null,
+                FadeInAnimation = null
+            };
+
+            var root = new TestRoot 
+            { 
+                Child = host 
+            };
+            
+            Assert.NotNull(host.Content);
+            Assert.Equal(typeof(TextBlock), host.Content.GetType());
+            Assert.Equal(defaultContent, host.Content);
+
+            var first = new FirstViewModel();
+            host.ViewModel = first;
+            Assert.NotNull(host.Content);
+            Assert.Equal(typeof(FirstView), host.Content.GetType());
+            Assert.Equal(first, ((FirstView)host.Content).DataContext);
+            Assert.Equal(first, ((FirstView)host.Content).ViewModel);
+
+            var second = new SecondViewModel();
+            host.ViewModel = second;
+            Assert.NotNull(host.Content);
+            Assert.Equal(typeof(SecondView), host.Content.GetType());
+            Assert.Equal(second, ((SecondView)host.Content).DataContext);
+            Assert.Equal(second, ((SecondView)host.Content).ViewModel);
+
+            host.ViewModel = null;
+            Assert.NotNull(host.Content);
+            Assert.Equal(typeof(TextBlock), host.Content.GetType());
+            Assert.Equal(defaultContent, host.Content);
+
+            host.ViewModel = first;
+            Assert.NotNull(host.Content);
+            Assert.Equal(typeof(FirstView), host.Content.GetType());
+            Assert.Equal(first, ((FirstView)host.Content).DataContext);
+            Assert.Equal(first, ((FirstView)host.Content).ViewModel);
+        }
+    }
+}