using FluentAssertions;
using MediatR;
using Workflow.Application.Integration.Commands;
using Workflow.Application.Integration.Handlers;
using Workflow.Application.Integration.Queries;
using Workflow.Application.Features.WorkflowInstances.Commands;
using Workflow.Domain.Entities;
using Workflow.Domain.Enums;
using Xunit;
namespace BuildFlow.Workflow.Tests.Integration;
///
/// AI/RAG 触发工作流的 CQRS 契约测试,禁止回退到 shared service bridge。
///
public class WorkflowTriggerCqrsTests
{
[Fact]
public async Task StartWorkflowByNameCommand_ShouldDispatchStartInstanceCommand()
{
await using var db = TestDbFactory.Create();
var definition = new WorkflowDefinition
{
Id = Guid.NewGuid(),
Name = "报销审批",
Code = "expense-approval",
Status = DefinitionStatus.Published,
Version = 1,
IsEnabled = true,
};
db.WorkflowDefinitions.Add(definition);
await db.SaveChangesAsync();
var instanceId = Guid.NewGuid();
var sender = new TestSender(instanceId);
var handler = new StartWorkflowByNameCommandHandler(db, sender);
var result = await handler.Handle(
new StartWorkflowByNameCommand("报销", Guid.NewGuid(), """{"amount":1200}"""),
CancellationToken.None);
result.Success.Should().BeTrue();
result.InstanceId.Should().Be(instanceId);
result.Title.Should().Be("报销");
sender.StartCommand.Should().NotBeNull();
sender.StartCommand!.DefinitionCode.Should().Be("expense-approval");
sender.StartCommand.Title.Should().StartWith("报销-");
sender.StartCommand.Variables.Should().Be("""{"amount":1200}""");
}
[Fact]
public async Task GetTriggerableWorkflowDefinitionsQuery_ShouldReturnPublishedDefinitions()
{
await using var db = TestDbFactory.Create();
db.WorkflowDefinitions.AddRange(
new WorkflowDefinition
{
Id = Guid.NewGuid(),
Name = "报销审批",
Code = "expense-approval",
Status = DefinitionStatus.Published,
Version = 1,
IsEnabled = true,
},
new WorkflowDefinition
{
Id = Guid.NewGuid(),
Name = "草稿流程",
Code = "draft-flow",
Status = DefinitionStatus.Draft,
Version = 1,
IsEnabled = true,
});
await db.SaveChangesAsync();
var handler = new GetTriggerableWorkflowDefinitionsQueryHandler(db);
var result = await handler.Handle(new GetTriggerableWorkflowDefinitionsQuery(), CancellationToken.None);
result.Should().ContainSingle();
result[0].Key.Should().Be("报销审批");
result[0].Name.Should().Be("报销审批");
}
private sealed class TestSender(Guid instanceId) : ISender
{
public StartWorkflowInstanceCommand? StartCommand { get; private set; }
public Task Send(IRequest request, CancellationToken cancellationToken = default)
{
if (request is StartWorkflowInstanceCommand command && typeof(TResponse) == typeof(Guid))
{
StartCommand = command;
return Task.FromResult((TResponse)(object)instanceId);
}
throw new NotSupportedException($"Unexpected request {request.GetType().Name}");
}
public Task Send(TRequest request, CancellationToken cancellationToken = default)
where TRequest : IRequest
=> throw new NotSupportedException($"Unexpected request {typeof(TRequest).Name}");
public Task