!2496 revert(#I4WSL1): recover remove code in ValidateForm

* test: 补充占位符单元测试
* test: 增加 ValidateFormTestBase 类
* refactor: 支持占位符错误信息
* revert: 恢复删除代码
This commit is contained in:
Argo 2022-03-08 03:46:50 +00:00
parent 09d447cd1d
commit 75838fdc98
5 changed files with 100 additions and 25 deletions

View File

@ -332,7 +332,10 @@ public partial class ValidateForm : IAsyncDisposable
{
rule.ErrorMessage = result.ErrorMessage;
}
results.Add(new ValidationResult(rule.ErrorMessage, new string[] { memberName }));
var errorMessage = !string.IsNullOrEmpty(rule.ErrorMessage) && rule.ErrorMessage.Contains("{0}")
? rule.FormatErrorMessage(displayName)
: rule.ErrorMessage;
results.Add(new ValidationResult(errorMessage, new string[] { memberName }));
}
}
}

View File

@ -3,14 +3,11 @@
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Shared;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using System;
using System.ComponentModel.DataAnnotations;
namespace UnitTest.Components;
public class ValidateFormTest : BootstrapBlazorTestBase
public class ValidateFormTest : ValidateFormTestBase
{
[Fact]
public void BootstrapBlazorDataAnnotationsValidator_Error()
@ -236,7 +233,7 @@ public class ValidateFormTest : BootstrapBlazorTestBase
}
[Fact]
public void Validate_UploadFile_Ok()
public async Task Validate_UploadFile_Ok()
{
var foo = new Dummy() { File = "text.txt" };
var cut = Context.RenderComponent<ValidateForm>(pb =>
@ -249,75 +246,83 @@ public class ValidateFormTest : BootstrapBlazorTestBase
});
});
var form = cut.Find("form");
cut.InvokeAsync(() => form.Submit());
await cut.InvokeAsync(() => form.Submit());
}
[Fact]
public void Validate_Localizer_Ok()
public async Task Validate_Localizer_Ok()
{
var foo = new MockFoo();
var cut = Context.RenderComponent<ValidateForm>(pb =>
{
pb.Add(a => a.Model, foo);
pb.AddChildContent<BootstrapInput<string>>(pb =>
pb.AddChildContent<MockInput<string>>(pb =>
{
pb.Add(a => a.Value, foo.Name);
pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(foo, "Name", typeof(string)));
});
});
var form = cut.Find("form");
cut.InvokeAsync(() => form.Submit());
await cut.InvokeAsync(() => form.Submit());
var msg = cut.FindComponent<MockInput<string>>().Instance.GetErrorMessage();
Assert.Equal("Name is Required", msg);
}
[Fact]
public void Validate_Attribute_Ok()
public async Task Validate_Attribute_Ok()
{
var foo = new MockFoo();
var cut = Context.RenderComponent<ValidateForm>(pb =>
{
pb.Add(a => a.Model, foo);
pb.AddChildContent<BootstrapInput<string>>(pb =>
pb.AddChildContent<MockInput<string>>(pb =>
{
pb.Add(a => a.Value, foo.Rule);
pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(foo, "Rule", typeof(string)));
});
});
var form = cut.Find("form");
cut.InvokeAsync(() => form.Submit());
await cut.InvokeAsync(() => form.Submit());
var msg = cut.FindComponent<MockInput<string>>().Instance.GetErrorMessage();
Assert.Equal("Rule is Required", msg);
}
[Fact]
public void Validate_MemberName_Ok()
public async Task Validate_MemberName_Ok()
{
var foo = new MockFoo();
var cut = Context.RenderComponent<ValidateForm>(pb =>
{
pb.Add(a => a.Model, foo);
pb.AddChildContent<BootstrapInput<string>>(pb =>
pb.AddChildContent<MockInput<string>>(pb =>
{
pb.Add(a => a.Value, foo.Member);
pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(foo, "Member", typeof(string)));
});
});
var form = cut.Find("form");
cut.InvokeAsync(() => form.Submit());
await cut.InvokeAsync(() => form.Submit());
var msg = cut.FindComponent<MockInput<string>>().Instance.GetErrorMessage();
Assert.Equal("Member is Required", msg);
}
[Fact]
public void Validate_Address_Ok()
public async Task Validate_Address_Ok()
{
var foo = new MockFoo();
var cut = Context.RenderComponent<ValidateForm>(pb =>
{
pb.Add(a => a.Model, foo);
pb.AddChildContent<BootstrapInput<string>>(pb =>
pb.AddChildContent<MockInput<string>>(pb =>
{
pb.Add(a => a.Value, foo.Address);
pb.Add(a => a.ValueExpression, Utility.GenerateValueExpression(foo, "Address", typeof(string)));
});
});
var form = cut.Find("form");
cut.InvokeAsync(() => form.Submit());
await cut.InvokeAsync(() => form.Submit());
var msg = cut.FindComponent<MockInput<string>>().Instance.GetErrorMessage();
Assert.Equal("Address must fill", msg);
}
[Fact]
@ -354,7 +359,6 @@ public class ValidateFormTest : BootstrapBlazorTestBase
[MetadataType(typeof(DummyMetadata))]
private class Dummy
{
[Required]
public DateTime? Value { get; set; }
public Foo Foo { get; set; } = new Foo();
@ -384,4 +388,9 @@ public class ValidateFormTest : BootstrapBlazorTestBase
[EmailAddress()]
public string? Member { get; set; } = "test";
}
private class MockInput<TValue> : BootstrapInput<TValue>
{
public string? GetErrorMessage() => base.ErrorMessage;
}
}

