Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copilot Instructions

## General Guidelines
- First general instruction
- Second general instruction

## Unit Testing
- Add new unit tests to existing `MerchantUIServiceTests.cs` for:
- `GetRecentMerchants` (success and failure cases)
- `GetMerchantKpis` (success and failure cases)
- `GetMerchantsForDropDown` (success and failure cases)
- Preferred file location: `EstateManagementUI.BlazorServer.Tests\UIServices\MerchantUIServiceTests.cs`
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ public void EstateIndex_RendersCorrectly()
BlazorServer.Models.EstateModel estate = new(Guid.NewGuid(), "Test Estate", "EST001");
estate = estate with {
ContractCount = 0,
RecentContracts = new List<Models.RecentContractModel>(),
RecentContracts = new List<ContractModels.RecentContractModel>(),
OperatorCount = 0,
AllOperators = new List<Models.OperatorModels.OperatorDropDownModel>(),
AssignedOperators = new List<OperatorModels.OperatorModel>(),
MerchantCount = 0,
RecentMerchants = new List<Models.RecentMerchantsModel>(),
RecentMerchants = new List<MerchantModels.RecentMerchantsModel>(),
UserCount = 0
};

Expand All @@ -48,12 +48,12 @@ public void EstateIndex_DisplaysEstateDetails()
estate = estate with
{
ContractCount = 0,
RecentContracts = new List<Models.RecentContractModel>(),
RecentContracts = new List<ContractModels.RecentContractModel>(),
OperatorCount = 0,
AllOperators = new List<Models.OperatorModels.OperatorDropDownModel>(),
AssignedOperators = new List<OperatorModels.OperatorModel>(),
MerchantCount = 0,
RecentMerchants = new List<Models.RecentMerchantsModel>(),
RecentMerchants = new List<MerchantModels.RecentMerchantsModel>(),
UserCount = 0
};
this.EstateUIService.Setup(e => e.LoadEstate(It.IsAny<CorrelationId>(), It.IsAny<Guid>())).ReturnsAsync(Result.Success(estate));
Expand All @@ -73,12 +73,12 @@ public void EstateIndex_HasCorrectPageTitle()
estate = estate with
{
ContractCount = 0,
RecentContracts = new List<Models.RecentContractModel>(),
RecentContracts = new List<ContractModels.RecentContractModel>(),
OperatorCount = 0,
AllOperators = new List<Models.OperatorModels.OperatorDropDownModel>(),
AssignedOperators = new List<OperatorModels.OperatorModel>(),
MerchantCount = 0,
RecentMerchants = new List<Models.RecentMerchantsModel>(),
RecentMerchants = new List<MerchantModels.RecentMerchantsModel>(),
UserCount = 0
};
this.EstateUIService.Setup(e => e.LoadEstate(It.IsAny<CorrelationId>(), It.IsAny<Guid>())).ReturnsAsync(Result.Success(estate));
Expand Down Expand Up @@ -286,8 +286,8 @@ public void EstateIndex_RemoveOperator_Failure_ShowsErrorMessage()
public void EstateIndex_DisplaysMerchants_WhenPresent()
{
// Arrange
List<RecentMerchantsModel> merchants = new() {
new RecentMerchantsModel
List<MerchantModels.RecentMerchantsModel> merchants = new() {
new MerchantModels.RecentMerchantsModel
{
MerchantId = Guid.NewGuid(),
Name = "Test Merchant",
Expand Down Expand Up @@ -325,8 +325,8 @@ public void EstateIndex_DisplaysNoMerchants_WhenEmpty()
public void EstateIndex_DisplaysContracts_WhenPresent()
{
// Arrange
List<RecentContractModel> contracts = new() {
new RecentContractModel
List<ContractModels.RecentContractModel> contracts = new() {
new ContractModels.RecentContractModel
{
ContractId = Guid.NewGuid(),
Description = "Test Contract",
Expand Down Expand Up @@ -459,21 +459,21 @@ public void EstateIndex_SuccessMessage_ClearsWhenSwitchingTabs()
}

// Helper methods
private void SetupSuccessfulDataLoad(List<RecentMerchantsModel>? merchants = null,
List<RecentContractModel>? contracts = null,
private void SetupSuccessfulDataLoad(List<MerchantModels.RecentMerchantsModel>? merchants = null,
List<ContractModels.RecentContractModel>? contracts = null,
List<OperatorModels.OperatorModel>? assignedOperators = null,
List<OperatorModels.OperatorDropDownModel>? operators = null)
{
BlazorServer.Models.EstateModel estate = new(Guid.NewGuid(), "Test Estate", "EST001");
estate = estate with
{
ContractCount = 5,
RecentContracts = contracts ?? new List<RecentContractModel>(),
RecentContracts = contracts ?? new List<ContractModels.RecentContractModel>(),
OperatorCount = 3,
AllOperators = operators ?? new List<OperatorModels.OperatorDropDownModel>(),
AssignedOperators = assignedOperators ?? new List<OperatorModels.OperatorModel>(),
MerchantCount = 10,
RecentMerchants = merchants ?? new List<RecentMerchantsModel>(),
RecentMerchants = merchants ?? new List<MerchantModels.RecentMerchantsModel>(),
UserCount = 2
};
this.EstateUIService.Setup(e => e.LoadEstate(It.IsAny<CorrelationId>(), It.IsAny<Guid>())).ReturnsAsync(Result.Success(estate));
Expand All @@ -485,9 +485,9 @@ private void SetupSuccessfulDataLoadWithOperators(List<OperatorModels.OperatorDr
private void SetupSuccessfulDataLoadWithAssignedOperators(List<OperatorModels.OperatorModel> assignedOperators)
=> SetupSuccessfulDataLoad(assignedOperators: assignedOperators);

private void SetupSuccessfulDataLoadWithMerchants(List<RecentMerchantsModel> merchants)
private void SetupSuccessfulDataLoadWithMerchants(List<MerchantModels.RecentMerchantsModel> merchants)
=> SetupSuccessfulDataLoad(merchants: merchants);

private void SetupSuccessfulDataLoadWithContracts(List<RecentContractModel> contracts)
private void SetupSuccessfulDataLoadWithContracts(List<ContractModels.RecentContractModel> contracts)
=> SetupSuccessfulDataLoad(contracts: contracts);
}
162 changes: 133 additions & 29 deletions EstateManagementUI.BlazorServer.Tests/Pages/HomePageTests.cs
Original file line number Diff line number Diff line change
@@ -1,42 +1,43 @@
using Bunit;
using EstateManagementUI.BlazorServer.Components.Pages;
using EstateManagementUI.BlazorServer.Components.Permissions;
using EstateManagementUI.BlazorServer.Models;
using EstateManagementUI.BlazorServer.Permissions;
using EstateManagementUI.BlazorServer.UIServices;
using EstateManagementUI.BusinessLogic.BackendAPI.DataTransferObjects;
using EstateManagementUI.BusinessLogic.Client;
using EstateManagementUI.BusinessLogic.Requests;
using MediatR;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
using Moq;
using Shouldly;
using System.Security.Claims;
using EstateManagementUI.BusinessLogic.Client;
using EstateManagementUI.BusinessLogic.Requests;
using SimpleResults;
using System.Security.Claims;

namespace EstateManagementUI.BlazorServer.Tests.Pages;

public class HomePageTests : TestContext
public class HomePageTests : BaseTest
{
private readonly Mock<IMediator> _mockMediator;
private readonly Mock<AuthenticationStateProvider> _mockAuthStateProvider;
private readonly Mock<NavigationManager> _mockNavigationManager;
private readonly Mock<ICalendarUIService> _mockCalenderUiService;
private readonly Mock<IMerchantUIService> _mockMerchantUiService;
private readonly Mock<ITransactionUIService> _mockTransactionUiService;
private readonly Mock<IJSRuntime> _mockJSRuntime;
private readonly Mock<IPermissionService> _mockPermissionService;


public HomePageTests()
{
_mockMediator = new Mock<IMediator>();
_mockAuthStateProvider = new Mock<AuthenticationStateProvider>();
_mockNavigationManager = new Mock<NavigationManager>();
_mockCalenderUiService = new Mock<ICalendarUIService>();
_mockMerchantUiService = new Mock<IMerchantUIService>();
_mockTransactionUiService = new Mock<ITransactionUIService>();

_mockJSRuntime = new Mock<IJSRuntime>();
_mockPermissionService = new Mock<IPermissionService>();

Services.AddSingleton(_mockMediator.Object);
Services.AddSingleton(_mockAuthStateProvider.Object);
Services.AddSingleton(_mockNavigationManager.Object);
Services.AddSingleton(_mockCalenderUiService.Object);
Services.AddSingleton(_mockMerchantUiService.Object);
Services.AddSingleton(_mockTransactionUiService.Object);
Services.AddSingleton(_mockJSRuntime.Object);
Services.AddSingleton(_mockPermissionService.Object);

// Add required permission components
ComponentFactories.AddStub<RequirePermission>();
Expand All @@ -55,12 +56,63 @@ public void Home_RendersCorrectly()
var user = new ClaimsPrincipal(identity);
var authState = Task.FromResult(new AuthenticationState(user));

List<ComparisonDateModel> comparisonDates = new()
{
new ComparisonDateModel
{
Date = DateTime.Today,
Description = "Today"
},
new ComparisonDateModel
{
Date = DateTime.Today.AddDays(-1),
Description = "Yesterday"
}
};

TransactionModels.MerchantKpiModel merchantKpi = new() { MerchantsWithNoSaleInLast7Days = 5, MerchantsWithNoSaleToday = 12, MerchantsWithSaleInLastHour = 45 };

TransactionModels.TodaysSalesModel todaysSales = new()
{
ComparisonSalesCount = 450,
ComparisonSalesValue = 125000.00m,
ComparisonAverageValue = 277.78m,
TodaysSalesCount = 523,
TodaysSalesValue = 145000.00m,
TodaysAverageValue = 277.24m
};

List<MerchantModels.RecentMerchantsModel> recentMerchants = new()
{
new MerchantModels.RecentMerchantsModel
{
MerchantId = Guid.Parse("22222222-2222-2222-2222-222222222222"),
Name = "Test Merchant 1",
Reference = "MERCH001",
CreatedDateTime = DateTime.Now
},
new MerchantModels.RecentMerchantsModel
{
MerchantId = Guid.Parse("22222222-2222-2222-2222-222222222223"),
Name = "Test Merchant 2",
Reference = "MERCH002",
CreatedDateTime = DateTime.Now.AddDays(-1)
},
new MerchantModels.RecentMerchantsModel
{
MerchantId = Guid.Parse("22222222-2222-2222-2222-222222222224"),
Name = "Test Merchant 3",
Reference = "MERCH003",
CreatedDateTime = DateTime.Now.AddDays(-5)
}
};

_mockAuthStateProvider.Setup(x => x.GetAuthenticationStateAsync()).Returns(authState);
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetComparisonDatesQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockComparisonDates()));
this._mockMediator.Setup(m => m.Send(It.IsAny<MerchantQueries.GetMerchantKpiQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockMerchantKpi()));
this._mockMediator.Setup(m => m.Send(It.IsAny<TransactionQueries.GetTodaysSalesQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockTodaysSales()));
this._mockMediator.Setup(m => m.Send(It.IsAny<TransactionQueries.GetTodaysFailedSalesQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockTodaysSales()));
this._mockMediator.Setup(m => m.Send(It.IsAny<MerchantQueries.GetRecentMerchantsQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockRecentMerchants()));
this._mockCalenderUiService.Setup(m => m.GetComparisonDates(It.IsAny<CorrelationId>(), It.IsAny<Guid>())).ReturnsAsync(Result.Success(comparisonDates));
this._mockMerchantUiService.Setup(m => m.GetMerchantKpis(It.IsAny<CorrelationId>(), It.IsAny<Guid>())).ReturnsAsync(Result.Success(merchantKpi));
this._mockMerchantUiService.Setup(m => m.GetRecentMerchants(It.IsAny<CorrelationId>(), It.IsAny<Guid>())).ReturnsAsync(Result.Success(recentMerchants));
this._mockTransactionUiService.Setup(m => m.GetTodaysSales(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), It.IsAny<DateTime>())).ReturnsAsync(Result.Success(todaysSales));
this._mockTransactionUiService.Setup(m => m.GetTodaysFailedSales(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), It.IsAny<String>(), It.IsAny<DateTime>())).ReturnsAsync(Result.Success(todaysSales));

// Act
var cut = RenderComponent<Home>();
Expand All @@ -81,13 +133,65 @@ public void Home_HasCorrectPageTitle()
var identity = new ClaimsIdentity(claims, "Test");
var user = new ClaimsPrincipal(identity);
var authState = Task.FromResult(new AuthenticationState(user));


List<ComparisonDateModel> comparisonDates = new()
{
new ComparisonDateModel
{
Date = DateTime.Today,
Description = "Today"
},
new ComparisonDateModel
{
Date = DateTime.Today.AddDays(-1),
Description = "Yesterday"
}
};

TransactionModels.MerchantKpiModel merchantKpi = new() { MerchantsWithNoSaleInLast7Days = 5, MerchantsWithNoSaleToday = 12, MerchantsWithSaleInLastHour = 45 };

TransactionModels.TodaysSalesModel todaysSales = new()
{
ComparisonSalesCount = 450,
ComparisonSalesValue = 125000.00m,
ComparisonAverageValue = 277.78m,
TodaysSalesCount = 523,
TodaysSalesValue = 145000.00m,
TodaysAverageValue = 277.24m
};

List<MerchantModels.RecentMerchantsModel> recentMerchants = new()
{
new MerchantModels.RecentMerchantsModel
{
MerchantId = Guid.Parse("22222222-2222-2222-2222-222222222222"),
Name = "Test Merchant 1",
Reference = "MERCH001",
CreatedDateTime = DateTime.Now
},
new MerchantModels.RecentMerchantsModel
{
MerchantId = Guid.Parse("22222222-2222-2222-2222-222222222223"),
Name = "Test Merchant 2",
Reference = "MERCH002",
CreatedDateTime = DateTime.Now.AddDays(-1)
},
new MerchantModels.RecentMerchantsModel
{
MerchantId = Guid.Parse("22222222-2222-2222-2222-222222222224"),
Name = "Test Merchant 3",
Reference = "MERCH003",
CreatedDateTime = DateTime.Now.AddDays(-5)
}
};

_mockAuthStateProvider.Setup(x => x.GetAuthenticationStateAsync()).Returns(authState);
this._mockMediator.Setup(m => m.Send(It.IsAny<Queries.GetComparisonDatesQuery>())).ReturnsAsync(Result.Success( StubTestData.GetMockComparisonDates()));
this._mockMediator.Setup(m => m.Send(It.IsAny<MerchantQueries.GetMerchantKpiQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockMerchantKpi()));
this._mockMediator.Setup(m => m.Send(It.IsAny<TransactionQueries.GetTodaysSalesQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockTodaysSales()));
this._mockMediator.Setup(m => m.Send(It.IsAny<TransactionQueries.GetTodaysFailedSalesQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockTodaysSales()));
this._mockMediator.Setup(m => m.Send(It.IsAny<MerchantQueries.GetRecentMerchantsQuery>())).ReturnsAsync(Result.Success(StubTestData.GetMockRecentMerchants()));

this._mockCalenderUiService.Setup(m => m.GetComparisonDates(It.IsAny<CorrelationId>(), It.IsAny<Guid>())).ReturnsAsync(Result.Success(comparisonDates));
this._mockMerchantUiService.Setup(m => m.GetMerchantKpis(It.IsAny<CorrelationId>(), It.IsAny<Guid>())).ReturnsAsync(Result.Success(merchantKpi));
this._mockMerchantUiService.Setup(m => m.GetRecentMerchants(It.IsAny<CorrelationId>(), It.IsAny<Guid>())).ReturnsAsync(Result.Success(recentMerchants));
this._mockTransactionUiService.Setup(m => m.GetTodaysSales(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), It.IsAny<DateTime>())).ReturnsAsync(Result.Success(todaysSales));
this._mockTransactionUiService.Setup(m => m.GetTodaysFailedSales(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), It.IsAny<String>(), It.IsAny<DateTime>())).ReturnsAsync(Result.Success(todaysSales));


// Act
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using EstateManagementUI.BlazorServer.UIServices;
using EstateManagementUI.BusinessLogic.Models;
using EstateManagementUI.BusinessLogic.Requests;
using MediatR;
using Moq;
using Shouldly;
using SimpleResults;
using Xunit;

namespace EstateManagementUI.BlazorServer.Tests.UIServices
{
public class CalendarUIServiceTests
{
private readonly Mock<IMediator> _mockMediator;
private readonly CalendarUIService _service;

public CalendarUIServiceTests()
{
_mockMediator = new Mock<IMediator>();
_service = new CalendarUIService(_mockMediator.Object);
}

[Fact]
public async Task GetComparisonDates_ReturnsMappedList_WhenMediatorSucceeds()
{
// Arrange
var estateId = Guid.NewGuid();
var bizList = new List<ComparisonDateModel>
{
new() { Date = DateTime.UtcNow.Date.AddDays(-7), Description = "Last Week" },
new() { Date = DateTime.UtcNow.Date.AddDays(-30), Description = "Last Month" }
};

_mockMediator
.Setup(m => m.Send(It.IsAny<Queries.GetComparisonDatesQuery>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Success(bizList));

// Act
var result = await _service.GetComparisonDates(CorrelationIdHelper.New(), estateId);

// Assert
result.IsSuccess.ShouldBeTrue();
result.Data.ShouldNotBeNull();
result.Data!.Count.ShouldBe(2);
result.Data[0].Description.ShouldBe("Last Week");
result.Data[1].Description.ShouldBe("Last Month");

_mockMediator.Verify(m => m.Send(It.IsAny<Queries.GetComparisonDatesQuery>(), It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
public async Task GetComparisonDates_ReturnsFailure_WhenMediatorFails()
{
// Arrange
_mockMediator
.Setup(m => m.Send(It.IsAny<Queries.GetComparisonDatesQuery>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Failure("backend error"));

// Act
var result = await _service.GetComparisonDates(CorrelationIdHelper.New(), Guid.NewGuid());

// Assert
result.IsFailed.ShouldBeTrue();
_mockMediator.Verify(m => m.Send(It.IsAny<Queries.GetComparisonDatesQuery>(), It.IsAny<CancellationToken>()), Times.Once);
}
}
}
Loading
Loading