using FluentAssertions; using WebClientTpos.Client.Services; using Xunit; namespace WebClientTpos.ComponentTests.Services; /// /// 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. /// 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); } }