using FluentAssertions; using Microsoft.EntityFrameworkCore; using Workflow.Application.Features.Notifications; using Workflow.Domain.Entities; using Workflow.Domain.Exceptions; using Workflow.Infrastructure.Persistence; using Xunit; namespace Workflow.Tests.Notifications; public class NotificationQueryTests { private static WorkflowDbContext CreateDbContext() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; return new WorkflowDbContext(options); } private static Notification NewNotification( Guid? recipientUserId = null, string? recipientRole = null, bool isRead = false, string category = "task-arrived") => new() { Id = Guid.NewGuid(), RecipientUserId = recipientUserId, RecipientRole = recipientRole, Title = "T", Content = "C", Category = category, IsRead = isRead, CreatedAt = DateTime.UtcNow }; [Fact] public async Task GetNotifications_ReturnsBothUserAndRoleTargeted() { var db = CreateDbContext(); var userId = Guid.NewGuid(); db.Notifications.AddRange( NewNotification(recipientUserId: userId), // 给该用户 NewNotification(recipientRole: "manager"), // 给 manager 角色 NewNotification(recipientUserId: Guid.NewGuid()), // 给别人 NewNotification(recipientRole: "hr")); // 给别的角色 await db.SaveChangesAsync(); var handler = new GetNotificationsQueryHandler(db); var result = await handler.Handle( new GetNotificationsQuery(userId, ["manager"], false, 1, 20), default); result.Items.Should().HaveCount(2); result.Total.Should().Be(2); } [Fact] public async Task GetNotifications_UnreadOnly_FiltersReadOnes() { var db = CreateDbContext(); var userId = Guid.NewGuid(); db.Notifications.AddRange( NewNotification(recipientUserId: userId, isRead: false), NewNotification(recipientUserId: userId, isRead: false), NewNotification(recipientUserId: userId, isRead: true)); await db.SaveChangesAsync(); var handler = new GetNotificationsQueryHandler(db); var result = await handler.Handle( new GetNotificationsQuery(userId, [], true, 1, 20), default); result.Items.Should().HaveCount(2); } [Fact] public async Task GetUnreadCount_CountsUserAndRoleTargeted() { var db = CreateDbContext(); var userId = Guid.NewGuid(); db.Notifications.AddRange( NewNotification(recipientUserId: userId, isRead: false), NewNotification(recipientUserId: userId, isRead: true), NewNotification(recipientRole: "manager", isRead: false), NewNotification(recipientRole: "manager", isRead: false)); await db.SaveChangesAsync(); var handler = new GetUnreadNotificationCountHandler(db); var count = await handler.Handle( new GetUnreadNotificationCountQuery(userId, ["manager"]), default); count.Should().Be(3); // 1 user + 2 role } [Fact] public async Task MarkNotificationRead_SetsReadAndReadAt() { var db = CreateDbContext(); var userId = Guid.NewGuid(); var n = NewNotification(recipientUserId: userId, isRead: false); db.Notifications.Add(n); await db.SaveChangesAsync(); var handler = new MarkNotificationReadCommandHandler(db); await handler.Handle(new MarkNotificationReadCommand(n.Id, userId), default); var updated = await db.Notifications.FindAsync(n.Id); updated!.IsRead.Should().BeTrue(); updated.ReadAt.Should().NotBeNull(); } [Fact] public async Task MarkNotificationRead_NotOwnNotification_Throws() { var db = CreateDbContext(); var n = NewNotification(recipientUserId: Guid.NewGuid()); db.Notifications.Add(n); await db.SaveChangesAsync(); var handler = new MarkNotificationReadCommandHandler(db); var act = () => handler.Handle( new MarkNotificationReadCommand(n.Id, Guid.NewGuid()), default); await act.Should().ThrowAsync(); } [Fact] public async Task MarkAllNotificationsRead_MarksAllUserAndRoleTargeted() { var db = CreateDbContext(); var userId = Guid.NewGuid(); db.Notifications.AddRange( NewNotification(recipientUserId: userId, isRead: false), NewNotification(recipientRole: "manager", isRead: false), NewNotification(recipientRole: "hr", isRead: false)); // 不属于该用户 await db.SaveChangesAsync(); var handler = new MarkAllNotificationsReadCommandHandler(db); await handler.Handle( new MarkAllNotificationsReadCommand(userId, ["manager"]), default); var all = await db.Notifications.ToListAsync(); all.Count(n => n.IsRead).Should().Be(2); // user + manager 两读,hr 仍未读 all.First(n => n.RecipientRole == "hr").IsRead.Should().BeFalse(); } }