using FluentAssertions; using Workflow.Application.Form.Derivation; using Workflow.Application.Form.Relation; using Xunit; namespace BuildFlow.Workflow.Tests.Form; public class FormRelationFieldTests { [Fact] public async Task DeriveAsync_RelationField_ResolvesSnapshot() { var service = new FormValueDerivationService([new SupplierResolver()], []); var result = await service.DeriveAsync( RelationSchema, """{"supplier":{"id":"supplier-1"},"supplierContact":"旧联系人"}""", new FormDerivationContext(null, Guid.NewGuid(), null), CancellationToken.None); result.DataJson.Should().Contain("\"label\":\"华东供应商\""); result.DataJson.Should().Contain("\"code\":\"SUP-001\""); result.DataJson.Should().NotContain("supplierContact"); } [Fact] public async Task DeriveAsync_RelationField_ThrowsWhenResolverMissing() { var service = new FormValueDerivationService([], []); var act = () => service.DeriveAsync( RelationSchema, """{"supplier":{"id":"supplier-1"}}""", new FormDerivationContext(null, Guid.NewGuid(), null), CancellationToken.None); await act.Should().ThrowAsync() .WithMessage("*关联源*supplier*未注册*"); } private sealed class SupplierResolver : IFormRelationResolver { public string SourceCode => "supplier"; public Task ResolveAsync( FormRelationResolveRequest request, CancellationToken ct) { request.Id.Should().Be("supplier-1"); return Task.FromResult(new FormRelationResolveResult( "supplier-1", "华东供应商", new Dictionary { ["code"] = "SUP-001", ["name"] = "华东供应商", })); } } private const string RelationSchema = """ { "type": "object", "properties": { "supplier": { "type": "object", "title": "供应商", "x-component": "RelationPicker", "x-field-kind": "relation", "x-relation": { "sourceType": "endpoint", "sourceCode": "supplier", "requestUrl": "/api/master-data/suppliers", "idField": "id", "labelField": "name", "snapshotFields": ["code", "name"], "onChange": { "clearFields": ["supplierContact"] }, "updatePolicy": "snapshotOnly" } }, "supplierContact": { "type": "string", "title": "供应商联系人", "x-component": "Input" } } } """; }