diff --git a/WotBlitzStatisticsPro.Blazor.Tests/MockNavigationManager.cs b/WotBlitzStatisticsPro.Blazor.Tests/MockNavigationManager.cs new file mode 100644 index 0000000..e52c673 --- /dev/null +++ b/WotBlitzStatisticsPro.Blazor.Tests/MockNavigationManager.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Components; + +namespace WotBlitzStatisticsPro.Blazor.Tests +{ + public class MockNavigationManager: NavigationManager + { + public int NavigationCount { get; private set; } = 0; + + public MockNavigationManager() + { + Initialize("https://unit-test.example/", "https://unit-test.example/bla-bla"); + } + + + protected override void NavigateToCore(string uri, bool forceLoad) + { + if (uri == "/") + { + Uri = BaseUri; + } + else if (uri.StartsWith("/") && uri.Length > 1) + { + Uri = $"{BaseUri}{uri.Substring(1)}"; + } + NotifyLocationChanged(false); + + NavigationCount++; + } + } +} \ No newline at end of file diff --git a/WotBlitzStatisticsPro.Blazor.Tests/MainLayoutTest.cs b/WotBlitzStatisticsPro.Blazor.Tests/Pages/MainLayoutTest.cs similarity index 60% rename from WotBlitzStatisticsPro.Blazor.Tests/MainLayoutTest.cs rename to WotBlitzStatisticsPro.Blazor.Tests/Pages/MainLayoutTest.cs index b607e23..0b0686c 100644 --- a/WotBlitzStatisticsPro.Blazor.Tests/MainLayoutTest.cs +++ b/WotBlitzStatisticsPro.Blazor.Tests/Pages/MainLayoutTest.cs @@ -1,41 +1,28 @@ using System.Threading; using Bunit; using FluentAssertions; -using MediatR; -using Microsoft.Extensions.DependencyInjection; using Moq; using NUnit.Framework; -using Radzen; using WotBlitzStatisticsPro.Blazor.Messages; -using WotBlitzStatisticsPro.Blazor.Services; using WotBlitzStatisticsPro.Blazor.Shared; -namespace WotBlitzStatisticsPro.Blazor.Tests +namespace WotBlitzStatisticsPro.Blazor.Tests.Pages { - public class MainLayoutTest: TestContextWrapper + public class MainLayoutTest: TestContextBase { - private readonly Mock _mediatorMock = new(); - private readonly Mock _searchServiceMock = new(); private IRenderedComponent _component; [SetUp] public void Setup() { - TestContext = new Bunit.TestContext(); - TestContext.Services.AddSingleton(_mediatorMock.Object); - - TestContext.Services.AddSingleton(); - TestContext.Services.AddSingleton(_searchServiceMock.Object); - TestContext.Services.AddLocalization(); - - _component = TestContext.RenderComponent(); + _component = TestContext?.RenderComponent(); } [Test] public void ShouldFireMediatorEventEachTimeWhenLanguageChanged() { // ===================================== - // Hint for css lookup + // Hint for css selector /* By.css('.classname') // get by class name By.css('input[type=radio]') // get input by type radio @@ -57,13 +44,10 @@ By.css('.parent .child') // get child who has a parent for (int i = 0; i < 3; i++) { elements[i].Click(); - _mediatorMock.Verify(m => m.Publish( + MediatorMock.Verify(m => m.Publish( It.Is(m => m.CultureName == expectedLanguages[0]), It.IsAny()), Times.Once); } } - - [TearDown] - public void TearDown() => TestContext?.Dispose(); } } \ No newline at end of file diff --git a/WotBlitzStatisticsPro.Blazor.Tests/Pages/NavMenuAndIndexPageTests.cs b/WotBlitzStatisticsPro.Blazor.Tests/Pages/NavMenuAndIndexPageTests.cs new file mode 100644 index 0000000..1b8c2f4 --- /dev/null +++ b/WotBlitzStatisticsPro.Blazor.Tests/Pages/NavMenuAndIndexPageTests.cs @@ -0,0 +1,108 @@ +using System; +using System.Threading; +using AngleSharp.Dom; +using Bunit; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using WotBlitzStatisticsPro.Blazor.Messages; +using WotBlitzStatisticsPro.Blazor.Model; +using WotBlitzStatisticsPro.Blazor.Shared; +using Index = WotBlitzStatisticsPro.Blazor.Pages.Index; + +namespace WotBlitzStatisticsPro.Blazor.Tests.Pages +{ + public class NavMenuAndIndexPageTests: TestContextBase + { + public enum ComponentType + { + NavMenu, + Index + } + + private IRenderedComponent _navMenuComponent; + private IRefreshableElementCollection _navMenuElements; + private IRenderedComponent _indexComponent; + private IRefreshableElementCollection _indexButtons; + + + [SetUp] + public void Setup() + { + _navMenuComponent = TestContext?.RenderComponent(); + _indexComponent = TestContext?.RenderComponent(); + + _navMenuElements = _navMenuComponent?.FindAll(".rz-navigation-item"); + _navMenuElements.Should().NotBeNull(); + _navMenuElements?.Count.Should().Be(4); + + _indexButtons = _indexComponent?.FindAll(".rz-button"); + _indexButtons.Should().NotBeNull(); + _indexButtons?.Count.Should().Be(3); + + + } + + [Test] + public void MavMenuShouldNavigateToRootWhenHomePressed() + { + var homeElement = _navMenuElements[0]; + homeElement.Should().NotBeNull(); + + homeElement.Click(); + + NavigationManagerMock.Uri.Should().Be(NavigationManagerMock.BaseUri); + } + + [TestCase(ComponentType.NavMenu)] + [TestCase(ComponentType.Index)] + public void ShouldFireLoginMediatorEventWhenElementClicked(ComponentType componentType) + { + var targetElement = componentType switch + { + ComponentType.NavMenu => _navMenuElements[1], + ComponentType.Index => _indexButtons[0], + _ => throw new ArgumentOutOfRangeException(nameof(componentType), componentType, null) + }; + targetElement.Click(); + + MediatorMock.Verify(m => m.Publish(It.IsAny(), It.IsAny()), Times.Once); + } + + [TestCase(ComponentType.NavMenu)] + [TestCase(ComponentType.Index)] + public void ShouldFireOpenPlayerSearchMediatorEventWhenElementClicked(ComponentType componentType) + { + var targetElement = componentType switch + { + ComponentType.NavMenu => _navMenuElements[2], + ComponentType.Index => _indexButtons[1], + _ => throw new ArgumentOutOfRangeException(nameof(componentType), componentType, null) + }; + targetElement.Click(); + + MediatorMock.Verify(m => m.Publish( + It.Is(m => m.Type == DialogType.FindPlayer), + It.IsAny()), Times.Once); + } + + [TestCase(ComponentType.NavMenu)] + [TestCase(ComponentType.Index)] + public void ShouldFireOpenClansSearchMediatorEventWhenElementClicked(ComponentType componentType) + { + var targetElement = componentType switch + { + ComponentType.NavMenu => _navMenuElements[3], + ComponentType.Index => _indexButtons[2], + _ => throw new ArgumentOutOfRangeException(nameof(componentType), componentType, null) + }; + targetElement.Click(); + + MediatorMock.Verify(m => m.Publish( + It.Is(m => m.Type == DialogType.FindClan), + It.IsAny()), Times.Once); + + } + + } +} \ No newline at end of file diff --git a/WotBlitzStatisticsPro.Blazor.Tests/Pages/SearchDialogTests.cs b/WotBlitzStatisticsPro.Blazor.Tests/Pages/SearchDialogTests.cs new file mode 100644 index 0000000..5fba31b --- /dev/null +++ b/WotBlitzStatisticsPro.Blazor.Tests/Pages/SearchDialogTests.cs @@ -0,0 +1,29 @@ +using Bunit; +using NUnit.Framework; +using WotBlitzStatisticsPro.Blazor.Model; +using WotBlitzStatisticsPro.Blazor.Pages; + +namespace WotBlitzStatisticsPro.Blazor.Tests.Pages +{ + public class SearchDialogTests: TestContextBase + { + private IRenderedComponent _component; + + + [SetUp] + public void Setup() + { + _component = TestContext?.RenderComponent(); + } + + + [TestCase(DialogType.FindPlayer)] + [TestCase(DialogType.FindClan)] + [Ignore("Search component is not implemented yet")] + public void ShouldRedirectToAppropriatePageWhenOkButtonClicked(DialogType dialogType) + { + // Find OK button by CSS and click + // Check OpenPlayerInfoMessage with appropriate accountId/clanId + } + } +} \ No newline at end of file diff --git a/WotBlitzStatisticsPro.Blazor.Tests/Services/LocalStorageServiceTests.cs b/WotBlitzStatisticsPro.Blazor.Tests/Services/LocalStorageServiceTests.cs new file mode 100644 index 0000000..0dc4b91 --- /dev/null +++ b/WotBlitzStatisticsPro.Blazor.Tests/Services/LocalStorageServiceTests.cs @@ -0,0 +1,64 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Bunit; +using FluentAssertions; +using Microsoft.AspNetCore.Components; +using Moq; +using NUnit.Framework; +using WotBlitzStatisticsPro.Blazor.Messages; +using WotBlitzStatisticsPro.Blazor.Model; +using WotBlitzStatisticsPro.Blazor.Services; +using TestContext = Bunit.TestContext; + +namespace WotBlitzStatisticsPro.Blazor.Tests.Services +{ + public class LocalStorageServiceTests + { + private TestContext _testContext; + private BunitJSInterop _jsRuntimeMock; + protected MockNavigationManager _navigationManagerMock; + + private LocalStorageService _localStorageService; + + + [SetUp] + public void Setup() + { + _navigationManagerMock = new MockNavigationManager(); + + _testContext = new TestContext(); + _jsRuntimeMock = _testContext.JSInterop; + _jsRuntimeMock.Setup("localStorage.getItem", UserSettings.UserSettingsLocalStorageKey).SetResult(string.Empty); + var localStorageSetItemHandler = _jsRuntimeMock.SetupVoid("localStorage.setItem", _ => true); + localStorageSetItemHandler.SetVoidResult(); + + _localStorageService = new LocalStorageService(_jsRuntimeMock.JSRuntime, _navigationManagerMock); + } + + [Test] + public async Task ShouldInvokeJsLocalStorageSetWithAppropriateDataOnChangeCurrentCulture() + { + string cultureName = "fake-CL"; + + await _localStorageService.Handle(new ChangeCurrentCultureMessage(cultureName), CancellationToken.None); + + _jsRuntimeMock.Invocations.Count.Should().Be(2); + var jsInvocations = _jsRuntimeMock.Invocations.ToArray(); + jsInvocations[0].Identifier.Should().Be("localStorage.getItem"); + jsInvocations[1].Identifier.Should().Be("localStorage.setItem"); + + var args = jsInvocations[1].Arguments; + args.Should().NotBeNull(); + args.Count.Should().Be(2); + args[0].Should().Be("user-settings"); + args[1].Should().Be($"{{\"Culture\":\"{cultureName}\"}}"); + + _navigationManagerMock.NavigationCount.Should().Be(1); + } + + [TearDown] + public void TearDown() => _testContext?.Dispose(); + + } +} \ No newline at end of file diff --git a/WotBlitzStatisticsPro.Blazor.Tests/Services/NavigatorInterceptorTests.cs b/WotBlitzStatisticsPro.Blazor.Tests/Services/NavigatorInterceptorTests.cs new file mode 100644 index 0000000..b39622c --- /dev/null +++ b/WotBlitzStatisticsPro.Blazor.Tests/Services/NavigatorInterceptorTests.cs @@ -0,0 +1,34 @@ +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using NUnit.Framework; +using WotBlitzStatisticsPro.Blazor.Messages; +using WotBlitzStatisticsPro.Blazor.Services; + +namespace WotBlitzStatisticsPro.Blazor.Tests.Services +{ + public class NavigatorInterceptorTests + { + private NavigationMessagesInterceptor _service; + private MockNavigationManager _navigationManager; + + [SetUp] + public void Setup() + { + _navigationManager = new MockNavigationManager(); + _service = new NavigationMessagesInterceptor(_navigationManager); + + } + + [Test] + public async Task ShouldNavigateToAppropriateLinkWhenOpenPlayerInfoMessageArrived() + { + int accountId = 42; + var message = new OpenPlayerInfoMessage(accountId, false); + + await _service.Handle(message, CancellationToken.None); + + _navigationManager.Uri.Should().Be($"{_navigationManager.BaseUri}player/{accountId}"); + } + } +} \ No newline at end of file diff --git a/WotBlitzStatisticsPro.Blazor.Tests/TestContextBase.cs b/WotBlitzStatisticsPro.Blazor.Tests/TestContextBase.cs new file mode 100644 index 0000000..0853458 --- /dev/null +++ b/WotBlitzStatisticsPro.Blazor.Tests/TestContextBase.cs @@ -0,0 +1,39 @@ +using Bunit; +using MediatR; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using NUnit.Framework; +using Radzen; +using WotBlitzStatisticsPro.Blazor.Services; + +namespace WotBlitzStatisticsPro.Blazor.Tests +{ + public class TestContextBase: TestContextWrapper + { + protected Mock MediatorMock; + protected Mock SearchServiceMock; + protected MockNavigationManager NavigationManagerMock; + + [SetUp] + protected void Init() + { + MediatorMock = new(); + SearchServiceMock = new(); + NavigationManagerMock = new(); + + TestContext = new Bunit.TestContext(); + TestContext.Services.AddSingleton(MediatorMock.Object); + TestContext.Services.AddLocalization(); + + TestContext.Services.AddSingleton(); + TestContext.Services.AddSingleton(SearchServiceMock.Object); + + + TestContext.Services.AddSingleton(NavigationManagerMock); + } + + [TearDown] + public void TearDown() => TestContext?.Dispose(); + } +} \ No newline at end of file