Browse Source

Mirror AbpSelectTagHelperService info text tests for AbpInputTagHelperService

Cover the new aria-describedby behaviour for <abp-input>:
- form-text rendered as <div>
- aria-describedby reaches the final HTML
- no-id case skips the InfoText id and aria-describedby
- caller-supplied aria-describedby is preserved (append + dedupe)
- [InputInfoText] attribute path produces a single aria-describedby
pull/25352/head
maliming 5 months ago
parent
commit
72cf6bbcb8
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 194
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Bootstrap/TagHelpers/Form/AbpInputTagHelperService_Tests.cs

194
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo/Abp/AspNetCore/Mvc/UI/Bootstrap/TagHelpers/Form/AbpInputTagHelperService_Tests.cs

@ -1,9 +1,14 @@
#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;
@ -45,6 +50,109 @@ public class AbpInputTagHelperService_Tests
service.LastGroupHtml.ShouldContain("mb-3");
}
[Fact]
public async Task Info_text_should_be_rendered_as_div_with_form_text_class()
{
var service = new TestAbpInputTagHelperServiceForInfo();
var tagHelper = new AbpInputTagHelper(service)
{
AspFor = CreateModelExpression(),
InfoText = "Description"
};
var output = CreateOutput();
await tagHelper.ProcessAsync(CreateContext(), output);
service.LastGroupHtml.ShouldContain("<div class=\"form-text\"");
service.LastGroupHtml.ShouldContain("id=\"TestInputInfoText\"");
service.LastGroupHtml.ShouldNotContain("<small");
}
[Fact]
public async Task Info_text_should_set_aria_describedby_on_input()
{
var service = new TestAbpInputTagHelperServiceForInfo();
var tagHelper = new AbpInputTagHelper(service)
{
AspFor = CreateModelExpression(),
InfoText = "Description"
};
var output = CreateOutput();
await tagHelper.ProcessAsync(CreateContext(), output);
service.LastInputTag.ShouldNotBeNull();
service.LastInputTag!.Attributes["aria-describedby"].Value.ToString().ShouldBe("TestInputInfoText");
service.LastGroupHtml.ShouldContain("aria-describedby=\"TestInputInfoText\"");
}
[Fact]
public async Task Info_text_should_skip_id_and_aria_describedby_when_input_has_no_id()
{
var service = new TestAbpInputTagHelperServiceForInfo(inputId: null);
var tagHelper = new AbpInputTagHelper(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.LastInputTag.ShouldNotBeNull();
service.LastInputTag!.Attributes.ContainsName("aria-describedby").ShouldBeFalse();
}
[Fact]
public async Task Aria_describedby_should_preserve_existing_value_set_by_caller()
{
var service = new TestAbpInputTagHelperServiceForInfo(existingAriaDescribedby: "custom-id");
var tagHelper = new AbpInputTagHelper(service)
{
AspFor = CreateModelExpression(),
InfoText = "Description"
};
var output = CreateOutput();
await tagHelper.ProcessAsync(CreateContext(), output);
service.LastInputTag.ShouldNotBeNull();
service.LastInputTag!.Attributes["aria-describedby"].Value.ToString().ShouldBe("custom-id TestInputInfoText");
service.LastGroupHtml.ShouldContain("aria-describedby=\"custom-id TestInputInfoText\"");
}
[Fact]
public async Task InputInfoText_attribute_should_render_info_text_with_single_aria_describedby()
{
var service = new TestAbpInputTagHelperServiceForInfo();
var tagHelper = new AbpInputTagHelper(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.LastInputTag.ShouldNotBeNull();
var ariaDescribedby = service.LastInputTag!.Attributes.Where(a => a.Name == "aria-describedby").ToList();
ariaDescribedby.Count.ShouldBe(1);
ariaDescribedby[0].Value.ToString().ShouldBe("TestInputInfoText");
}
private static TagHelperContext CreateContext()
{
return new TagHelperContext(
@ -69,6 +177,21 @@ public class AbpInputTagHelperService_Tests
metadataProvider.GetModelExplorerForType(typeof(string), null));
}
private static ModelExpression CreateModelExpressionWithInputInfoText()
{
var metadataProvider = new EmptyModelMetadataProvider();
var modelExplorer = metadataProvider
.GetModelExplorerForType(typeof(TestModelWithInputInfoText), null)
.GetExplorerForProperty(nameof(TestModelWithInputInfoText.TestInput));
return new ModelExpression(nameof(TestModelWithInputInfoText.TestInput), modelExplorer);
}
private class TestModelWithInputInfoText
{
[InputInfoText("Description from attribute")]
public string TestInput { get; set; } = string.Empty;
}
private sealed class TestAbpInputTagHelperService : AbpInputTagHelperService
{
private readonly string _inputTypeName;
@ -119,4 +242,75 @@ public class AbpInputTagHelperService_Tests
suppress = false;
}
}
private sealed class TestAbpInputTagHelperServiceForInfo : AbpInputTagHelperService
{
private readonly string? _inputId;
private readonly string? _existingAriaDescribedby;
public string LastGroupHtml { get; private set; } = string.Empty;
public TagHelperOutput? LastInputTag { get; private set; }
public TestAbpInputTagHelperServiceForInfo(string? inputId = "TestInput", string? existingAriaDescribedby = null)
: base(null!, HtmlEncoder.Default, new FakeTagHelperLocalizer())
{
_inputId = inputId;
_existingAriaDescribedby = existingAriaDescribedby;
}
protected override Task<(TagHelperOutput, bool)> GetInputTagHelperOutputAsync(TagHelperContext context, TagHelperOutput output)
{
var attributes = new TagHelperAttributeList
{
{ "type", "text" },
{ "class", "form-control" }
};
if (!string.IsNullOrEmpty(_inputId))
{
attributes.Add("id", _inputId);
}
if (!string.IsNullOrEmpty(_existingAriaDescribedby))
{
attributes.Add("aria-describedby", _existingAriaDescribedby);
}
LastInputTag = new TagHelperOutput(
"input",
attributes,
(_, _) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()))
{
TagMode = TagMode.SelfClosing
};
AddInfoTextId(LastInputTag);
return Task.FromResult((LastInputTag, false));
}
protected override Task<string> GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox)
{
return Task.FromResult(string.Empty);
}
protected override Task<string> GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
{
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…
Cancel
Save