mirror of
https://github.com/DrMboga/WotBlitzStatisticsBlazor.git
synced 2026-10-23 19:30:06 +02:00
feat: saving logged-in user to local storage + tests
This commit is contained in:
1 parent
07cda06fea
commit
6cbb809f44
8 files changed
+264
-13
No files matched your search
@@ -0,0 +1,31 @@
|
|||||||
|
using Bunit;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Threading;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.Messages;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.Pages;
|
||||||
|
|
||||||
|
namespace WotBlitzStatisticsPro.Blazor.Tests.Pages
|
||||||
|
{
|
||||||
|
public class LoginPageTests: TestContextBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void ShouldParseLoginDataAndSendRedirectFromWgLoginMessage()
|
||||||
|
{
|
||||||
|
string accessToken = "fake_token";
|
||||||
|
string nickname = "fake_nick";
|
||||||
|
long accountId = 123456789;
|
||||||
|
long expiration = 987654321;
|
||||||
|
NavigationManagerMock.NavigateTo($"/login?&status=ok&access_token={accessToken}&nickname={nickname}&account_id={accountId}&expires_at={expiration}");
|
||||||
|
|
||||||
|
var component = TestContext.RenderComponent<Login>();
|
||||||
|
|
||||||
|
MediatorMock.Verify(m => m.Publish(
|
||||||
|
It.Is<RedirectFromWgLoginMessage>(m => m.AccessToken == accessToken &&
|
||||||
|
m.NickName == nickname &&
|
||||||
|
m.AccountId == accountId &&
|
||||||
|
m.ExpiresAt == expiration),
|
||||||
|
It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
using Bunit;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.GraphQl;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.Messages;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.Model;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.Pages;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.Services;
|
||||||
|
|
||||||
|
namespace WotBlitzStatisticsPro.Blazor.Tests.Pages
|
||||||
|
{
|
||||||
|
public class WgLoginDialogTests: TestContextBase
|
||||||
|
{
|
||||||
|
private UserSettings _settings;
|
||||||
|
private IRenderedComponent<WgLoginDialog> _component;
|
||||||
|
private Mock<ILocalStorageService> _localStorageServiceMock;
|
||||||
|
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_settings = new();
|
||||||
|
|
||||||
|
_localStorageServiceMock = new();
|
||||||
|
_localStorageServiceMock.Setup(s => s.ReadSettings()).ReturnsAsync(_settings);
|
||||||
|
|
||||||
|
TestContext?.Services.AddSingleton(_localStorageServiceMock.Object);
|
||||||
|
|
||||||
|
TestContext?.JSInterop.SetupVoid("Radzen.preventArrows", _ => true).SetVoidResult();
|
||||||
|
TestContext?.JSInterop.SetupVoid("Radzen.closePopup", _ => true).SetVoidResult();
|
||||||
|
|
||||||
|
_component = TestContext?.RenderComponent<WgLoginDialog>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShouldChangeRealmPropertiesWhenDropDownSelectedChanged()
|
||||||
|
{
|
||||||
|
// Default realm is Eu
|
||||||
|
_component.Instance.CurrentRealmType.Should().Be(RealmType.Eu);
|
||||||
|
|
||||||
|
// Find 4 dropdown items
|
||||||
|
var items = _component.FindAll(".rz-dropdown-item");
|
||||||
|
items.Should().NotBeNull();
|
||||||
|
items.Count.Should().Be(4);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
// Asia is the last dropdown item
|
||||||
|
var asiaItem = items[3];
|
||||||
|
asiaItem.Click();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_component.Instance.CurrentRealmType.Should().Be(RealmType.Asia);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShouldNotSendLoginMessageWhenCancelClicked()
|
||||||
|
{
|
||||||
|
var buttons = _component.FindAll(".rz-button");
|
||||||
|
buttons.Should().NotBeNull();
|
||||||
|
buttons.Count.Should().Be(2);
|
||||||
|
|
||||||
|
// Cancel is first
|
||||||
|
buttons[0].Click();
|
||||||
|
|
||||||
|
// Should not send any messages to mediator
|
||||||
|
MediatorMock.Verify(m => m.Publish(
|
||||||
|
It.IsAny<RedirectToWgLoginMessage>(),
|
||||||
|
It.IsAny<CancellationToken>()), Times.Never);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShouldSendRedirectToWgMessageWhenOkClicked()
|
||||||
|
{
|
||||||
|
var realm = RealmType.Na;
|
||||||
|
_component.Instance.CurrentRealmType = realm;
|
||||||
|
var buttons = _component.FindAll(".rz-button");
|
||||||
|
buttons.Should().NotBeNull();
|
||||||
|
buttons.Count.Should().Be(2);
|
||||||
|
|
||||||
|
// OK is the second one
|
||||||
|
buttons[1].Click();
|
||||||
|
|
||||||
|
// Should send messages to mediator with appropriate Realm
|
||||||
|
MediatorMock.Verify(m => m.Publish(
|
||||||
|
It.Is<RedirectToWgLoginMessage>(m => m.Realm == realm),
|
||||||
|
It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,6 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bunit;
|
using Bunit;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Microsoft.AspNetCore.Components;
|
|
||||||
using Moq;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using WotBlitzStatisticsPro.Blazor.GraphQl;
|
using WotBlitzStatisticsPro.Blazor.GraphQl;
|
||||||
using WotBlitzStatisticsPro.Blazor.Messages;
|
using WotBlitzStatisticsPro.Blazor.Messages;
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Radzen;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.GraphQl;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.Messages;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.Model;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.Services;
|
||||||
|
|
||||||
|
namespace WotBlitzStatisticsPro.Blazor.Tests.Services
|
||||||
|
{
|
||||||
|
public class WargamingLoginServiceTests: TestContextBase
|
||||||
|
{
|
||||||
|
private Mock<IGraphQlBackendService> _graphQlBackendMock;
|
||||||
|
private Mock<ILocalStorageService> _localStorageMock;
|
||||||
|
|
||||||
|
private WargamingLoginService _service;
|
||||||
|
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_graphQlBackendMock = new();
|
||||||
|
_localStorageMock = new();
|
||||||
|
|
||||||
|
_service = new WargamingLoginService(
|
||||||
|
_graphQlBackendMock.Object,
|
||||||
|
TestContext.Services.GetService<DialogService>(),
|
||||||
|
TestContext.Services.GetService<IStringLocalizer<App>>(),
|
||||||
|
NavigationManagerMock,
|
||||||
|
_localStorageMock.Object,
|
||||||
|
MediatorMock.Object
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ShouldRequestRedirectUrlFromBackendWhenRedirectToWgLoginMessageArrives()
|
||||||
|
{
|
||||||
|
var realm = RealmType.Eu;
|
||||||
|
string url = "/fakeUrl";
|
||||||
|
_graphQlBackendMock.Setup(b => b.GetWgLoginUrl(realm)).ReturnsAsync(url);
|
||||||
|
await _service.Handle(new RedirectToWgLoginMessage(realm), CancellationToken.None);
|
||||||
|
|
||||||
|
_graphQlBackendMock.Verify(b => b.GetWgLoginUrl(realm), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ShouldNavigateToAppropriateUrlWhenRedirectToWgLoginMessageArrives()
|
||||||
|
{
|
||||||
|
var realm = RealmType.Eu;
|
||||||
|
string url = "/fakeUrl";
|
||||||
|
_graphQlBackendMock.Setup(b => b.GetWgLoginUrl(It.IsAny<RealmType>())).ReturnsAsync(url);
|
||||||
|
await _service.Handle(new RedirectToWgLoginMessage(realm), CancellationToken.None);
|
||||||
|
|
||||||
|
NavigationManagerMock.NavigationCount.Should().Be(1);
|
||||||
|
NavigationManagerMock.Uri.Should().Be($"https://unit-test.example{url}&redirect_uri=https://unit-test.example/login/{realm}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ShouldStoreAppropriateDataToLocalStorageWhenRedirectFromWgLoginMessageArrives()
|
||||||
|
{
|
||||||
|
var realm = RealmType.Asia;
|
||||||
|
string nick = "fakeNick";
|
||||||
|
string token = "fakeToken";
|
||||||
|
long accountId = 123456789;
|
||||||
|
long expiration = 987654321;
|
||||||
|
|
||||||
|
await _service.Handle(new RedirectFromWgLoginMessage(realm, nick, accountId, token, expiration), CancellationToken.None);
|
||||||
|
|
||||||
|
_localStorageMock.Verify(s => s.SetItemAsync<LoginInfo>(
|
||||||
|
Constants.LoginInfoLocalStorageKey,
|
||||||
|
It.Is<LoginInfo>(l => l.Realm == realm && l.NickName == nick && l.AccountId == accountId && l.AccessToken == token && l.ExpiresAt == expiration))
|
||||||
|
, Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ShouldFireOnPlayerInfoMessageWhenRedirectFromWgLoginMessageArrives()
|
||||||
|
{
|
||||||
|
var realm = RealmType.Asia;
|
||||||
|
string nick = "fakeNick";
|
||||||
|
string token = "fakeToken";
|
||||||
|
long accountId = 123456789;
|
||||||
|
long expiration = 987654321;
|
||||||
|
|
||||||
|
await _service.Handle(new RedirectFromWgLoginMessage(realm, nick, accountId, token, expiration), CancellationToken.None);
|
||||||
|
|
||||||
|
MediatorMock.Verify(m => m.Publish(
|
||||||
|
It.Is<OpenPlayerInfoMessage>(m => m.AccountId == accountId && m.IsLoggedIn),
|
||||||
|
It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,5 +39,7 @@
|
|||||||
public const string CountryOther = "other";
|
public const string CountryOther = "other";
|
||||||
public const string CountryEuropean = "european";
|
public const string CountryEuropean = "european";
|
||||||
|
|
||||||
|
|
||||||
|
public const string LoginInfoLocalStorageKey = "login_info";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using WotBlitzStatisticsPro.Blazor.GraphQl;
|
||||||
|
|
||||||
|
namespace WotBlitzStatisticsPro.Blazor.Model
|
||||||
|
{
|
||||||
|
public class LoginInfo
|
||||||
|
{
|
||||||
|
public RealmType Realm { get; set; }
|
||||||
|
public string NickName { get; set; }
|
||||||
|
public long AccountId { get; set; }
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
public long ExpiresAt { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<RadzenLabel Text=@Localize["Region"] />
|
<RadzenLabel Text=@Localize["Region"] />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<RadzenDropDown @bind-Value=@_currentRealmType
|
<RadzenDropDown @bind-Value=@CurrentRealmType
|
||||||
Data=@_realms
|
Data=@_realms
|
||||||
ValueProperty="RealmType"
|
ValueProperty="RealmType"
|
||||||
Style="margin-bottom: 10px; width: 87px"
|
Style="margin-bottom: 10px; width: 87px"
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
RealmType _currentRealmType = RealmType.Eu;
|
public RealmType CurrentRealmType { get; set; } = RealmType.Eu;
|
||||||
|
|
||||||
readonly List<RealmSelector> _realms = new()
|
readonly List<RealmSelector> _realms = new()
|
||||||
{
|
{
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
var settings = await LocalStorageService.ReadSettings();
|
var settings = await LocalStorageService.ReadSettings();
|
||||||
_currentRealmType = settings.RealmType;
|
CurrentRealmType = settings.RealmType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnRealmChanged(object value)
|
public async Task OnRealmChanged(object value)
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
|
|
||||||
public async Task RedirectToWg()
|
public async Task RedirectToWg()
|
||||||
{
|
{
|
||||||
await Mediator.Publish(new RedirectToWgLoginMessage(_currentRealmType));
|
await Mediator.Publish(new RedirectToWgLoginMessage(CurrentRealmType));
|
||||||
|
|
||||||
DialogService.Close(true);
|
DialogService.Close(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Threading;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Radzen;
|
using Radzen;
|
||||||
using WotBlitzStatisticsPro.Blazor.Messages;
|
using WotBlitzStatisticsPro.Blazor.Messages;
|
||||||
|
using WotBlitzStatisticsPro.Blazor.Model;
|
||||||
using WotBlitzStatisticsPro.Blazor.Pages;
|
using WotBlitzStatisticsPro.Blazor.Pages;
|
||||||
|
|
||||||
namespace WotBlitzStatisticsPro.Blazor.Services
|
namespace WotBlitzStatisticsPro.Blazor.Services
|
||||||
@@ -19,17 +19,23 @@ namespace WotBlitzStatisticsPro.Blazor.Services
|
|||||||
private readonly DialogService _dialogService;
|
private readonly DialogService _dialogService;
|
||||||
private readonly IStringLocalizer<App> _localizer;
|
private readonly IStringLocalizer<App> _localizer;
|
||||||
private readonly NavigationManager _navigationManager;
|
private readonly NavigationManager _navigationManager;
|
||||||
|
private readonly ILocalStorageService _localStorage;
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
public WargamingLoginService(
|
public WargamingLoginService(
|
||||||
IGraphQlBackendService graphQlBackendService,
|
IGraphQlBackendService graphQlBackendService,
|
||||||
DialogService dialogService,
|
DialogService dialogService,
|
||||||
IStringLocalizer<App> localizer,
|
IStringLocalizer<App> localizer,
|
||||||
NavigationManager navigationManager)
|
NavigationManager navigationManager,
|
||||||
|
ILocalStorageService localStorage,
|
||||||
|
IMediator mediator)
|
||||||
{
|
{
|
||||||
_graphQlBackendService = graphQlBackendService;
|
_graphQlBackendService = graphQlBackendService;
|
||||||
_dialogService = dialogService;
|
_dialogService = dialogService;
|
||||||
_localizer = localizer;
|
_localizer = localizer;
|
||||||
_navigationManager = navigationManager;
|
_navigationManager = navigationManager;
|
||||||
|
_localStorage = localStorage;
|
||||||
|
_mediator = mediator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(LoginToWgMessage notification, CancellationToken cancellationToken)
|
public async Task Handle(LoginToWgMessage notification, CancellationToken cancellationToken)
|
||||||
@@ -49,11 +55,18 @@ namespace WotBlitzStatisticsPro.Blazor.Services
|
|||||||
_navigationManager.NavigateTo(url);
|
_navigationManager.NavigateTo(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Handle(RedirectFromWgLoginMessage notification, CancellationToken cancellationToken)
|
public async Task Handle(RedirectFromWgLoginMessage notification, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// ToDo: Store login info to local storage
|
// Store login info to local storage
|
||||||
// ToDo: Send OpenPlayerInfoMessage with isLoggedIn = true
|
await _localStorage.SetItemAsync(Constants.LoginInfoLocalStorageKey, new LoginInfo {
|
||||||
return Task.CompletedTask;
|
Realm = notification.Realm,
|
||||||
|
AccessToken = notification.AccessToken,
|
||||||
|
AccountId = notification.AccountId,
|
||||||
|
ExpiresAt = notification.ExpiresAt,
|
||||||
|
NickName = notification.NickName, });
|
||||||
|
|
||||||
|
// Send OpenPlayerInfoMessage with isLoggedIn = true
|
||||||
|
await _mediator.Publish(new OpenPlayerInfoMessage(notification.AccountId, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user