145 lines
5.3 KiB
C#
145 lines
5.3 KiB
C#
using BuildFlow.Shared.Domain.Errors;
|
||
using FluentAssertions;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Workflow.Application.Features.Notifications;
|
||
using Xunit;
|
||
|
||
namespace BuildFlow.Workflow.Tests.Notification;
|
||
|
||
public class NotificationQueryTests
|
||
{
|
||
private static WorkflowDbContext CreateDbContext()
|
||
{
|
||
var options = new DbContextOptionsBuilder<WorkflowDbContext>()
|
||
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||
.Options;
|
||
var db = new WorkflowDbContext(options);
|
||
db.SavingChanges += AuditStub.OnSave;
|
||
return db; }
|
||
|
||
private static global::Workflow.Domain.Entities.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_ThrowsForbidden()
|
||
{
|
||
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);
|
||
|
||
var exception = await act.Should().ThrowAsync<UnauthorizedException>();
|
||
exception.Which.Code.Should().Be(ErrorCode.Forbidden);
|
||
}
|
||
|
||
[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();
|
||
}
|
||
}
|