using FluentAssertions; using Microsoft.EntityFrameworkCore; using Workflow.Application.Features.WorkflowTasks.Handlers; using Workflow.Application.Features.WorkflowTasks.Queries; using Workflow.Domain.Entities; using Workflow.Domain.Enums; using Xunit; using TaskStatus = global::Workflow.Domain.Enums.TaskStatus; namespace BuildFlow.Workflow.Tests.Handlers; public class OverdueAndCcTaskQueryHandlerTests { private static WorkflowDbContext CreateDbContext() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; var db = new WorkflowDbContext(options); db.SavingChanges += AuditStub.OnSave; return db; } private static WorkflowTask SeedTask(WorkflowDbContext db, Guid assigneeId, TaskType type, TaskStatus status, DateTime? dueAt) { var task = new WorkflowTask { Id = Guid.NewGuid(), InstanceId = Guid.NewGuid(), TokenId = Guid.NewGuid(), NodeId = Guid.NewGuid(), Title = "Task", AssigneeId = assigneeId, Type = type, Status = status, DueAt = dueAt }; db.WorkflowTasks.Add(task); return task; } #region GetOverdueTasks [Fact] public async Task GetOverdueTasks_ReturnsOverduePendingTasks() { await using var db = CreateDbContext(); var user = Guid.NewGuid(); SeedTask(db, user, TaskType.Approval, TaskStatus.Pending, DateTime.UtcNow.AddDays(-1)); await db.SaveChangesAsync(); var handler = new GetOverdueTasksQueryHandler(db); var result = await handler.Handle(new GetOverdueTasksQuery(null, 1, 10), CancellationToken.None); result.Should().NotBeNull(); result.Items.Should().HaveCount(1); result.Total.Should().Be(1); } [Fact] public async Task GetOverdueTasks_FiltersByUser() { await using var db = CreateDbContext(); var userA = Guid.NewGuid(); var userB = Guid.NewGuid(); SeedTask(db, userA, TaskType.Approval, TaskStatus.Pending, DateTime.UtcNow.AddDays(-1)); SeedTask(db, userB, TaskType.Approval, TaskStatus.Pending, DateTime.UtcNow.AddDays(-1)); await db.SaveChangesAsync(); var handler = new GetOverdueTasksQueryHandler(db); var result = await handler.Handle(new GetOverdueTasksQuery(userA, 1, 10), CancellationToken.None); result.Items.Should().HaveCount(1); result.Items[0].AssigneeId.Should().Be(userA); } [Fact] public async Task GetOverdueTasks_ExcludesFutureDueAndNonPending() { await using var db = CreateDbContext(); var user = Guid.NewGuid(); SeedTask(db, user, TaskType.Approval, TaskStatus.Pending, DateTime.UtcNow.AddDays(1)); SeedTask(db, user, TaskType.Approval, TaskStatus.Approved, DateTime.UtcNow.AddDays(-1)); await db.SaveChangesAsync(); var handler = new GetOverdueTasksQueryHandler(db); var result = await handler.Handle(new GetOverdueTasksQuery(null, 1, 10), CancellationToken.None); result.Items.Should().BeEmpty(); result.Total.Should().Be(0); } #endregion #region GetCcTasks [Fact] public async Task GetCcTasks_ReturnsCcTasksForUser() { await using var db = CreateDbContext(); var user = Guid.NewGuid(); SeedTask(db, user, TaskType.Cc, TaskStatus.Pending, null); SeedTask(db, user, TaskType.Approval, TaskStatus.Pending, null); await db.SaveChangesAsync(); var handler = new GetCcTasksQueryHandler(db); var result = await handler.Handle(new GetCcTasksQuery(user, 1, 10), CancellationToken.None); result.Items.Should().HaveCount(1); result.Items[0].Status.Should().Be(TaskStatus.Pending); } [Fact] public async Task GetCcTasks_EmptyForOtherUser() { await using var db = CreateDbContext(); SeedTask(db, Guid.NewGuid(), TaskType.Cc, TaskStatus.Pending, null); await db.SaveChangesAsync(); var handler = new GetCcTasksQueryHandler(db); var result = await handler.Handle(new GetCcTasksQuery(Guid.NewGuid(), 1, 10), CancellationToken.None); result.Items.Should().BeEmpty(); } #endregion }