- Add FormDefinitionVersion with compare/versions endpoints and schema differ - Add Notification entity, endpoints and application features - Add Scheduler (timeout) and WebhookDispatcher services - Add FormDataValidator/FieldPermissionEvaluator/ReactionEvaluator - Add workflow task mark-read, CC support and SystemUserContext - Add EF migrations for form versions and notifications - Add unit tests for form schema, notifications, scheduler and serialization
167 lines
4.8 KiB
C#
167 lines
4.8 KiB
C#
using FluentAssertions;
|
|
using Workflow.Application.Form.Schema;
|
|
using Xunit;
|
|
|
|
namespace Workflow.Tests.Form;
|
|
|
|
public class SchemaDifferTests
|
|
{
|
|
private const string OldSchema = """
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string", "title": "姓名", "required": true, "x-component": "Input" },
|
|
"age": { "type": "number", "title": "年龄", "x-component": "InputNumber" },
|
|
"gender": { "type": "string", "title": "性别", "x-component": "Select" }
|
|
}
|
|
}
|
|
""";
|
|
|
|
[Fact]
|
|
public void Diff_NoChanges_ReturnsEmpty()
|
|
{
|
|
var diff = SchemaDiffer.Diff(OldSchema, OldSchema);
|
|
|
|
diff.Added.Should().BeEmpty();
|
|
diff.Removed.Should().BeEmpty();
|
|
diff.Modified.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Diff_DetectsAddedField()
|
|
{
|
|
var newSchema = """
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string", "title": "姓名", "required": true, "x-component": "Input" },
|
|
"age": { "type": "number", "title": "年龄", "x-component": "InputNumber" },
|
|
"gender": { "type": "string", "title": "性别", "x-component": "Select" },
|
|
"email": { "type": "string", "title": "邮箱", "x-component": "Input" }
|
|
}
|
|
}
|
|
""";
|
|
|
|
var diff = SchemaDiffer.Diff(OldSchema, newSchema);
|
|
|
|
diff.Added.Should().ContainSingle(f => f.Path == "email");
|
|
diff.Removed.Should().BeEmpty();
|
|
diff.Modified.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Diff_DetectsRemovedField()
|
|
{
|
|
var newSchema = """
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string", "title": "姓名", "required": true, "x-component": "Input" },
|
|
"age": { "type": "number", "title": "年龄", "x-component": "InputNumber" }
|
|
}
|
|
}
|
|
""";
|
|
|
|
var diff = SchemaDiffer.Diff(OldSchema, newSchema);
|
|
|
|
diff.Removed.Should().ContainSingle(f => f.Path == "gender");
|
|
diff.Added.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Diff_DetectsComponentChange()
|
|
{
|
|
var newSchema = """
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string", "title": "姓名", "required": true, "x-component": "Input" },
|
|
"age": { "type": "number", "title": "年龄", "x-component": "Input" },
|
|
"gender": { "type": "string", "title": "性别", "x-component": "Select" }
|
|
}
|
|
}
|
|
""";
|
|
|
|
var diff = SchemaDiffer.Diff(OldSchema, newSchema);
|
|
|
|
diff.Modified.Should().ContainSingle(f => f.Path == "age" && f.Change!.Contains("组件"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Diff_DetectsRequiredChange()
|
|
{
|
|
var newSchema = """
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string", "title": "姓名", "x-component": "Input" },
|
|
"age": { "type": "number", "title": "年龄", "x-component": "InputNumber" },
|
|
"gender": { "type": "string", "title": "性别", "x-component": "Select" }
|
|
}
|
|
}
|
|
""";
|
|
|
|
var diff = SchemaDiffer.Diff(OldSchema, newSchema);
|
|
|
|
diff.Modified.Should().ContainSingle(f => f.Path == "name" && f.Change!.Contains("必填"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Diff_HandlesNullInputs()
|
|
{
|
|
var diff = SchemaDiffer.Diff(null, null);
|
|
|
|
diff.Added.Should().BeEmpty();
|
|
diff.Removed.Should().BeEmpty();
|
|
diff.Modified.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Diff_HandlesInvalidJson()
|
|
{
|
|
var diff = SchemaDiffer.Diff("not json", "{ }");
|
|
|
|
// 无效的旧 schema 视为空,新 schema 也空,无差异
|
|
diff.Added.Should().BeEmpty();
|
|
diff.Removed.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Diff_HandlesNestedFields()
|
|
{
|
|
var oldNested = """
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"card": {
|
|
"type": "void",
|
|
"x-component": "Card",
|
|
"properties": {
|
|
"name": { "type": "string", "title": "姓名", "x-component": "Input" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
""";
|
|
var newNested = """
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"card": {
|
|
"type": "void",
|
|
"x-component": "Card",
|
|
"properties": {
|
|
"name": { "type": "string", "title": "姓名", "x-component": "Input" },
|
|
"age": { "type": "number", "title": "年龄", "x-component": "InputNumber" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
""";
|
|
|
|
var diff = SchemaDiffer.Diff(oldNested, newNested);
|
|
|
|
diff.Added.Should().ContainSingle(f => f.Path == "card.age");
|
|
}
|
|
}
|