- packages/logger: upgrade tsconfig target to ES2022 to support Array.at() - packages/http-client: exclude test files from tsc build to prevent noUnusedLocals errors - packages/http-client/test: use vi.hoisted() for mock functions (vi.mock hoisting fix) - services/goodgo-mcp-server/tests: use vi.hoisted() for all 4 test files (catalog, inventory, analytics, recipe) - web-client-tpos: remove stale @using WebClientTpos.Client.Components.Auth from 10 auth pages (moved to blazor-ui RCL) - web-client-tpos: remove AttachToken() calls in PosDataService (auth via BFF httpOnly cookie) - web-client-tpos: fix IamApiService.SetAuthHeader() and MerchantApiService.AttachTokenAsync() — make no-op, remove _auth dependency - web-client-tpos: fix Profile.razor — remove AttachToken() method and calls - web-client-tpos: fix OnboardingReady.razor — escape @keyframes → @@keyframes in Razor style block - web-client-tpos: fix PosDataService.GetListFromApiAsync() — check array before property lookup to fix plain array deserialization - web-client-tpos/tests: update AuthStateServiceTests to new AuthStateService.Login(email, role) signature (no token param) - web-client-tpos/tests: update PosDataServiceTests to new PosDataService(http) constructor (no authState param) All 113 Node.js tests pass. All 30 .NET component tests pass. All .NET builds succeed. Co-Authored-By: Paperclip <noreply@paperclip.ing>
203 lines
5.4 KiB
C#
203 lines
5.4 KiB
C#
using FluentAssertions;
|
|
using WebClientTpos.Client.Services;
|
|
using Xunit;
|
|
|
|
namespace WebClientTpos.ComponentTests.Services;
|
|
|
|
/// <summary>
|
|
/// EN: Unit tests for AuthStateService — singleton tracking auth state in the POS app.
|
|
/// Token is managed by BFF httpOnly cookie; this service only tracks email, role, expiry.
|
|
/// VI: Unit tests cho AuthStateService — singleton theo dõi trạng thái auth trong POS app.
|
|
/// Token được quản lý bởi BFF httpOnly cookie; service này chỉ lưu email, role, expiry.
|
|
/// </summary>
|
|
public class AuthStateServiceTests
|
|
{
|
|
private static AuthStateService CreateSut() => new();
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Initial state
|
|
// -----------------------------------------------------------------------
|
|
|
|
[Fact]
|
|
public void InitialState_ShouldNotBeAuthenticated()
|
|
{
|
|
// Arrange & Act
|
|
var sut = CreateSut();
|
|
|
|
// Assert
|
|
sut.IsAuthenticated.Should().BeFalse();
|
|
sut.UserEmail.Should().BeNull();
|
|
sut.UserRole.Should().BeNull();
|
|
sut.TokenExpiry.Should().BeNull();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Login
|
|
// -----------------------------------------------------------------------
|
|
|
|
[Fact]
|
|
public void Login_WithValidCredentials_ShouldSetAuthenticatedState()
|
|
{
|
|
// Arrange
|
|
var sut = CreateSut();
|
|
|
|
// Act
|
|
sut.Login("owner@goodgo.vn", "owner");
|
|
|
|
// Assert
|
|
sut.IsAuthenticated.Should().BeTrue();
|
|
sut.UserEmail.Should().Be("owner@goodgo.vn");
|
|
sut.UserRole.Should().Be("owner");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("owner")]
|
|
[InlineData("staff")]
|
|
[InlineData("customer")]
|
|
[InlineData("branch")]
|
|
public void Login_WithAnyRole_ShouldSetRole(string role)
|
|
{
|
|
// Arrange
|
|
var sut = CreateSut();
|
|
|
|
// Act
|
|
sut.Login("user@goodgo.vn", role);
|
|
|
|
// Assert
|
|
sut.UserRole.Should().Be(role);
|
|
}
|
|
|
|
[Fact]
|
|
public void Login_CalledTwiceWithSameData_ShouldNotFireOnChange()
|
|
{
|
|
// Arrange
|
|
var sut = CreateSut();
|
|
sut.Login("user@goodgo.vn", "owner");
|
|
var changeCount = 0;
|
|
sut.OnChange += () => changeCount++;
|
|
|
|
// Act — same email + same role again
|
|
sut.Login("user@goodgo.vn", "owner");
|
|
|
|
// Assert
|
|
// EN: Idempotent login must not trigger OnChange / VI: Login idempotent không kích hoạt OnChange
|
|
changeCount.Should().Be(0);
|
|
}
|
|
|
|
[Fact]
|
|
public void Login_WithNewRole_ShouldFireOnChange()
|
|
{
|
|
// Arrange
|
|
var sut = CreateSut();
|
|
sut.Login("user@goodgo.vn", "staff");
|
|
var changeCount = 0;
|
|
sut.OnChange += () => changeCount++;
|
|
|
|
// Act
|
|
sut.Login("user@goodgo.vn", "owner");
|
|
|
|
// Assert
|
|
changeCount.Should().BeGreaterThan(0);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Logout
|
|
// -----------------------------------------------------------------------
|
|
|
|
[Fact]
|
|
public void Logout_AfterLogin_ShouldClearState()
|
|
{
|
|
// Arrange
|
|
var sut = CreateSut();
|
|
sut.Login("owner@goodgo.vn", "owner");
|
|
|
|
// Act
|
|
sut.Logout();
|
|
|
|
// Assert
|
|
sut.IsAuthenticated.Should().BeFalse();
|
|
sut.UserEmail.Should().BeNull();
|
|
sut.UserRole.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Logout_ShouldFireOnChange()
|
|
{
|
|
// Arrange
|
|
var sut = CreateSut();
|
|
sut.Login("user@goodgo.vn", "staff");
|
|
var fired = false;
|
|
sut.OnChange += () => fired = true;
|
|
|
|
// Act
|
|
sut.Logout();
|
|
|
|
// Assert
|
|
fired.Should().BeTrue();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// GetPortalUrl
|
|
// -----------------------------------------------------------------------
|
|
|
|
[Theory]
|
|
[InlineData("owner", "/admin")]
|
|
[InlineData("admin", "/admin")]
|
|
[InlineData("staff", "/staff/dashboard")]
|
|
[InlineData("branch", "/admin")]
|
|
[InlineData("customer", "/app")]
|
|
[InlineData("unknown", "/auth/login")]
|
|
[InlineData(null, "/auth/login")]
|
|
public void GetPortalUrl_ShouldReturnCorrectPathForRole(string? role, string expectedUrl)
|
|
{
|
|
// Arrange
|
|
var sut = CreateSut();
|
|
if (role != null)
|
|
{
|
|
sut.Login("user@goodgo.vn", role);
|
|
}
|
|
|
|
// Act
|
|
var url = sut.GetPortalUrl();
|
|
|
|
// Assert
|
|
url.Should().Be(expectedUrl);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// OnChange event
|
|
// -----------------------------------------------------------------------
|
|
|
|
[Fact]
|
|
public void OnChange_ShouldBeRaisedOnLogin()
|
|
{
|
|
// Arrange
|
|
var sut = CreateSut();
|
|
var raised = false;
|
|
sut.OnChange += () => raised = true;
|
|
|
|
// Act
|
|
sut.Login("new@goodgo.vn", "owner");
|
|
|
|
// Assert
|
|
raised.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void OnChange_MultipleSubscribers_ShouldAllBeNotified()
|
|
{
|
|
// Arrange
|
|
var sut = CreateSut();
|
|
var count = 0;
|
|
sut.OnChange += () => count++;
|
|
sut.OnChange += () => count++;
|
|
sut.OnChange += () => count++;
|
|
|
|
// Act
|
|
sut.Logout();
|
|
|
|
// Assert
|
|
count.Should().Be(3);
|
|
}
|
|
}
|