Files
ROLAC/API/ROLAC.API.Tests/Services/GivingServiceTests.cs
Chris Chen 62592c29ae
ci-cd-vm / ci-cd (push) Successful in 4m2s
Add audit logs.
2026-06-23 12:13:47 -07:00

162 lines
5.8 KiB
C#

using Microsoft.EntityFrameworkCore;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Moq;
using ROLAC.API.Data;
using ROLAC.API.Data.Interceptors;
using ROLAC.API.DTOs.Giving;
using ROLAC.API.Entities;
using ROLAC.API.Services;
using Xunit;
namespace ROLAC.API.Tests.Services;
public class GivingServiceTests
{
private static IHttpContextAccessor BuildAccessor(string userId = "test-user")
{
var claims = new[] { new Claim(ClaimTypes.NameIdentifier, userId) };
var ctx = new DefaultHttpContext { User = new(new ClaimsIdentity(claims)) };
var mock = new Mock<IHttpContextAccessor>();
mock.Setup(x => x.HttpContext).Returns(ctx);
return mock.Object;
}
private static AppDbContext BuildDb(string userId = "test-user")
{
var interceptor = new AuditSaveChangesInterceptor(new ROLAC.API.Services.Logging.CurrentUserAccessor(BuildAccessor(userId)));
return new AppDbContext(
new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.AddInterceptors(interceptor)
.Options);
}
private static async Task<int> SeedCategoryAsync(AppDbContext db)
{
var c = new GivingCategory { Name_en = "Tithe", IsActive = true };
db.GivingCategories.Add(c);
await db.SaveChangesAsync();
return c.Id;
}
[Fact]
public async Task CreateAsync_PersistsGiving()
{
using var db = BuildDb();
var catId = await SeedCategoryAsync(db);
var svc = new GivingService(db);
var id = await svc.CreateAsync(new CreateGivingRequest
{
GivingCategoryId = catId, Amount = 100m, PaymentMethod = "Cash",
GivingDate = new DateOnly(2026, 5, 31), IsAnonymous = true,
});
var saved = await db.Givings.FindAsync(id);
Assert.NotNull(saved);
Assert.Equal(100m, saved!.Amount);
Assert.Null(saved.OfferingSessionId);
}
[Fact]
public async Task GetPagedAsync_FiltersByCategory()
{
using var db = BuildDb();
var catId = await SeedCategoryAsync(db);
var svc = new GivingService(db);
await svc.CreateAsync(new CreateGivingRequest { GivingCategoryId = catId, Amount = 10m, PaymentMethod = "Cash", GivingDate = new DateOnly(2026,5,31) });
var page = await svc.GetPagedAsync(1, 20, null, catId, null, null);
Assert.Equal(1, page.TotalCount);
Assert.Equal("Tithe", page.Items[0].CategoryName);
}
[Fact]
public async Task UpdateAsync_Throws_WhenGivingBelongsToSubmittedSession()
{
using var db = BuildDb();
var catId = await SeedCategoryAsync(db);
var session = new OfferingSession { SessionDate = new DateOnly(2026,5,31), Status = "Submitted" };
db.OfferingSessions.Add(session);
await db.SaveChangesAsync();
var giving = new Giving { GivingCategoryId = catId, Amount = 50m, PaymentMethod = "Cash",
GivingDate = new DateOnly(2026,5,31), OfferingSessionId = session.Id };
db.Givings.Add(giving);
await db.SaveChangesAsync();
var svc = new GivingService(db);
await Assert.ThrowsAsync<InvalidOperationException>(() =>
svc.UpdateAsync(giving.Id, new UpdateGivingRequest
{ GivingCategoryId = catId, Amount = 999m, PaymentMethod = "Cash", GivingDate = new DateOnly(2026,5,31) }));
}
[Fact]
public async Task DeleteAsync_Throws_WhenMissing()
{
using var db = BuildDb();
var svc = new GivingService(db);
await Assert.ThrowsAsync<KeyNotFoundException>(() => svc.DeleteAsync(999));
}
[Fact]
public async Task CreateAsync_Anonymous_NullsProvidedMemberId()
{
using var db = BuildDb();
var catId = await SeedCategoryAsync(db);
var svc = new GivingService(db);
var id = await svc.CreateAsync(new CreateGivingRequest
{
GivingCategoryId = catId, Amount = 25m, PaymentMethod = "Cash",
GivingDate = new DateOnly(2026, 5, 31),
IsAnonymous = true, MemberId = 12345, // provided, but must be stripped
});
var saved = await db.Givings.FindAsync(id);
Assert.True(saved!.IsAnonymous);
Assert.Null(saved.MemberId);
}
[Fact]
public async Task DeleteAsync_Throws_WhenGivingBelongsToSubmittedSession()
{
using var db = BuildDb();
var catId = await SeedCategoryAsync(db);
var session = new OfferingSession { SessionDate = new DateOnly(2026, 5, 31), Status = "Submitted" };
db.OfferingSessions.Add(session);
await db.SaveChangesAsync();
var giving = new Giving { GivingCategoryId = catId, Amount = 50m, PaymentMethod = "Cash",
GivingDate = new DateOnly(2026, 5, 31), OfferingSessionId = session.Id };
db.Givings.Add(giving);
await db.SaveChangesAsync();
var svc = new GivingService(db);
await Assert.ThrowsAsync<InvalidOperationException>(() => svc.DeleteAsync(giving.Id));
}
[Fact]
public async Task GetPagedAsync_MatchesByMemberName()
{
using var db = BuildDb();
var catId = await SeedCategoryAsync(db);
var member = new Member { FirstName_en = "Grace", LastName_en = "Lee" };
db.Members.Add(member);
await db.SaveChangesAsync();
var svc = new GivingService(db);
await svc.CreateAsync(new CreateGivingRequest
{
GivingCategoryId = catId, Amount = 75m, PaymentMethod = "Cash",
GivingDate = new DateOnly(2026, 5, 31), MemberId = member.Id,
});
var page = await svc.GetPagedAsync(1, 20, "grace", null, null, null);
Assert.Equal(1, page.TotalCount);
Assert.Equal(member.Id, page.Items[0].MemberId);
}
}