mirror of https://github.com/abpframework/abp.git
committed by
GitHub
5 changed files with 502 additions and 17 deletions
@ -0,0 +1,246 @@ |
|||||
|
#nullable enable |
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using System.Text.Encodings.Web; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding; |
||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures; |
||||
|
using Microsoft.AspNetCore.Razor.TagHelpers; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Shouldly; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
||||
|
|
||||
|
public class AbpSelectTagHelperService_Tests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public async Task Info_text_should_be_rendered_as_div_with_form_text_class() |
||||
|
{ |
||||
|
var service = new TestAbpSelectTagHelperService(); |
||||
|
var tagHelper = new AbpSelectTagHelper(service) |
||||
|
{ |
||||
|
AspFor = CreateModelExpression(), |
||||
|
InfoText = "Description" |
||||
|
}; |
||||
|
|
||||
|
var output = CreateOutput(); |
||||
|
|
||||
|
await tagHelper.ProcessAsync(CreateContext(), output); |
||||
|
|
||||
|
service.LastGroupHtml.ShouldContain("<div class=\"form-text\""); |
||||
|
service.LastGroupHtml.ShouldContain("id=\"TestSelectInfoText\""); |
||||
|
service.LastGroupHtml.ShouldNotContain("<small"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Info_text_should_set_aria_describedby_on_select() |
||||
|
{ |
||||
|
var service = new TestAbpSelectTagHelperService(); |
||||
|
var tagHelper = new AbpSelectTagHelper(service) |
||||
|
{ |
||||
|
AspFor = CreateModelExpression(), |
||||
|
InfoText = "Description" |
||||
|
}; |
||||
|
|
||||
|
var output = CreateOutput(); |
||||
|
|
||||
|
await tagHelper.ProcessAsync(CreateContext(), output); |
||||
|
|
||||
|
service.LastSelectTag.ShouldNotBeNull(); |
||||
|
service.LastSelectTag!.Attributes.ContainsName("aria-describedby").ShouldBeTrue(); |
||||
|
service.LastSelectTag.Attributes["aria-describedby"].Value.ToString().ShouldBe("TestSelectInfoText"); |
||||
|
service.LastGroupHtml.ShouldContain("aria-describedby=\"TestSelectInfoText\""); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Info_text_should_skip_id_and_aria_describedby_when_select_has_no_id() |
||||
|
{ |
||||
|
var service = new TestAbpSelectTagHelperService(selectId: null); |
||||
|
var tagHelper = new AbpSelectTagHelper(service) |
||||
|
{ |
||||
|
AspFor = CreateModelExpression(), |
||||
|
InfoText = "Description" |
||||
|
}; |
||||
|
|
||||
|
var output = CreateOutput(); |
||||
|
|
||||
|
await tagHelper.ProcessAsync(CreateContext(), output); |
||||
|
|
||||
|
service.LastGroupHtml.ShouldContain("<div class=\"form-text\""); |
||||
|
service.LastGroupHtml.ShouldContain("Description"); |
||||
|
service.LastGroupHtml.ShouldNotContain("id=\"InfoText\""); |
||||
|
service.LastGroupHtml.ShouldNotContain("aria-describedby=\"InfoText\""); |
||||
|
|
||||
|
service.LastSelectTag.ShouldNotBeNull(); |
||||
|
service.LastSelectTag!.Attributes.ContainsName("aria-describedby").ShouldBeFalse(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Aria_describedby_should_preserve_existing_value_set_by_caller() |
||||
|
{ |
||||
|
var service = new TestAbpSelectTagHelperService(existingAriaDescribedby: "custom-id"); |
||||
|
var tagHelper = new AbpSelectTagHelper(service) |
||||
|
{ |
||||
|
AspFor = CreateModelExpression(), |
||||
|
InfoText = "Description" |
||||
|
}; |
||||
|
|
||||
|
var output = CreateOutput(); |
||||
|
|
||||
|
await tagHelper.ProcessAsync(CreateContext(), output); |
||||
|
|
||||
|
service.LastSelectTag.ShouldNotBeNull(); |
||||
|
service.LastSelectTag!.Attributes["aria-describedby"].Value.ToString().ShouldBe("custom-id TestSelectInfoText"); |
||||
|
service.LastGroupHtml.ShouldContain("aria-describedby=\"custom-id TestSelectInfoText\""); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Aria_describedby_should_split_on_html_whitespace_separators() |
||||
|
{ |
||||
|
var service = new TestAbpSelectTagHelperService(existingAriaDescribedby: "id1\tid2"); |
||||
|
var tagHelper = new AbpSelectTagHelper(service) |
||||
|
{ |
||||
|
AspFor = CreateModelExpression(), |
||||
|
InfoText = "Description" |
||||
|
}; |
||||
|
|
||||
|
var output = CreateOutput(); |
||||
|
|
||||
|
await tagHelper.ProcessAsync(CreateContext(), output); |
||||
|
|
||||
|
service.LastSelectTag.ShouldNotBeNull(); |
||||
|
service.LastSelectTag!.Attributes["aria-describedby"].Value.ToString().ShouldBe("id1\tid2 TestSelectInfoText"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task InputInfoText_attribute_should_render_info_text_with_single_aria_describedby() |
||||
|
{ |
||||
|
var service = new TestAbpSelectTagHelperService(); |
||||
|
var tagHelper = new AbpSelectTagHelper(service) |
||||
|
{ |
||||
|
AspFor = CreateModelExpressionWithInputInfoText() |
||||
|
}; |
||||
|
|
||||
|
var output = CreateOutput(); |
||||
|
|
||||
|
await tagHelper.ProcessAsync(CreateContext(), output); |
||||
|
|
||||
|
service.LastGroupHtml.ShouldContain("<div class=\"form-text\""); |
||||
|
service.LastGroupHtml.ShouldContain("Description from attribute"); |
||||
|
service.LastGroupHtml.ShouldNotContain("<small"); |
||||
|
|
||||
|
service.LastSelectTag.ShouldNotBeNull(); |
||||
|
var ariaDescribedby = service.LastSelectTag!.Attributes.Where(a => a.Name == "aria-describedby").ToList(); |
||||
|
ariaDescribedby.Count.ShouldBe(1); |
||||
|
ariaDescribedby[0].Value.ToString().ShouldBe("TestSelectInfoText"); |
||||
|
} |
||||
|
|
||||
|
private static TagHelperContext CreateContext() |
||||
|
{ |
||||
|
return new TagHelperContext( |
||||
|
new TagHelperAttributeList(), |
||||
|
new Dictionary<object, object>(), |
||||
|
"test"); |
||||
|
} |
||||
|
|
||||
|
private static TagHelperOutput CreateOutput() |
||||
|
{ |
||||
|
return new TagHelperOutput( |
||||
|
"abp-select", |
||||
|
new TagHelperAttributeList(), |
||||
|
(_, _) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); |
||||
|
} |
||||
|
|
||||
|
private static ModelExpression CreateModelExpression() |
||||
|
{ |
||||
|
var metadataProvider = new EmptyModelMetadataProvider(); |
||||
|
return new ModelExpression( |
||||
|
"TestSelect", |
||||
|
metadataProvider.GetModelExplorerForType(typeof(string), null)); |
||||
|
} |
||||
|
|
||||
|
private static ModelExpression CreateModelExpressionWithInputInfoText() |
||||
|
{ |
||||
|
var metadataProvider = new EmptyModelMetadataProvider(); |
||||
|
var modelExplorer = metadataProvider |
||||
|
.GetModelExplorerForType(typeof(TestModelWithInputInfoText), null) |
||||
|
.GetExplorerForProperty(nameof(TestModelWithInputInfoText.TestSelect)); |
||||
|
return new ModelExpression(nameof(TestModelWithInputInfoText.TestSelect), modelExplorer); |
||||
|
} |
||||
|
|
||||
|
private class TestModelWithInputInfoText |
||||
|
{ |
||||
|
[InputInfoText("Description from attribute")] |
||||
|
public string TestSelect { get; set; } = string.Empty; |
||||
|
} |
||||
|
|
||||
|
private sealed class TestAbpSelectTagHelperService : AbpSelectTagHelperService |
||||
|
{ |
||||
|
private readonly string? _selectId; |
||||
|
private readonly string? _existingAriaDescribedby; |
||||
|
|
||||
|
public string LastGroupHtml { get; private set; } = string.Empty; |
||||
|
|
||||
|
public TagHelperOutput? LastSelectTag { get; private set; } |
||||
|
|
||||
|
public TestAbpSelectTagHelperService(string? selectId = "TestSelect", string? existingAriaDescribedby = null) |
||||
|
: base(null!, HtmlEncoder.Default, new FakeTagHelperLocalizer(), null!, null!) |
||||
|
{ |
||||
|
_selectId = selectId; |
||||
|
_existingAriaDescribedby = existingAriaDescribedby; |
||||
|
} |
||||
|
|
||||
|
protected override Task<TagHelperOutput> GetSelectTagAsync(TagHelperContext context, TagHelperOutput output, TagHelperContent childContent) |
||||
|
{ |
||||
|
var attributes = new TagHelperAttributeList(); |
||||
|
if (!string.IsNullOrEmpty(_selectId)) |
||||
|
{ |
||||
|
attributes.Add("id", _selectId); |
||||
|
} |
||||
|
if (!string.IsNullOrEmpty(_existingAriaDescribedby)) |
||||
|
{ |
||||
|
attributes.Add("aria-describedby", _existingAriaDescribedby); |
||||
|
} |
||||
|
|
||||
|
LastSelectTag = new TagHelperOutput( |
||||
|
"select", |
||||
|
attributes, |
||||
|
(_, _) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())) |
||||
|
{ |
||||
|
TagMode = TagMode.StartTagAndEndTag |
||||
|
}; |
||||
|
|
||||
|
AddInfoTextId(LastSelectTag); |
||||
|
|
||||
|
return Task.FromResult(LastSelectTag); |
||||
|
} |
||||
|
|
||||
|
protected override Task<string> GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput selectTag) |
||||
|
{ |
||||
|
return Task.FromResult(string.Empty); |
||||
|
} |
||||
|
|
||||
|
protected override Task<string> GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput selectTag) |
||||
|
{ |
||||
|
return Task.FromResult(string.Empty); |
||||
|
} |
||||
|
|
||||
|
protected override void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool suppress) |
||||
|
{ |
||||
|
LastGroupHtml = html; |
||||
|
suppress = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private sealed class FakeTagHelperLocalizer : IAbpTagHelperLocalizer |
||||
|
{ |
||||
|
public string GetLocalizedText(string text, ModelExplorer explorer) => text; |
||||
|
|
||||
|
public IStringLocalizer? GetLocalizerOrNull(ModelExplorer explorer) => null; |
||||
|
|
||||
|
public IStringLocalizer? GetLocalizerOrNull(Assembly assembly) => null; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue