diff --git a/Directory.Packages.props b/Directory.Packages.props
index 4ccf6f3b..3260542b 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -24,7 +24,7 @@
-
+
@@ -43,4 +43,4 @@
-
\ No newline at end of file
+
diff --git a/EstateManagementUI.BlazorServer.Tests/Common/AuthenticationHelpersTests.cs b/EstateManagementUI.BlazorServer.Tests/Common/AuthenticationHelpersTests.cs
index f5945852..03ebe818 100644
--- a/EstateManagementUI.BlazorServer.Tests/Common/AuthenticationHelpersTests.cs
+++ b/EstateManagementUI.BlazorServer.Tests/Common/AuthenticationHelpersTests.cs
@@ -10,48 +10,48 @@ public void GetSecurityServiceAddresses_WithDefaultPorts_ReturnsCorrectAddresses
{
// Arrange
var authority = "https://localhost:5001";
-
+
// Act
var (authorityAddress, issuerAddress) = AuthenticationHelpers.GetSecurityServiceAddresses(
authority, null, null);
-
+
// Assert
authorityAddress.ShouldBe("https://localhost:5001");
issuerAddress.ShouldBe("https://localhost:5001");
}
-
+
[Fact]
public void GetSecurityServiceAddresses_WithCustomLocalPort_ReturnsCorrectAuthorityAddress()
{
// Arrange
var authority = "https://localhost:5001";
var securityServiceLocalPort = "6001";
-
+
// Act
var (authorityAddress, issuerAddress) = AuthenticationHelpers.GetSecurityServiceAddresses(
authority, securityServiceLocalPort, null);
-
+
// Assert
authorityAddress.ShouldBe("https://localhost:6001");
issuerAddress.ShouldBe("https://localhost:5001");
}
-
+
[Fact]
public void GetSecurityServiceAddresses_WithCustomPort_ReturnsCorrectIssuerAddress()
{
// Arrange
var authority = "https://localhost:5001";
var securityServicePort = "7001";
-
+
// Act
var (authorityAddress, issuerAddress) = AuthenticationHelpers.GetSecurityServiceAddresses(
authority, null, securityServicePort);
-
+
// Assert
authorityAddress.ShouldBe("https://localhost:5001");
issuerAddress.ShouldBe("https://localhost:7001");
}
-
+
[Fact]
public void GetSecurityServiceAddresses_WithBothCustomPorts_ReturnsCorrectAddresses()
{
@@ -59,57 +59,57 @@ public void GetSecurityServiceAddresses_WithBothCustomPorts_ReturnsCorrectAddres
var authority = "https://localhost:5001";
var securityServiceLocalPort = "6001";
var securityServicePort = "7001";
-
+
// Act
var (authorityAddress, issuerAddress) = AuthenticationHelpers.GetSecurityServiceAddresses(
authority, securityServiceLocalPort, securityServicePort);
-
+
// Assert
authorityAddress.ShouldBe("https://localhost:6001");
issuerAddress.ShouldBe("https://localhost:7001");
}
-
+
[Fact]
public void GetSecurityServiceAddresses_WithTrailingSlash_RemovesTrailingSlash()
{
// Arrange
var authority = "https://localhost:5001/";
-
+
// Act
var (authorityAddress, issuerAddress) = AuthenticationHelpers.GetSecurityServiceAddresses(
authority, null, null);
-
+
// Assert
authorityAddress.ShouldBe("https://localhost:5001");
issuerAddress.ShouldBe("https://localhost:5001");
}
-
+
[Fact]
public void GetSecurityServiceAddresses_WithPath_PreservesPath()
{
// Arrange
var authority = "https://localhost:5001/auth";
var securityServiceLocalPort = "6001";
-
+
// Act
var (authorityAddress, issuerAddress) = AuthenticationHelpers.GetSecurityServiceAddresses(
authority, securityServiceLocalPort, null);
-
+
// Assert
authorityAddress.ShouldBe("https://localhost:6001/auth");
issuerAddress.ShouldBe("https://localhost:5001/auth");
}
-
+
[Fact]
public void GetSecurityServiceAddresses_WithEmptyPortStrings_UsesDefaultPort()
{
// Arrange
var authority = "https://localhost:5001";
-
+
// Act
var (authorityAddress, issuerAddress) = AuthenticationHelpers.GetSecurityServiceAddresses(
authority, string.Empty, string.Empty);
-
+
// Assert
authorityAddress.ShouldBe("https://localhost:5001");
issuerAddress.ShouldBe("https://localhost:5001");
diff --git a/EstateManagementUI.BlazorServer.Tests/Common/TestAuthenticationHandlerTests.cs b/EstateManagementUI.BlazorServer.Tests/Common/TestAuthenticationHandlerTests.cs
index 761d6259..67068a9a 100644
--- a/EstateManagementUI.BlazorServer.Tests/Common/TestAuthenticationHandlerTests.cs
+++ b/EstateManagementUI.BlazorServer.Tests/Common/TestAuthenticationHandlerTests.cs
@@ -5,7 +5,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
-using Moq;
+using Imposter.Abstractions;
using Shouldly;
using System.Security.Claims;
using System.Text.Encodings.Web;
@@ -14,22 +14,22 @@ namespace EstateManagementUI.BlazorServer.Tests.Common;
public class TestAuthenticationHandlerTests
{
- private readonly Mock> _options;
- private readonly Mock _loggerFactory;
+ private readonly IOptionsMonitorImposter _options;
+ private readonly ILoggerFactoryImposter _loggerFactory;
private readonly IConfiguration _configuration;
- private readonly Mock _httpContextAccessor;
+ private readonly IHttpContextAccessorImposter _httpContextAccessor;
private readonly UrlEncoder _encoder;
public TestAuthenticationHandlerTests()
{
- _options = new Mock>();
- _loggerFactory = new Mock();
- _httpContextAccessor = new Mock();
+ _options = new IOptionsMonitorImposter();
+ _loggerFactory = new ILoggerFactoryImposter();
+ _httpContextAccessor = new IHttpContextAccessorImposter();
_encoder = UrlEncoder.Default;
-
- _options.Setup(x => x.Get(It.IsAny())).Returns(new AuthenticationSchemeOptions());
- _loggerFactory.Setup(x => x.CreateLogger(It.IsAny())).Returns(Mock.Of());
-
+
+ _options.Get(Arg.Any()).Returns(new AuthenticationSchemeOptions());
+ _loggerFactory.CreateLogger(Arg.Any()).Returns((new ILoggerImposter()).Instance());
+
// Create a real configuration
var configBuilder = new ConfigurationBuilder();
configBuilder.AddInMemoryCollection(new Dictionary
@@ -52,29 +52,29 @@ public async Task HandleAuthenticateAsync_WithDefaultConfig_UsesAdministratorRol
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.QueryString = new QueryString("");
-
+
// Configure session
- var sessionFeature = new Mock();
- var session = new Mock();
- sessionFeature.Setup(s => s.Session).Returns(session.Object);
- httpContext.Features.Set(sessionFeature.Object);
-
- _httpContextAccessor.Setup(x => x.HttpContext).Returns(httpContext);
-
+ var sessionFeature = new ISessionFeatureImposter();
+ var session = new ISessionImposter();
+ sessionFeature.Session.Getter().Returns(session.Instance());
+ httpContext.Features.Set(sessionFeature.Instance());
+
+ _httpContextAccessor.HttpContext.Getter().Returns(httpContext);
+
var handler = new TestAuthenticationHandler(
- _options.Object,
- _loggerFactory.Object,
- _encoder,
- _configuration,
- _httpContextAccessor.Object);
-
+ _options.Instance(),
+ _loggerFactory.Instance(),
+ _encoder,
+ _configuration,
+ _httpContextAccessor.Instance());
+
await handler.InitializeAsync(
- new AuthenticationScheme(TestAuthenticationHandler.SchemeName, null, typeof(TestAuthenticationHandler)),
+ new AuthenticationScheme(TestAuthenticationHandler.SchemeName, null, typeof(TestAuthenticationHandler)),
httpContext);
-
+
// Act
var result = await handler.AuthenticateAsync();
-
+
// Assert
result.Succeeded.ShouldBeTrue();
result.Principal.ShouldNotBeNull();
@@ -89,42 +89,42 @@ public async Task HandleAuthenticateAsync_CreatesAdministratorUserClaims()
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.QueryString = new QueryString("");
-
+
// Configure session
- var sessionFeature = new Mock();
- var session = new Mock();
- sessionFeature.Setup(s => s.Session).Returns(session.Object);
- httpContext.Features.Set(sessionFeature.Object);
-
- _httpContextAccessor.Setup(x => x.HttpContext).Returns(httpContext);
-
+ var sessionFeature = new ISessionFeatureImposter();
+ var session = new ISessionImposter();
+ sessionFeature.Session.Getter().Returns(session.Instance());
+ httpContext.Features.Set(sessionFeature.Instance());
+
+ _httpContextAccessor.HttpContext.Getter().Returns(httpContext);
+
var handler = new TestAuthenticationHandler(
- _options.Object,
- _loggerFactory.Object,
- _encoder,
- _configuration,
- _httpContextAccessor.Object);
-
+ _options.Instance(),
+ _loggerFactory.Instance(),
+ _encoder,
+ _configuration,
+ _httpContextAccessor.Instance());
+
await handler.InitializeAsync(
- new AuthenticationScheme(TestAuthenticationHandler.SchemeName, null, typeof(TestAuthenticationHandler)),
+ new AuthenticationScheme(TestAuthenticationHandler.SchemeName, null, typeof(TestAuthenticationHandler)),
httpContext);
-
+
// Act
var result = await handler.AuthenticateAsync();
-
+
// Assert
result.Succeeded.ShouldBeTrue();
result.Principal.ShouldNotBeNull();
-
+
var roleClaim = result.Principal.FindFirst(ClaimTypes.Role);
roleClaim?.Value.ShouldBe("Administrator");
-
+
var nameClaim = result.Principal.FindFirst(ClaimTypes.Name);
nameClaim?.Value.ShouldBe("Admin User");
-
+
var emailClaim = result.Principal.FindFirst(ClaimTypes.Email);
emailClaim?.Value.ShouldBe("administrator@test.com");
-
+
var estateIdClaim = result.Principal.FindFirst("estateId");
estateIdClaim?.Value.ShouldBe("11111111-1111-1111-1111-111111111111");
}
@@ -135,33 +135,33 @@ public async Task HandleAuthenticateAsync_CreatesAllRequiredClaims()
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.QueryString = new QueryString("");
-
+
// Configure session
- var sessionFeature = new Mock();
- var session = new Mock();
- sessionFeature.Setup(s => s.Session).Returns(session.Object);
- httpContext.Features.Set(sessionFeature.Object);
-
- _httpContextAccessor.Setup(x => x.HttpContext).Returns(httpContext);
-
+ var sessionFeature = new ISessionFeatureImposter();
+ var session = new ISessionImposter();
+ sessionFeature.Session.Getter().Returns(session.Instance());
+ httpContext.Features.Set(sessionFeature.Instance());
+
+ _httpContextAccessor.HttpContext.Getter().Returns(httpContext);
+
var handler = new TestAuthenticationHandler(
- _options.Object,
- _loggerFactory.Object,
- _encoder,
- _configuration,
- _httpContextAccessor.Object);
-
+ _options.Instance(),
+ _loggerFactory.Instance(),
+ _encoder,
+ _configuration,
+ _httpContextAccessor.Instance());
+
await handler.InitializeAsync(
- new AuthenticationScheme(TestAuthenticationHandler.SchemeName, null, typeof(TestAuthenticationHandler)),
+ new AuthenticationScheme(TestAuthenticationHandler.SchemeName, null, typeof(TestAuthenticationHandler)),
httpContext);
-
+
// Act
var result = await handler.AuthenticateAsync();
-
+
// Assert
result.Succeeded.ShouldBeTrue();
result.Principal.ShouldNotBeNull();
-
+
result.Principal.FindFirst(ClaimTypes.NameIdentifier).ShouldNotBeNull();
result.Principal.FindFirst(ClaimTypes.Name).ShouldNotBeNull();
result.Principal.FindFirst(ClaimTypes.Email).ShouldNotBeNull();
@@ -176,29 +176,29 @@ public async Task HandleAuthenticateAsync_AlwaysSucceeds()
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.QueryString = new QueryString("");
-
+
// Configure session
- var sessionFeature = new Mock();
- var session = new Mock();
- sessionFeature.Setup(s => s.Session).Returns(session.Object);
- httpContext.Features.Set(sessionFeature.Object);
-
- _httpContextAccessor.Setup(x => x.HttpContext).Returns(httpContext);
-
+ var sessionFeature = new ISessionFeatureImposter();
+ var session = new ISessionImposter();
+ sessionFeature.Session.Getter().Returns(session.Instance());
+ httpContext.Features.Set(sessionFeature.Instance());
+
+ _httpContextAccessor.HttpContext.Getter().Returns(httpContext);
+
var handler = new TestAuthenticationHandler(
- _options.Object,
- _loggerFactory.Object,
- _encoder,
- _configuration,
- _httpContextAccessor.Object);
-
+ _options.Instance(),
+ _loggerFactory.Instance(),
+ _encoder,
+ _configuration,
+ _httpContextAccessor.Instance());
+
await handler.InitializeAsync(
- new AuthenticationScheme(TestAuthenticationHandler.SchemeName, null, typeof(TestAuthenticationHandler)),
+ new AuthenticationScheme(TestAuthenticationHandler.SchemeName, null, typeof(TestAuthenticationHandler)),
httpContext);
-
+
// Act
var result = await handler.AuthenticateAsync();
-
+
// Assert
result.Succeeded.ShouldBeTrue();
result.Failure.ShouldBeNull();
@@ -210,29 +210,29 @@ public async Task HandleAuthenticateAsync_CreatesAuthenticationTicket()
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.QueryString = new QueryString("");
-
+
// Configure session
- var sessionFeature = new Mock();
- var session = new Mock();
- sessionFeature.Setup(s => s.Session).Returns(session.Object);
- httpContext.Features.Set(sessionFeature.Object);
-
- _httpContextAccessor.Setup(x => x.HttpContext).Returns(httpContext);
-
+ var sessionFeature = new ISessionFeatureImposter();
+ var session = new ISessionImposter();
+ sessionFeature.Session.Getter().Returns(session.Instance());
+ httpContext.Features.Set(sessionFeature.Instance());
+
+ _httpContextAccessor.HttpContext.Getter().Returns(httpContext);
+
var handler = new TestAuthenticationHandler(
- _options.Object,
- _loggerFactory.Object,
- _encoder,
- _configuration,
- _httpContextAccessor.Object);
-
+ _options.Instance(),
+ _loggerFactory.Instance(),
+ _encoder,
+ _configuration,
+ _httpContextAccessor.Instance());
+
await handler.InitializeAsync(
- new AuthenticationScheme(TestAuthenticationHandler.SchemeName, null, typeof(TestAuthenticationHandler)),
+ new AuthenticationScheme(TestAuthenticationHandler.SchemeName, null, typeof(TestAuthenticationHandler)),
httpContext);
-
+
// Act
var result = await handler.AuthenticateAsync();
-
+
// Assert
result.Succeeded.ShouldBeTrue();
result.Ticket.ShouldNotBeNull();
diff --git a/EstateManagementUI.BlazorServer.Tests/EstateManagementUI.BlazorServer.Tests.csproj b/EstateManagementUI.BlazorServer.Tests/EstateManagementUI.BlazorServer.Tests.csproj
index f6b8834d..b6cda5d7 100644
--- a/EstateManagementUI.BlazorServer.Tests/EstateManagementUI.BlazorServer.Tests.csproj
+++ b/EstateManagementUI.BlazorServer.Tests/EstateManagementUI.BlazorServer.Tests.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/EstateManagementUI.BlazorServer.Tests/GlobalUsings.cs b/EstateManagementUI.BlazorServer.Tests/GlobalUsings.cs
new file mode 100644
index 00000000..526fc02d
--- /dev/null
+++ b/EstateManagementUI.BlazorServer.Tests/GlobalUsings.cs
@@ -0,0 +1,4 @@
+global using Microsoft.AspNetCore.Authentication;
+global using Microsoft.AspNetCore.Hosting;
+global using Microsoft.AspNetCore.Http.Features;
+global using EstateManagementUI.BlazorServer.Permissions;
diff --git a/EstateManagementUI.BlazorServer.Tests/Imposters.cs b/EstateManagementUI.BlazorServer.Tests/Imposters.cs
new file mode 100644
index 00000000..f63032f1
--- /dev/null
+++ b/EstateManagementUI.BlazorServer.Tests/Imposters.cs
@@ -0,0 +1,39 @@
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Authorization;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Microsoft.JSInterop;
+using MediatR;
+using Imposter.Abstractions;
+using EstateManagementUI.BusinessLogic.Client;
+using EstateManagementUI.BusinessLogic.Services;
+using EstateManagementUI.BlazorServer.UIServices;
+using EstateManagementUI.BlazorServer.Permissions;
+
+
+[assembly: GenerateImposter(typeof(AuthenticationStateProvider))]
+[assembly: GenerateImposter(typeof(IApiClient))]
+[assembly: GenerateImposter(typeof(ICalendarUIService))]
+[assembly: GenerateImposter(typeof(IContractUIService))]
+[assembly: GenerateImposter(typeof(IEstateUIService))]
+[assembly: GenerateImposter(typeof(IFileProcessingUIService))]
+[assembly: GenerateImposter(typeof(IHttpContextAccessor))]
+[assembly: GenerateImposter(typeof(IJSRuntime))]
+[assembly: GenerateImposter(typeof(ILogger<>))]
+[assembly: GenerateImposter(typeof(ILoggerFactory))]
+[assembly: GenerateImposter(typeof(IMediator))]
+[assembly: GenerateImposter(typeof(IMerchantUIService))]
+[assembly: GenerateImposter(typeof(IOperatorUIService))]
+[assembly: GenerateImposter(typeof(IOptionsMonitor))]
+[assembly: GenerateImposter(typeof(IPermissionKeyProvider))]
+[assembly: GenerateImposter(typeof(IPermissionService))]
+[assembly: GenerateImposter(typeof(IPermissionStore))]
+[assembly: GenerateImposter(typeof(ISession))]
+[assembly: GenerateImposter(typeof(ISessionFeature))]
+[assembly: GenerateImposter(typeof(ITransactionUIService))]
+[assembly: GenerateImposter(typeof(IWebHostEnvironment))]
+[assembly: GenerateImposter(typeof(NavigationManager))]
diff --git a/EstateManagementUI.BlazorServer.Tests/Pages/BaseTest.cs b/EstateManagementUI.BlazorServer.Tests/Pages/BaseTest.cs
index 9aa23799..917ead3a 100644
--- a/EstateManagementUI.BlazorServer.Tests/Pages/BaseTest.cs
+++ b/EstateManagementUI.BlazorServer.Tests/Pages/BaseTest.cs
@@ -10,7 +10,7 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection;
-using Moq;
+using Imposter.Abstractions;
using SimpleResults;
using TestContext = Bunit.TestContext;
@@ -18,25 +18,25 @@ namespace EstateManagementUI.BlazorServer.Tests.Pages;
public abstract class BaseTest :TestContext {
protected BaseTest() {
- this._mockMediator = new Mock();
- this._mockNavigationManager = new Mock();
- this._mockPermissionKeyProvider = new Mock();
- this._mockAuthStateProvider = new Mock();
- this._mockPermissionService = new Mock();
- this._mockPermissionStore = new Mock();
+ this._mockMediator = new IMediatorImposter();
+ this._mockNavigationManager = new NavigationManagerImposter();
+ this._mockPermissionKeyProvider = new IPermissionKeyProviderImposter();
+ this._mockAuthStateProvider = new AuthenticationStateProviderImposter();
+ this._mockPermissionService = new IPermissionServiceImposter();
+ this._mockPermissionStore = new IPermissionStoreImposter();
this._fakeNavigationManager = new FakeNavigationManager();
-
- this._mockPermissionKeyProvider.Setup(x => x.GetKey()).Returns("test-key");
- this._mockPermissionService.Setup(x => x.HasPermissionAsync(It.IsAny(), It.IsAny())).ReturnsAsync(true);
- this.MerchantUIService.Setup(x => x.GetMerchants(It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny()))
+
+ this._mockPermissionKeyProvider.GetKey().Returns("test-key");
+ this._mockPermissionService.HasPermissionAsync(Arg.Any(), Arg.Any()).ReturnsAsync(true);
+ this.MerchantUIService.GetMerchants(Arg.Any(),
+ Arg.Any(),
+ Arg.Any(),
+ Arg.Any(),
+ Arg.Any(),
+ Arg.Any(),
+ Arg.Any())
.ReturnsAsync(Result.Success(new List()));
- this.MerchantUIService.Setup(x => x.GetMerchantsForDropDown(It.IsAny(), It.IsAny()))
+ this.MerchantUIService.GetMerchantsForDropDown(Arg.Any(), Arg.Any())
.ReturnsAsync(Result.Success(new List
{
new()
@@ -46,7 +46,7 @@ protected BaseTest() {
MerchantName = "Test Merchant"
}
}));
- this.FileProcessingUIService.Setup(x => x.GetFileProfiles(It.IsAny()))
+ this.FileProcessingUIService.GetFileProfiles(Arg.Any())
.ReturnsAsync(Result.Success(new List
{
new()
@@ -66,18 +66,18 @@ protected BaseTest() {
}
}));
- this.Services.AddSingleton(this._mockMediator.Object);
- //this.Services.AddSingleton(this._mockNavigationManager.Object);
+ this.Services.AddSingleton(this._mockMediator.Instance());
+ //this.Services.AddSingleton(this._mockNavigationManager.Instance());
Services.AddSingleton(_fakeNavigationManager); // register FakeNavigationManager
- this.Services.AddSingleton(this._mockPermissionKeyProvider.Object);
- this.Services.AddSingleton(this._mockPermissionService.Object);
- this.Services.AddSingleton(this._mockAuthStateProvider.Object);
- this.Services.AddSingleton(this._mockPermissionStore.Object);
- this.Services.AddSingleton(this.EstateUIService.Object);
- this.Services.AddSingleton(this.OperatorUIService.Object);
- this.Services.AddSingleton(this.ContractUIService.Object);
- this.Services.AddSingleton(this.MerchantUIService.Object);
- this.Services.AddSingleton(this.FileProcessingUIService.Object);
+ this.Services.AddSingleton(this._mockPermissionKeyProvider.Instance());
+ this.Services.AddSingleton(this._mockPermissionService.Instance());
+ this.Services.AddSingleton(this._mockAuthStateProvider.Instance());
+ this.Services.AddSingleton(this._mockPermissionStore.Instance());
+ this.Services.AddSingleton(this.EstateUIService.Instance());
+ this.Services.AddSingleton(this.OperatorUIService.Instance());
+ this.Services.AddSingleton(this.ContractUIService.Instance());
+ this.Services.AddSingleton(this.MerchantUIService.Instance());
+ this.Services.AddSingleton(this.FileProcessingUIService.Instance());
// Add required permission components that render their children
@@ -90,18 +90,18 @@ protected BaseTest() {
this.AddTestAuthorization().SetClaims(claims);
}
- protected readonly Mock _mockMediator;
- protected readonly Mock _mockNavigationManager;
- protected readonly Mock _mockPermissionKeyProvider;
- protected readonly Mock _mockPermissionService;
- protected readonly Mock _mockAuthStateProvider;
- protected readonly Mock _mockPermissionStore;
+ protected readonly IMediatorImposter _mockMediator;
+ protected readonly NavigationManagerImposter _mockNavigationManager;
+ protected readonly IPermissionKeyProviderImposter _mockPermissionKeyProvider;
+ protected readonly IPermissionServiceImposter _mockPermissionService;
+ protected readonly AuthenticationStateProviderImposter _mockAuthStateProvider;
+ protected readonly IPermissionStoreImposter _mockPermissionStore;
protected readonly FakeNavigationManager _fakeNavigationManager;
- protected readonly Mock EstateUIService = new Mock();
- protected readonly Mock OperatorUIService = new Mock();
- protected readonly Mock ContractUIService = new Mock();
- protected readonly Mock MerchantUIService = new Mock();
- protected readonly Mock FileProcessingUIService = new Mock();
+ protected readonly IEstateUIServiceImposter EstateUIService = new IEstateUIServiceImposter();
+ protected readonly IOperatorUIServiceImposter OperatorUIService = new IOperatorUIServiceImposter();
+ protected readonly IContractUIServiceImposter ContractUIService = new IContractUIServiceImposter();
+ protected readonly IMerchantUIServiceImposter MerchantUIService = new IMerchantUIServiceImposter();
+ protected readonly IFileProcessingUIServiceImposter FileProcessingUIService = new IFileProcessingUIServiceImposter();
///
/// Minimal test double for NavigationManager.
/// Register in DI as NavigationManager so components receive it in tests.
diff --git a/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsEditPageTests.cs b/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsEditPageTests.cs
index 6cb9f658..ba7c3485 100644
--- a/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsEditPageTests.cs
+++ b/EstateManagementUI.BlazorServer.Tests/Pages/Contracts/ContractsEditPageTests.cs
@@ -8,7 +8,7 @@
using MediatR;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
-using Moq;
+using Imposter.Abstractions;
using Shouldly;
using SimpleResults;
using TransactionProcessor.DataTransferObjects.Responses.Contract;
@@ -29,14 +29,14 @@ public void ContractsEdit_RendersCorrectly()
OperatorName = "Test Operator",
Products = new List()
};
-
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.ReturnsAsync(Result.Success(contract));
-
+
// Act
var cut = RenderComponent(parameters => parameters
.Add(p => p.ContractId, contractId));
-
+
// Assert
cut.Markup.ShouldContain("Edit Contract");
}
@@ -54,14 +54,14 @@ public void ContractsEdit_DisplaysContractDetails()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 Contract");
cut.Markup.ShouldContain("Test Operator");
@@ -80,18 +80,18 @@ public void ContractsEdit_HasCorrectPageTitle()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.ReturnsAsync(Result.Success(contract));
// Act
var cut = RenderComponent(parameters => parameters
.Add(p => p.ContractId, contractId));
-
+
// Assert
var pageTitle = cut.FindComponent();
pageTitle.Instance.ChildContent.ShouldNotBeNull();
}
-
+
[Fact]
public void ContractsEdit_UpdateContractButton_CanBeFound()
{
@@ -105,18 +105,18 @@ public void ContractsEdit_UpdateContractButton_CanBeFound()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 Update Contract button
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? updateButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Update Contract"));
-
+
// Assert
updateButton.ShouldNotBeNull();
}
@@ -134,18 +134,18 @@ public void ContractsEdit_AddProductButton_CanBeFound()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 Add Product button
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? addProductButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Add Product"));
-
+
// Assert
addProductButton.ShouldNotBeNull();
}
@@ -163,20 +163,20 @@ public void ContractsEdit_AddProductButton_OpensModal()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 Add Product button
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? addProductButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Add Product"));
addProductButton.ShouldNotBeNull();
addProductButton.Click();
-
+
// Assert - Modal should be visible
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Add New Product"), timeout: TimeSpan.FromSeconds(5));
}
@@ -206,14 +206,14 @@ public void ContractsEdit_WithProducts_DisplaysProductList()
}
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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("Product 1");
cut.Markup.ShouldContain("Display 1");
@@ -245,19 +245,19 @@ public void ContractsEdit_WithProducts_HasRemoveProductButton()
}
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 remove button (it has a trash icon svg)
IRefreshableElementCollection buttons = cut.FindAll("button");
- var removeButton = buttons.FirstOrDefault(b =>
+ var removeButton = buttons.FirstOrDefault(b =>
b.GetAttribute("title") == "Remove Product");
-
+
// Assert
removeButton.ShouldNotBeNull();
}
@@ -298,18 +298,18 @@ public void ContractsEdit_WithProductHavingFees_HasAddFeeButton()
}
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 Add Fee button
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? addFeeButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Add Fee"));
-
+
// Assert
addFeeButton.ShouldNotBeNull();
cut.Markup.ShouldContain("Fee 1");
@@ -341,20 +341,20 @@ public void ContractsEdit_AddFeeButton_OpensModal()
}
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 Add Fee button
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? addFeeButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Add Fee"));
addFeeButton.ShouldNotBeNull();
addFeeButton.Click();
-
+
// Assert - Modal should be visible
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Add Transaction Fee"), timeout: TimeSpan.FromSeconds(5));
}
@@ -372,18 +372,18 @@ public void ContractsEdit_WithNoProducts_ShowsEmptyState()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 yet");
}
-
+
[Fact]
public void ContractsEdit_BackToListButton_NavigatesToContractsIndex() {
// Arrange
@@ -396,20 +396,20 @@ public void ContractsEdit_BackToListButton_NavigatesToContractsIndex() {
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 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");
}
@@ -427,27 +427,27 @@ public void ContractsEdit_ProductModal_HasCancelButton()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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));
-
+
// Open the modal
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? addProductButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Add Product"));
addProductButton?.Click();
-
+
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Add New Product"), timeout: TimeSpan.FromSeconds(5));
-
+
// Find cancel button in modal (type="button" excludes submit buttons)
IRefreshableElementCollection modalButtons = cut.FindAll("button");
- IElement? cancelButton = modalButtons.FirstOrDefault(b =>
- b.TextContent.Contains("Cancel") &&
+ IElement? cancelButton = modalButtons.FirstOrDefault(b =>
+ b.TextContent.Contains("Cancel") &&
b.GetAttribute("type") == "button");
-
+
// Assert
cancelButton.ShouldNotBeNull();
}
@@ -478,27 +478,27 @@ public void ContractsEdit_FeeModal_HasCancelButton()
}
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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));
-
+
// Open the modal
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? addFeeButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Add Fee"));
addFeeButton?.Click();
-
+
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Add Transaction Fee"), timeout: TimeSpan.FromSeconds(5));
-
+
// Find cancel button in modal (type="button" excludes submit buttons)
IRefreshableElementCollection modalButtons = cut.FindAll("button");
- IElement? cancelButton = modalButtons.FirstOrDefault(b =>
- b.TextContent.Contains("Cancel") &&
+ IElement? cancelButton = modalButtons.FirstOrDefault(b =>
+ b.TextContent.Contains("Cancel") &&
b.GetAttribute("type") == "button");
-
+
// Assert
cancelButton.ShouldNotBeNull();
}
@@ -540,19 +540,19 @@ public void ContractsEdit_WithTransactionFees_HasRemoveFeeButton()
}
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 remove fee button (it has a trash icon svg and title)
IRefreshableElementCollection buttons = cut.FindAll("button");
- var removeFeeButton = buttons.FirstOrDefault(b =>
+ var removeFeeButton = buttons.FirstOrDefault(b =>
b.GetAttribute("title") == "Remove Fee");
-
+
// Assert
removeFeeButton.ShouldNotBeNull();
}
@@ -570,14 +570,14 @@ public void ContractsEdit_DisplaysOperatorNameAsReadOnly()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 Operator");
cut.Markup.ShouldContain("Operator cannot be changed after contract creation");
@@ -596,14 +596,14 @@ public void ContractsEdit_UpdateContractButton_Exists()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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 - Find Update Contract button
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? updateButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Update Contract"));
@@ -623,31 +623,31 @@ public void ContractsEdit_AddProductModal_HasRequiredFields()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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));
-
+
// Open modal
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? addProductButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Add Product") && b.GetAttribute("type") != "submit");
addProductButton.ShouldNotBeNull();
addProductButton.Click();
-
+
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Add New Product"), timeout: TimeSpan.FromSeconds(5));
-
+
// Assert - Check form has required fields
cut.Markup.ShouldContain("Product Name");
cut.Markup.ShouldContain("Display Text");
cut.Markup.ShouldContain("Variable Value");
cut.Markup.ShouldContain("Value");
-
+
// Check submit button exists
IRefreshableElementCollection modalButtons = cut.FindAll("button");
- IElement? submitButton = modalButtons.FirstOrDefault(b =>
+ IElement? submitButton = modalButtons.FirstOrDefault(b =>
b.TextContent.Contains("Add Product") && b.GetAttribute("type") == "submit");
submitButton.ShouldNotBeNull();
}
@@ -665,25 +665,25 @@ public void ContractsEdit_AddProductModal_HasSubmitButton()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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));
-
+
// Open modal
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? addProductButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Add Product") && b.GetAttribute("type") != "submit");
addProductButton.ShouldNotBeNull();
addProductButton.Click();
-
+
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Add New Product"), timeout: TimeSpan.FromSeconds(5));
-
+
// Assert - Check submit button exists
IRefreshableElementCollection modalButtons = cut.FindAll("button");
- IElement? submitButton = modalButtons.FirstOrDefault(b =>
+ IElement? submitButton = modalButtons.FirstOrDefault(b =>
b.TextContent.Contains("Add Product") && b.GetAttribute("type") == "submit");
submitButton.ShouldNotBeNull();
}
@@ -701,22 +701,22 @@ public void ContractsEdit_AddProductModal_HasVariableValueCheckbox()
Products = new List()
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg.Any(), Arg.Any())
.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));
-
+
// Open modal
IRefreshableElementCollection buttons = cut.FindAll("button");
IElement? addProductButton = buttons.FirstOrDefault(b => b.TextContent.Contains("Add Product") && b.GetAttribute("type") != "submit");
addProductButton.ShouldNotBeNull();
addProductButton.Click();
-
+
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Add New Product"), timeout: TimeSpan.FromSeconds(5));
-
+
// Assert - Check variable value checkbox exists
cut.Markup.ShouldContain("Variable Value");
var checkbox = cut.Find("input[type='checkbox']");
@@ -749,31 +749,31 @@ public void ContractsEdit_AddFeeModal_HasRequiredFields()
}
};
- this.ContractUIService.Setup(c => c.GetContract(It.IsAny(), It.IsAny(), It.IsAny()))
+ this.ContractUIService.GetContract(Arg.Any(), Arg