- 从文件模块的多部分上传处理器中移除未使用的实体引用 - 从即时通讯模块的群组成员处理器中移除未使用的实体引用 - 从RAG模块的AI模型配置中移除未使用的实体引用 - 从监控模块的告警规则配置中移除未使用的实体引用 - 从平台模块的角色权限处理器中移除未使用的实体引用 - 从脚本模块的执行日志实体引用中进行清理 - 从多个基础设施配置类中移除未使用的依赖项 - 优化测试文件中的导入声明,移除不必要的引用
118 lines
4.4 KiB
C#
118 lines
4.4 KiB
C#
using FluentAssertions;
|
||
using Xunit;
|
||
using Workflow.Application.Form.ComponentRegistry.Handlers;
|
||
using Workflow.Application.Form.ComponentRegistry.Queries;
|
||
using Workflow.Domain.Entities;
|
||
|
||
namespace BuildFlow.Workflow.Tests.Form;
|
||
|
||
/// <summary>
|
||
/// manifest handler 单元测试:验证后端元数据驱动的物料清单查询逻辑
|
||
/// (分组、排序、IsActive 过滤、轻量投影不含 SupportedProps)。
|
||
/// </summary>
|
||
public class GetFormComponentManifestQueryHandlerTests
|
||
{
|
||
private static WorkflowDbContext CreateDb(params FormComponentRegistry[] seeds)
|
||
{
|
||
var db = TestDbFactory.Create();
|
||
if (seeds.Length > 0)
|
||
{
|
||
db.FormComponentRegistries.AddRange(seeds);
|
||
db.SaveChanges();
|
||
}
|
||
return db;
|
||
}
|
||
|
||
private static FormComponentRegistry Seed(
|
||
string name,
|
||
string category,
|
||
int sortOrder,
|
||
bool active = true,
|
||
string supportedProps = "{\"basic\":[]}") => new()
|
||
{
|
||
Id = Guid.NewGuid(),
|
||
Name = name,
|
||
DisplayName = name + "显示名",
|
||
Category = category,
|
||
Icon = "lucide:test",
|
||
DefaultSchema = "{}",
|
||
SupportedProps = supportedProps,
|
||
IsActive = active,
|
||
SortOrder = sortOrder,
|
||
};
|
||
|
||
[Fact]
|
||
public async Task Returns_Groups_By_Category_Sorted_By_SortOrder()
|
||
{
|
||
// 跨分类、乱序插入,验证分组聚合 + 组内/组间排序
|
||
var db = CreateDb(
|
||
Seed("Select", "选择控件", 2),
|
||
Seed("Input", "基础输入", 1),
|
||
Seed("RadioGroup", "选择控件", 1),
|
||
Seed("Textarea", "基础输入", 2)
|
||
);
|
||
var handler = new GetFormComponentManifestQueryHandler(db);
|
||
|
||
var result = await handler.Handle(new GetFormComponentManifestQuery(), default);
|
||
|
||
// 分组顺序:基础输入(sortOrder min=1) 在 选择控件(min=1) 之前?同 min 时按出现稳定顺序
|
||
// 基础输入组内最小 sortOrder=1,选择控件组内最小=1,两者相等,稳定排序保持插入顺序
|
||
result.Groups.Should().HaveCount(2);
|
||
var basic = result.Groups.First(g => g.Title == "基础输入");
|
||
basic.Items.Select(i => i.Name).Should().Equal(["Input", "Textarea"]);
|
||
var select = result.Groups.First(g => g.Title == "选择控件");
|
||
select.Items.Select(i => i.Name).Should().Equal(["RadioGroup", "Select"]);
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Filters_Out_Inactive_Components()
|
||
{
|
||
var db = CreateDb(
|
||
Seed("Input", "基础输入", 1, active: true),
|
||
Seed("Hidden", "基础输入", 2, active: false)
|
||
);
|
||
var handler = new GetFormComponentManifestQueryHandler(db);
|
||
|
||
var result = await handler.Handle(new GetFormComponentManifestQuery(), default);
|
||
|
||
result.Groups.Should().ContainSingle();
|
||
result.Groups[0].Items.Should().ContainSingle();
|
||
result.Groups[0].Items[0].Name.Should().Be("Input");
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Projection_Excludes_SupportedProps()
|
||
{
|
||
// manifest 是轻量接口:物料面板不需要 SupportedProps(那是属性面板用的全量接口的职责)
|
||
var db = CreateDb(
|
||
Seed("Input", "基础输入", 1, supportedProps: "{\"basic\":[{\"key\":\"placeholder\"}]}")
|
||
);
|
||
var handler = new GetFormComponentManifestQueryHandler(db);
|
||
|
||
var result = await handler.Handle(new GetFormComponentManifestQuery(), default);
|
||
|
||
var item = result.Groups[0].Items[0];
|
||
// ComponentManifestItem 只应有这 6 个字段,不含 SupportedProps
|
||
item.Name.Should().Be("Input");
|
||
item.DisplayName.Should().Be("Input显示名");
|
||
item.Category.Should().Be("基础输入");
|
||
item.Icon.Should().Be("lucide:test");
|
||
item.DefaultSchema.Should().Be("{}");
|
||
item.SortOrder.Should().Be(1);
|
||
// 确认 DTO 类型本身没有 SupportedProps 字段(编译期保证,运行期额外断言属性集)
|
||
item.GetType().GetProperties().Select(p => p.Name)
|
||
.Should().NotContain("SupportedProps");
|
||
}
|
||
|
||
[Fact]
|
||
public async Task Returns_Empty_When_No_Active_Components()
|
||
{
|
||
var db = CreateDb(Seed("Hidden", "x", 1, active: false));
|
||
var handler = new GetFormComponentManifestQueryHandler(db);
|
||
|
||
var result = await handler.Handle(new GetFormComponentManifestQuery(), default);
|
||
|
||
result.Groups.Should().BeEmpty();
|
||
}
|
||
}
|