build-flow.api/tests/BuildFlow.Workflow.Tests/BuildFlow/BuildFlowButtonActionTests.cs

128 lines
4.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using FluentAssertions;
using Microsoft.EntityFrameworkCore;
using Workflow.Application.BuildFlow.Buttons.Commands;
using Workflow.Application.BuildFlow.Buttons.Handlers;
using Workflow.Application.BuildFlow.Buttons.Services;
using Workflow.Application.BuildFlow.CustomFunctions.Commands;
using Workflow.Application.BuildFlow.CustomFunctions.Handlers;
using Workflow.Application.BuildFlow.CustomFunctions.Services;
using Workflow.Domain.Entities;
using Workflow.Domain.Enums;
using Xunit;
namespace BuildFlow.Workflow.Tests.BuildFlow;
/// <summary>
/// 按钮动作链测试,约束按钮配置驱动后端动作执行,而不是前端写死行为。
/// </summary>
public class BuildFlowButtonActionTests
{
[Fact]
public async Task CreateButtonDefinition_PersistsActionMetadata()
{
await using var db = TestDbFactory.Create();
var handler = new CreateBuildFlowButtonDefinitionCommandHandler(db);
var button = await handler.Handle(
new CreateBuildFlowButtonDefinitionCommand(
null,
null,
null,
null,
"submit",
"提交",
"send",
BuildFlowButtonPlacement.FormToolbar,
"form:submit",
null,
null,
"""{"title":"确认提交?"}""",
"""[]""",
10),
CancellationToken.None);
button.Code.Should().Be("submit");
button.PermissionCode.Should().Be("form:submit");
button.Status.Should().Be(BuildFlowMetadataStatus.Draft);
}
[Fact]
public async Task ExecuteAsync_RunFunctionAction_ReturnsFunctionResultAndWritesLog()
{
await using var db = TestDbFactory.Create();
var function = await CreatePublishedFunctionAsync(db);
var button = CreateButton(function.Id);
db.BuildFlowButtons.Add(button);
await db.SaveChangesAsync();
var executor = new BuildFlowButtonActionExecutor(
db,
new CustomFunctionExecutionService(db));
var result = await executor.ExecuteAsync(
button.Id,
"""{"amount":1200}""",
CancellationToken.None);
result.Success.Should().BeTrue();
result.Results.Should().ContainSingle().Which.ResultJson.Should().Be("\"high\"");
(await db.BuildFlowActionExecutionLogs.CountAsync()).Should().Be(1);
}
[Fact]
public async Task ExecuteAsync_WhenActionFails_DoesNotPersistActionLog()
{
await using var db = TestDbFactory.Create();
var button = CreateButton(Guid.NewGuid());
db.BuildFlowButtons.Add(button);
await db.SaveChangesAsync();
var executor = new BuildFlowButtonActionExecutor(
db,
new CustomFunctionExecutionService(db));
var act = () => executor.ExecuteAsync(button.Id, "{}", CancellationToken.None);
await act.Should().ThrowAsync<BusinessException>();
(await db.BuildFlowActionExecutionLogs.CountAsync()).Should().Be(0);
}
private static async Task<CustomFunction> CreatePublishedFunctionAsync(WorkflowDbContext db)
{
var createHandler = new CreateCustomFunctionCommandHandler(db);
var publishHandler = new PublishCustomFunctionCommandHandler(db);
var function = await createHandler.Handle(
new CreateCustomFunctionCommand(
"button-amount-level",
"按钮金额分级",
null,
"((System.Text.Json.JsonElement)Variables[\"amount\"]).GetDecimal() > 1000 ? \"high\" : \"normal\"",
null,
null,
5000),
CancellationToken.None);
await publishHandler.Handle(new PublishCustomFunctionCommand(function.Id), CancellationToken.None);
return await db.CustomFunctions.FindAsync(function.Id) ?? throw new InvalidOperationException();
}
private static BuildFlowButtonDefinition CreateButton(Guid functionId)
=> new()
{
Id = Guid.NewGuid(),
Code = "submit-and-run",
Label = "提交并计算",
Placement = BuildFlowButtonPlacement.FormToolbar,
Status = BuildFlowMetadataStatus.Published,
ActionsJson = $$"""
[
{
"type": "runFunction",
"target": "{{functionId}}",
"params": { "amount": "$input.amount" },
"runPolicy": "stopOnFailure"
}
]
""",
};
}