diff --git a/EstateManagementUI.BlazorServer.Tests/Pages/Operators/OperatorsNewPageTests.cs b/EstateManagementUI.BlazorServer.Tests/Pages/Operators/OperatorsNewPageTests.cs new file mode 100644 index 00000000..e4fe71f1 --- /dev/null +++ b/EstateManagementUI.BlazorServer.Tests/Pages/Operators/OperatorsNewPageTests.cs @@ -0,0 +1,163 @@ +using AngleSharp.Dom; +using Bunit; +using EstateManagementUI.BlazorServer.Models; +using EstateManagementUI.BusinessLogic.Requests; +using Moq; +using Shouldly; +using SimpleResults; +using OperatorsNew = EstateManagementUI.BlazorServer.Components.Pages.Operators.New; + +namespace EstateManagementUI.BlazorServer.Tests.Pages.Operators; + +public class OperatorsNewPageTests : BaseTest +{ + [Fact] + public void OperatorsNew_RendersCorrectly() + { + // Arrange & Act + IRenderedComponent cut = RenderComponent(); + + // Assert + cut.Markup.ShouldContain("Create New Operator"); + } + + [Fact] + public void OperatorsNew_HasCorrectPageTitle() + { + // Arrange & Act + IRenderedComponent cut = RenderComponent(); + + // Assert + IRenderedComponent pageTitle = cut.FindComponent(); + pageTitle.Instance.ChildContent.ShouldNotBeNull(); + } + + [Fact] + public void OperatorsNew_CancelButton_NavigatesToOperatorsIndex() + { + // Arrange + IRenderedComponent cut = RenderComponent(); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Create New Operator"), timeout: TimeSpan.FromSeconds(5)); + + // Act - Find and click the Cancel button + IRefreshableElementCollection buttons = cut.FindAll("button"); + IElement? cancelButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Cancel")); + cancelButton.ShouldNotBeNull(); + cancelButton.Click(); + + // Assert + _fakeNavigationManager.Uri.ShouldContain("/operators"); + } + + [Fact] + public void OperatorsNew_CreateOperatorButton_IsPresent() + { + // Arrange + IRenderedComponent cut = RenderComponent(); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Create New Operator"), timeout: TimeSpan.FromSeconds(5)); + + // Act & Assert + IElement createButton = cut.Find("#createOperatorButton"); + createButton.ShouldNotBeNull(); + } + + [Fact] + public void OperatorsNew_SuccessfulCreation_NavigatesToOperatorsIndex() + { + // Arrange + this.OperatorUIService.Setup(o => o.CreateOperator(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success()); + + IRenderedComponent cut = RenderComponent(); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Create New Operator"), timeout: TimeSpan.FromSeconds(5)); + + // Act - Fill in the form + IElement nameInput = cut.Find("input[placeholder='Enter operator name']"); + nameInput.Change("Test Operator"); + + // Submit the form + IElement createButton = cut.Find("#createOperatorButton"); + createButton.Click(); + + // Assert + cut.WaitForAssertion(() => { + _fakeNavigationManager.Uri.ShouldContain("/operators"); + }, timeout: TimeSpan.FromSeconds(5)); + } + + [Fact] + public void OperatorsNew_FailedCreation_ShowsErrorMessage() + { + // Arrange + this.OperatorUIService.Setup(o => o.CreateOperator(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Failure); + + IRenderedComponent cut = RenderComponent(); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Create New Operator"), timeout: TimeSpan.FromSeconds(5)); + + // Act - Fill in the form + IElement nameInput = cut.Find("input[placeholder='Enter operator name']"); + nameInput.Change("Test Operator"); + + // Submit the form + IElement createButton = cut.Find("#createOperatorButton"); + createButton.Click(); + + // Assert + cut.WaitForAssertion(() => { + cut.Markup.ShouldContain("Failed to create operator"); + }, timeout: TimeSpan.FromSeconds(5)); + } + + [Fact] + public void OperatorsNew_FormValidation_RequiresOperatorName() + { + // Arrange + IRenderedComponent cut = RenderComponent(); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Create New Operator"), timeout: TimeSpan.FromSeconds(5)); + + // Act - Submit form without operator name + IElement createButton = cut.Find("#createOperatorButton"); + createButton.Click(); + + // Assert - Validation message should appear + cut.WaitForAssertion(() => { + cut.Markup.ShouldContain("Operator name is required"); + }, timeout: TimeSpan.FromSeconds(5)); + } + + [Fact] + public void OperatorsNew_DisplaysCheckboxOptions() + { + // Arrange & Act + IRenderedComponent cut = RenderComponent(); + + // Assert - Verify checkbox options are displayed + cut.Markup.ShouldContain("Require Custom Merchant Number"); + cut.Markup.ShouldContain("Require Custom Terminal Number"); + } + + [Fact] + public void OperatorsNew_SuccessfulCreation_ShowsSuccessMessage() + { + // Arrange + this.OperatorUIService.Setup(o => o.CreateOperator(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success()); + + IRenderedComponent cut = RenderComponent(); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Create New Operator"), timeout: TimeSpan.FromSeconds(5)); + + // Act - Fill in the form + IElement nameInput = cut.Find("input[placeholder='Enter operator name']"); + nameInput.Change("Test Operator"); + + // Submit the form + IElement createButton = cut.Find("#createOperatorButton"); + createButton.Click(); + + // Assert - Success message should appear before navigation + cut.WaitForAssertion(() => { + cut.Markup.ShouldContain("Operator created successfully"); + }, timeout: TimeSpan.FromSeconds(5)); + } +}