View File

@ -47,10 +47,7 @@ public class BootstrapBlazorTestHost : IDisposable
protected virtual void ConfigureServices(IServiceCollection services)
{
services.AddBootstrapBlazor();
services.ConfigureJsonLocalizationOptions(op =>
{
op.AdditionalJsonAssemblies = new[] { typeof(Alert).Assembly, GetType().Assembly };
});
services.ConfigureJsonLocalizationOptions(op => op.AdditionalJsonAssemblies = new[] { typeof(Alert).Assembly });
}
protected virtual void ConfigureConfigration(IServiceCollection services)

View File

@ -0,0 +1,66 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace UnitTest.Core;
[Collection("ValidateFormTestContext")]
public class ValidateFormTestBase
{
protected TestContext Context { get; }
public ValidateFormTestBase()
{
Context = ValidateFormTestHost.Instance;
}
}
[CollectionDefinition("ValidateFormTestContext")]
public class ValidateFormTestCollection : ICollectionFixture<ValidateFormTestHost>
{
}
public class ValidateFormTestHost : IDisposable
{
[NotNull]
internal static TestContext? Instance { get; private set; }
public ValidateFormTestHost()
{
Instance = new TestContext();
// Mock 脚本
Instance.JSInterop.Mode = JSRuntimeMode.Loose;
ConfigureServices(Instance.Services);
ConfigureConfigration(Instance.Services);
// 渲染 SwalRoot 组件 激活 ICacheManager 接口
Instance.Services.GetRequiredService<ICacheManager>();
}
protected virtual void ConfigureServices(IServiceCollection services)
{
services.AddBootstrapBlazor().ConfigureJsonLocalizationOptions(op =>
{
op.AdditionalJsonAssemblies = new[] { typeof(Alert).Assembly, GetType().Assembly };
});
}
protected virtual void ConfigureConfigration(IServiceCollection services)
{
// 增加单元测试 appsettings.json 配置文件
services.AddConfiguration();
}
public void Dispose()
{
Instance.Dispose();
GC.SuppressFinalize(this);
}
}

View File

@ -32,6 +32,6 @@
"Email": "Age msg"
},
"System.ComponentModel.DataAnnotations.RequiredAttribute": {
"ErrorMessage": "Rule is Required"
"ErrorMessage": "{0} is Required"
}
}