Browse Source

Add a unit test for ViewModelViewHost

pull/2560/head
artyom 7 years ago
parent
commit
97b44c02d2
  1. 27
      src/Avalonia.ReactiveUI/ViewModelViewHost.cs
  2. 6
      tests/Avalonia.ReactiveUI.UnitTests/Attributes.cs
  3. 2
      tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs
  4. 2
      tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs
  5. 72
      tests/Avalonia.ReactiveUI.UnitTests/ViewModelViewHostTest.cs

27
src/Avalonia.ReactiveUI/ViewModelViewHost.cs

@ -1,6 +1,8 @@
// Copyright (c) The Avalonia Project. All rights reserved. // 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. // 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 ReactiveUI;
using Splat; using Splat;
@ -18,7 +20,20 @@ namespace Avalonia.ReactiveUI
/// </summary> /// </summary>
public static readonly AvaloniaProperty<object> ViewModelProperty = public static readonly AvaloniaProperty<object> ViewModelProperty =
AvaloniaProperty.Register<ViewModelViewHost, object>(nameof(ViewModel)); 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> /// <summary>
/// Gets or sets the ViewModel to display. /// Gets or sets the ViewModel to display.
/// </summary> /// </summary>
@ -33,16 +48,6 @@ namespace Avalonia.ReactiveUI
/// </summary> /// </summary>
public IViewLocator ViewLocator { get; set; } 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> /// <summary>
/// Invoked when ReactiveUI router navigates to a view model. /// Invoked when ReactiveUI router navigates to a view model.
/// </summary> /// </summary>

6
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)]

2
tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs

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

2
tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs

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

72
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);
}
}
}
Loading…
Cancel
Save