From 194d370082d8b02da45bd3b1f7fa03141629f402 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 12:03:09 +0000 Subject: [PATCH 1/4] Initial plan From d8d67f75b2722c8eb3d8d6813c4f82e5f5d063c9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 12:08:30 +0000 Subject: [PATCH 2/4] Add button finding and navigation tests to Contracts Index Page Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com> --- .../Contracts/ContractsIndexPageTests.cs | 94 +++++++++++++++++-- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsIndexPageTests.cs b/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsIndexPageTests.cs index eb65e945..35b74300 100644 --- a/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsIndexPageTests.cs +++ b/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsIndexPageTests.cs @@ -1,3 +1,4 @@ +using AngleSharp.Dom; using Bunit; using EstateManagementUI.BlazorServer.Components.Permissions; using EstateManagementUI.BlazorServer.Permissions; @@ -52,10 +53,9 @@ public void ContractsIndex_WithNoContracts_ShowsEmptyState() // Act var cut = RenderComponent(); - cut.WaitForState(() => !cut.Markup.Contains("animate-spin")); // Assert - cut.Markup.ShouldContain("No contracts found"); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("No contracts found"), timeout: TimeSpan.FromSeconds(5)); } [Fact] @@ -87,10 +87,9 @@ public void ContractsIndex_WithContracts_DisplaysContractList() // Act var cut = RenderComponent(); - cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); // Assert - cut.Markup.ShouldContain("Contract 1"); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Contract 1"), timeout: TimeSpan.FromSeconds(5)); cut.Markup.ShouldContain("Contract 2"); cut.Markup.ShouldContain("Operator A"); cut.Markup.ShouldContain("Operator B"); @@ -121,10 +120,9 @@ public void ContractsIndex_DisplaysProductCount() // Act var cut = RenderComponent(); - cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5)); // Assert - cut.Markup.ShouldContain("Product(s)"); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Product(s)"), timeout: TimeSpan.FromSeconds(5)); } [Fact] @@ -141,4 +139,88 @@ public void ContractsIndex_HasCorrectPageTitle() var pageTitle = cut.FindComponent(); pageTitle.Instance.ChildContent.ShouldNotBeNull(); } + + [Fact] + public void ContractsIndex_AddNewContractButton_NavigatesToNewContractPage() + { + // Arrange + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(new List())); + + var cut = RenderComponent(); + cut.WaitForAssertion(() => !cut.Markup.Contains("animate-spin"), timeout: TimeSpan.FromSeconds(5)); + + // Act - Find and click the "Add New Contract" button + var addButton = cut.Find("#newContractButton"); + addButton.Click(); + + // Assert + _fakeNavigationManager.Uri.ShouldContain("/contracts/new"); + } + + [Fact] + public void ContractsIndex_ViewButton_NavigatesToContractDetails() + { + // Arrange + var contractId = Guid.NewGuid(); + var contracts = new List + { + new ContractModel + { + ContractId = contractId, + Description = "Test Contract", + OperatorName = "Test Operator", + OperatorId = Guid.NewGuid(), + Products = new List() + } + }; + + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(contracts)); + + var cut = RenderComponent(); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Test Contract"), timeout: TimeSpan.FromSeconds(5)); + + // Act - Find and click the "View" button + var buttons = cut.FindAll("button"); + var viewButton = buttons.FirstOrDefault(b => b.TextContent.Contains("View")); + viewButton.ShouldNotBeNull(); + viewButton.Click(); + + // Assert + _fakeNavigationManager.Uri.ShouldContain($"/contracts/{contractId}"); + } + + [Fact] + public void ContractsIndex_EditButton_NavigatesToEditContractPage() + { + // Arrange + var contractId = Guid.NewGuid(); + var contracts = new List + { + new ContractModel + { + ContractId = contractId, + Description = "Test Contract", + OperatorName = "Test Operator", + OperatorId = Guid.NewGuid(), + Products = new List() + } + }; + + _mockMediator.Setup(x => x.Send(It.IsAny(), default)) + .ReturnsAsync(Result.Success(contracts)); + + var cut = RenderComponent(); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Test Contract"), timeout: TimeSpan.FromSeconds(5)); + + // Act - Find and click the "Edit" button + var buttons = cut.FindAll("button"); + var editButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Edit")); + editButton.ShouldNotBeNull(); + editButton.Click(); + + // Assert + _fakeNavigationManager.Uri.ShouldContain($"/contracts/{contractId}/edit"); + } } From 1ee4aafd073d2f733dd6c44bb46f99c96726f31f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 12:10:23 +0000 Subject: [PATCH 3/4] Improve code consistency with explicit types and positive assertions Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com> --- .../Contracts/ContractsIndexPageTests.cs | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsIndexPageTests.cs b/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsIndexPageTests.cs index 35b74300..4714fc33 100644 --- a/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsIndexPageTests.cs +++ b/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsIndexPageTests.cs @@ -21,7 +21,7 @@ public class ContractsIndexPageTests : BaseTest public void ContractsIndex_RendersCorrectly() { // Arrange - var contracts = new List + List contracts = new List { new ContractModel { @@ -37,7 +37,7 @@ public void ContractsIndex_RendersCorrectly() .ReturnsAsync(Result.Success(contracts)); // Act - var cut = RenderComponent(); + IRenderedComponent cut = RenderComponent(); // Assert cut.Markup.ShouldContain("Contract Management"); @@ -47,12 +47,12 @@ public void ContractsIndex_RendersCorrectly() public void ContractsIndex_WithNoContracts_ShowsEmptyState() { // Arrange - var emptyList = new List(); + List emptyList = new List(); _mockMediator.Setup(x => x.Send(It.IsAny(), default)) .ReturnsAsync(Result.Success(emptyList)); // Act - var cut = RenderComponent(); + IRenderedComponent cut = RenderComponent(); // Assert cut.WaitForAssertion(() => cut.Markup.ShouldContain("No contracts found"), timeout: TimeSpan.FromSeconds(5)); @@ -62,7 +62,7 @@ public void ContractsIndex_WithNoContracts_ShowsEmptyState() public void ContractsIndex_WithContracts_DisplaysContractList() { // Arrange - var contracts = new List + List contracts = new List { new ContractModel { @@ -86,7 +86,7 @@ public void ContractsIndex_WithContracts_DisplaysContractList() .ReturnsAsync(Result.Success(contracts)); // Act - var cut = RenderComponent(); + IRenderedComponent cut = RenderComponent(); // Assert cut.WaitForAssertion(() => cut.Markup.ShouldContain("Contract 1"), timeout: TimeSpan.FromSeconds(5)); @@ -99,7 +99,7 @@ public void ContractsIndex_WithContracts_DisplaysContractList() public void ContractsIndex_DisplaysProductCount() { // Arrange - var contracts = new List + List contracts = new List { new ContractModel { @@ -119,7 +119,7 @@ public void ContractsIndex_DisplaysProductCount() .ReturnsAsync(Result.Success(contracts)); // Act - var cut = RenderComponent(); + IRenderedComponent cut = RenderComponent(); // Assert cut.WaitForAssertion(() => cut.Markup.ShouldContain("Product(s)"), timeout: TimeSpan.FromSeconds(5)); @@ -133,10 +133,10 @@ public void ContractsIndex_HasCorrectPageTitle() .ReturnsAsync(Result.Success(new List())); // Act - var cut = RenderComponent(); + IRenderedComponent cut = RenderComponent(); // Assert - var pageTitle = cut.FindComponent(); + IRenderedComponent pageTitle = cut.FindComponent(); pageTitle.Instance.ChildContent.ShouldNotBeNull(); } @@ -147,11 +147,11 @@ public void ContractsIndex_AddNewContractButton_NavigatesToNewContractPage() _mockMediator.Setup(x => x.Send(It.IsAny(), default)) .ReturnsAsync(Result.Success(new List())); - var cut = RenderComponent(); - cut.WaitForAssertion(() => !cut.Markup.Contains("animate-spin"), timeout: TimeSpan.FromSeconds(5)); + IRenderedComponent cut = RenderComponent(); + cut.WaitForAssertion(() => cut.Markup.ShouldContain("Contract Management"), timeout: TimeSpan.FromSeconds(5)); // Act - Find and click the "Add New Contract" button - var addButton = cut.Find("#newContractButton"); + IElement addButton = cut.Find("#newContractButton"); addButton.Click(); // Assert @@ -162,8 +162,8 @@ public void ContractsIndex_AddNewContractButton_NavigatesToNewContractPage() public void ContractsIndex_ViewButton_NavigatesToContractDetails() { // Arrange - var contractId = Guid.NewGuid(); - var contracts = new List + Guid contractId = Guid.NewGuid(); + List contracts = new List { new ContractModel { @@ -178,12 +178,12 @@ public void ContractsIndex_ViewButton_NavigatesToContractDetails() _mockMediator.Setup(x => x.Send(It.IsAny(), default)) .ReturnsAsync(Result.Success(contracts)); - var cut = RenderComponent(); + IRenderedComponent cut = RenderComponent(); cut.WaitForAssertion(() => cut.Markup.ShouldContain("Test Contract"), timeout: TimeSpan.FromSeconds(5)); // Act - Find and click the "View" button - var buttons = cut.FindAll("button"); - var viewButton = buttons.FirstOrDefault(b => b.TextContent.Contains("View")); + IRefreshableElementCollection buttons = cut.FindAll("button"); + IElement? viewButton = buttons.FirstOrDefault(b => b.TextContent.Contains("View")); viewButton.ShouldNotBeNull(); viewButton.Click(); @@ -195,8 +195,8 @@ public void ContractsIndex_ViewButton_NavigatesToContractDetails() public void ContractsIndex_EditButton_NavigatesToEditContractPage() { // Arrange - var contractId = Guid.NewGuid(); - var contracts = new List + Guid contractId = Guid.NewGuid(); + List contracts = new List { new ContractModel { @@ -211,12 +211,12 @@ public void ContractsIndex_EditButton_NavigatesToEditContractPage() _mockMediator.Setup(x => x.Send(It.IsAny(), default)) .ReturnsAsync(Result.Success(contracts)); - var cut = RenderComponent(); + IRenderedComponent cut = RenderComponent(); cut.WaitForAssertion(() => cut.Markup.ShouldContain("Test Contract"), timeout: TimeSpan.FromSeconds(5)); // Act - Find and click the "Edit" button - var buttons = cut.FindAll("button"); - var editButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Edit")); + IRefreshableElementCollection buttons = cut.FindAll("button"); + IElement? editButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Edit")); editButton.ShouldNotBeNull(); editButton.Click(); From 59fecdaacc78d8c290353125a7fadf214b31ba7c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:05:47 +0000 Subject: [PATCH 4/4] Fix RequirePermission stub to render child content Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com> --- EstateManagementUI.BlazorServer.Tests/Pages/BaseTest.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/EstateManagementUI.BlazorServer.Tests/Pages/BaseTest.cs b/EstateManagementUI.BlazorServer.Tests/Pages/BaseTest.cs index 930d4ddd..7f8b9676 100644 --- a/EstateManagementUI.BlazorServer.Tests/Pages/BaseTest.cs +++ b/EstateManagementUI.BlazorServer.Tests/Pages/BaseTest.cs @@ -33,9 +33,11 @@ protected BaseTest() { this.Services.AddSingleton(this._mockPermissionStore.Object); - // Add required permission components - this.ComponentFactories.AddStub(); - this.ComponentFactories.AddStub(); + // Add required permission components that render their children + this.ComponentFactories.AddStub( + parameters => parameters.Get(p => p.ChildContent)); + this.ComponentFactories.AddStub( + parameters => parameters.Get(p => p.ChildContent)); var claims = new[] { new Claim(ClaimTypes.Role, "Estate"), new Claim("estateId", Guid.NewGuid().ToString()), new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "EstateUser") }; this.AddTestAuthorization().SetClaims(claims);