diff --git a/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsViewPageTests.cs b/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsViewPageTests.cs index 8dbd80ce..1888eab5 100644 --- a/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsViewPageTests.cs +++ b/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsViewPageTests.cs @@ -1,3 +1,4 @@ +using AngleSharp.Dom; using Bunit; using EstateManagementUI.BlazorServer.Components.Pages.Contracts; using EstateManagementUI.BlazorServer.Components.Permissions; @@ -79,4 +80,244 @@ public void ContractsView_HasCorrectPageTitle() var pageTitle = cut.FindComponent(); pageTitle.Instance.ChildContent.ShouldNotBeNull(); } + + [Fact] + public void ContractsView_HasBackButton() + { + // Arrange + var contractId = Guid.NewGuid(); + var contract = new ContractModel + { + ContractId = contractId, + Description = "Test Contract", + OperatorName = "Test Operator" + }; + + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(contract)); + + // Act + var cut = RenderComponent(parameters => parameters + .Add(p => p.ContractId, contractId)); + cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); + + // Assert + cut.Markup.ShouldContain("Back to List"); + } + + [Fact] + public void ContractsView_BackButton_NavigatesToContractsList() + { + // Arrange + var contractId = Guid.NewGuid(); + var contract = new ContractModel + { + ContractId = contractId, + Description = "Test Contract", + OperatorName = "Test Operator" + }; + + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(contract)); + + // Act + var cut = RenderComponent(parameters => parameters + .Add(p => p.ContractId, contractId)); + cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); + + // Find and click the Back to List button + IRefreshableElementCollection buttons = cut.FindAll("button"); + IElement? backButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Back to List")); + backButton.ShouldNotBeNull(); + backButton.Click(); + + // Assert + _fakeNavigationManager.Uri.ShouldContain("/contracts"); + } + + [Fact] + public void ContractsView_DisplaysProducts_WhenPresent() + { + // Arrange + var contractId = Guid.NewGuid(); + var contract = new ContractModel + { + ContractId = contractId, + Description = "Test Contract", + OperatorName = "Test Operator", + Products = new List + { + new ContractProductModel + { + ContractProductId = Guid.NewGuid(), + ProductName = "Test Product", + DisplayText = "Test Display", + ProductType = "MobileTopup", + Value = "100", + NumberOfFees = 2 + } + } + }; + + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(contract)); + + // Act + var cut = RenderComponent(parameters => parameters + .Add(p => p.ContractId, contractId)); + cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); + + // Assert + cut.Markup.ShouldContain("Test Product"); + cut.Markup.ShouldContain("Test Display"); + cut.Markup.ShouldContain("100"); + } + + [Fact] + public void ContractsView_DisplaysNoProducts_WhenEmpty() + { + // Arrange + var contractId = Guid.NewGuid(); + var contract = new ContractModel + { + ContractId = contractId, + Description = "Test Contract", + OperatorName = "Test Operator", + Products = new List() + }; + + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(contract)); + + // Act + var cut = RenderComponent(parameters => parameters + .Add(p => p.ContractId, contractId)); + cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); + + // Assert + cut.Markup.ShouldContain("No products added to this contract yet"); + } + + [Fact] + public void ContractsView_DisplaysTransactionFees_WhenPresent() + { + // Arrange + var contractId = Guid.NewGuid(); + var contract = new ContractModel + { + ContractId = contractId, + Description = "Test Contract", + OperatorName = "Test Operator", + Products = new List + { + new ContractProductModel + { + ContractProductId = Guid.NewGuid(), + ProductName = "Test Product", + DisplayText = "Test Display", + ProductType = "MobileTopup", + Value = "100", + NumberOfFees = 1, + TransactionFees = new List + { + new ContractProductTransactionFeeModel + { + TransactionFeeId = Guid.NewGuid(), + Description = "Service Fee", + CalculationType = 0, + FeeType = 0, + Value = 10.50m + } + } + } + } + }; + + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(contract)); + + // Act + var cut = RenderComponent(parameters => parameters + .Add(p => p.ContractId, contractId)); + cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); + + // Assert + cut.Markup.ShouldContain("Transaction Fees"); + cut.Markup.ShouldContain("Service Fee"); + cut.Markup.ShouldContain("10.50"); + } + + [Fact] + public void ContractsView_LoadContract_QueryFails_ShowsNotFoundMessage() + { + // Arrange + var contractId = Guid.NewGuid(); + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Failure("Failed to load contract")); + + // Act + var cut = RenderComponent(parameters => parameters + .Add(p => p.ContractId, contractId)); + cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); + + // Assert + cut.Markup.ShouldContain("Contract not found"); + } + + [Fact] + public void ContractsView_LoadContract_ReturnsNull_ShowsNotFoundMessage() + { + // Arrange + var contractId = Guid.NewGuid(); + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(null!)); + + // Act + var cut = RenderComponent(parameters => parameters + .Add(p => p.ContractId, contractId)); + cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); + + // Assert + cut.Markup.ShouldContain("Contract not found"); + } + + [Fact] + public void ContractsView_ContractNotFound_HasBackButton() + { + // Arrange + var contractId = Guid.NewGuid(); + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(null!)); + + // Act + var cut = RenderComponent(parameters => parameters + .Add(p => p.ContractId, contractId)); + cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); + + // Assert + cut.Markup.ShouldContain("Back to List"); + } + + [Fact] + public void ContractsView_ContractNotFound_BackButton_NavigatesToContractsList() + { + // Arrange + var contractId = Guid.NewGuid(); + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(null!)); + + // Act + var cut = RenderComponent(parameters => parameters + .Add(p => p.ContractId, contractId)); + cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); + + // Find and click the Back to List button + IRefreshableElementCollection buttons = cut.FindAll("button"); + IElement? backButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Back to List")); + backButton.ShouldNotBeNull(); + backButton.Click(); + + // Assert + _fakeNavigationManager.Uri.ShouldContain("/contracts"); + } }