public void Reinitialize_AllowsContextToBeReused() { // Arrange var initialUniqueId = "123"; var expectedUniqueId = "456"; var initialItems = new Dictionary<object, object> { { "test-entry", 1234 } }; var expectedItems = new Dictionary<object, object> { { "something", "new" } }; var initialAttributes = new TagHelperAttributeList { { "name", "value" } }; var context = new TagHelperContext(initialAttributes, initialItems, initialUniqueId); // Act context.Reinitialize(expectedItems, expectedUniqueId); // Assert Assert.Same(expectedItems, context.Items); Assert.Equal(expectedUniqueId, context.UniqueId); Assert.Empty(context.AllAttributes); }
/// <summary> /// Instantiates a new instance of <see cref="TagHelperOutput"/>. /// </summary> /// <param name="tagName">The HTML element's tag name.</param> /// <param name="attributes">The HTML attributes.</param> public TagHelperOutput( string tagName, [NotNull] TagHelperAttributeList attributes) { TagName = tagName; Attributes = new TagHelperAttributeList(attributes); }
public void DetermineMode_SetsModeWithHigestValue() { // Arrange var modeInfos = new[] { new ModeAttributes<Mode>(Mode.A, new[] { "first-attr" }), new ModeAttributes<Mode>(Mode.B, new[] { "first-attr", "second-attr" }), new ModeAttributes<Mode>(Mode.D, new[] { "second-attr", "third-attr" }), new ModeAttributes<Mode>(Mode.C, new[] { "first-attr", "second-attr", "third-attr" }), }; var attributes = new TagHelperAttributeList { new TagHelperAttribute("first-attr", "value"), new TagHelperAttribute("second-attr", "value"), new TagHelperAttribute("third-attr", "value"), new TagHelperAttribute("not-in-any-mode", "value") }; var context = MakeTagHelperContext(attributes); // Act Mode result; var modeMatch = AttributeMatcher.TryDetermineMode(context, modeInfos, Compare, out result); // Assert Assert.True(modeMatch); Assert.Equal(Mode.D, result); }
/// <summary> /// Instantiates a new <see cref="TagHelperExecutionContext"/>. /// </summary> /// <param name="tagName">The HTML tag name in the Razor source.</param> /// <param name="tagMode">HTML syntax of the element in the Razor source.</param> /// <param name="items">The collection of items used to communicate with other /// <see cref="ITagHelper"/>s</param> /// <param name="uniqueId">An identifier unique to the HTML element this context is for.</param> /// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param> /// <param name="startTagHelperWritingScope"> /// A delegate used to start a writing scope in a Razor page and optionally override the page's /// <see cref="HtmlEncoder"/> within that scope. /// </param> /// <param name="endTagHelperWritingScope">A delegate used to end a writing scope in a Razor page.</param> public TagHelperExecutionContext( string tagName, TagMode tagMode, IDictionary<object, object> items, string uniqueId, Func<Task> executeChildContentAsync, Action<HtmlEncoder> startTagHelperWritingScope, Func<TagHelperContent> endTagHelperWritingScope) { if (startTagHelperWritingScope == null) { throw new ArgumentNullException(nameof(startTagHelperWritingScope)); } if (endTagHelperWritingScope == null) { throw new ArgumentNullException(nameof(endTagHelperWritingScope)); } _tagHelpers = new List<ITagHelper>(); _allAttributes = new TagHelperAttributeList(); Context = new TagHelperContext(_allAttributes, items, uniqueId); Output = new TagHelperOutput(tagName, new TagHelperAttributeList(), GetChildContentAsync) { TagMode = tagMode }; Reinitialize(tagName, tagMode, items, uniqueId, executeChildContentAsync); _startTagHelperWritingScope = startTagHelperWritingScope; _endTagHelperWritingScope = endTagHelperWritingScope; }
public void DetermineMode_FindsFullModeMatchWithMultipleAttributes() { // Arrange var modeInfo = new[] { ModeAttributes.Create("mode0", new [] { "first-attr", "second-attr" }) }; var attributes = new TagHelperAttributeList { ["first-attr"] = "value", ["second-attr"] = "value", ["not-in-any-mode"] = "value" }; var context = MakeTagHelperContext(attributes); // Act var modeMatch = AttributeMatcher.DetermineMode(context, modeInfo); // Assert Assert.Collection(modeMatch.FullMatches, match => { Assert.Equal("mode0", match.Mode); Assert.Collection(match.PresentAttributes, attribute => Assert.Equal("first-attr", attribute), attribute => Assert.Equal("second-attr", attribute) ); }); Assert.Empty(modeMatch.PartialMatches); Assert.Empty(modeMatch.PartiallyMatchedAttributes); }
public async Task CheckBoxHandlesMultipleAttributesSameNameCorrectly( TagHelperAttributeList outputAttributes, string expectedAttributeString) { // Arrange var originalContent = "original content"; var originalTagName = "not-input"; var expectedContent = $"{originalContent}<input {expectedAttributeString} id=\"HtmlEncode[[IsACar]]\" " + "name=\"HtmlEncode[[IsACar]]\" type=\"HtmlEncode[[checkbox]]\" value=\"HtmlEncode[[true]]\" />" + "<input name=\"HtmlEncode[[IsACar]]\" type=\"HtmlEncode[[hidden]]\" value=\"HtmlEncode[[false]]\" />"; var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>( Enumerable.Empty<IReadOnlyTagHelperAttribute>()), items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: useCachedResult => Task.FromResult<TagHelperContent>(result: null)); var output = new TagHelperOutput(originalTagName, outputAttributes) { TagMode = TagMode.SelfClosing, }; output.Content.SetContent(originalContent); var htmlGenerator = new TestableHtmlGenerator(new EmptyModelMetadataProvider()); var tagHelper = GetTagHelper(htmlGenerator, model: false, propertyName: nameof(Model.IsACar)); // Act await tagHelper.ProcessAsync(context, output); // Assert Assert.Empty(output.Attributes); // Moved to Content and cleared Assert.Equal(expectedContent, HtmlContentUtilities.HtmlContentToString(output.Content)); Assert.Equal(TagMode.SelfClosing, output.TagMode); Assert.Null(output.TagName); // Cleared }
public void DetermineMode_SetsModeIfAllAttributesMatch() { // Arrange var modeInfos = new[] { new ModeAttributes<Mode>(Mode.A, new[] { "a-required-attributes" }), new ModeAttributes<Mode>(Mode.B, new[] { "first-attr", "second-attr" }), new ModeAttributes<Mode>(Mode.C, new[] { "first-attr", "third-attr" }), }; var attributes = new TagHelperAttributeList { ["first-attr"] = "value", ["second-attr"] = "value", ["not-in-any-mode"] = "value" }; var context = MakeTagHelperContext(attributes); // Act Mode result; var modeMatch = AttributeMatcher.TryDetermineMode(context, modeInfos, Compare, out result); // Assert Assert.True(modeMatch); Assert.Equal(Mode.B, result); }
public void Process_SrcDefaultsToTagHelperOutputSrcAttributeAddedByOtherTagHelper( string src, string srcOutput, string expectedSrcPrefix) { // Arrange var allAttributes = new TagHelperAttributeList( new TagHelperAttributeList { { "alt", new HtmlString("Testing") }, { "asp-append-version", true }, }); var context = MakeTagHelperContext(allAttributes); var outputAttributes = new TagHelperAttributeList { { "alt", new HtmlString("Testing") }, { "src", srcOutput }, }; var output = new TagHelperOutput( "img", outputAttributes, getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>( new DefaultTagHelperContent())); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); var urlHelper = new Mock<IUrlHelper>(); // Ensure expanded path does not look like an absolute path on Linux, avoiding // https://github.com/aspnet/External/issues/21 urlHelper .Setup(urlhelper => urlhelper.Content(It.IsAny<string>())) .Returns(new Func<string, string>(url => url.Replace("~/", "virtualRoot/"))); var urlHelperFactory = new Mock<IUrlHelperFactory>(); urlHelperFactory .Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>())) .Returns(urlHelper.Object); var helper = new ImageTagHelper( hostingEnvironment, MakeCache(), new HtmlTestEncoder(), urlHelperFactory.Object) { ViewContext = viewContext, AppendVersion = true, Src = src, }; // Act helper.Process(context, output); // Assert Assert.Equal( expectedSrcPrefix + "?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", (string)output.Attributes["src"].Value, StringComparer.Ordinal); }
public void Process_HrefDefaultsToTagHelperOutputHrefAttributeAddedByOtherTagHelper( string href, string hrefOutput, string expectedHrefPrefix) { // Arrange var allAttributes = new TagHelperAttributeList( new TagHelperAttributeList { { "rel", new HtmlString("stylesheet") }, { "asp-append-version", true }, }); var context = MakeTagHelperContext(allAttributes); var outputAttributes = new TagHelperAttributeList { { "rel", new HtmlString("stylesheet") }, { "href", hrefOutput }, }; var output = MakeTagHelperOutput("link", outputAttributes); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); var urlHelper = new Mock<IUrlHelper>(); // Ensure expanded path does not look like an absolute path on Linux, avoiding // https://github.com/aspnet/External/issues/21 urlHelper .Setup(urlhelper => urlhelper.Content(It.IsAny<string>())) .Returns(new Func<string, string>(url => url.Replace("~/", "virtualRoot/"))); var urlHelperFactory = new Mock<IUrlHelperFactory>(); urlHelperFactory .Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>())) .Returns(urlHelper.Object); var helper = new LinkTagHelper( hostingEnvironment, MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), urlHelperFactory.Object) { ViewContext = viewContext, AppendVersion = true, Href = href, }; // Act helper.Process(context, output); // Assert Assert.Equal( expectedHrefPrefix + "?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", (string)output.Attributes["href"].Value, StringComparer.Ordinal); }
/// <summary> /// Instantiates a new instance of <see cref="TagHelperOutput"/>. /// </summary> /// <param name="tagName">The HTML element's tag name.</param> /// <param name="attributes">The HTML attributes.</param> public TagHelperOutput( string tagName, TagHelperAttributeList attributes) { if (attributes == null) { throw new ArgumentNullException(nameof(attributes)); } TagName = tagName; Attributes = new TagHelperAttributeList(attributes); }
public void IntIndexer_Getter_ThrowsIfIndexInvalid(int index) { // Arrange var attributes = new TagHelperAttributeList(new[] { new TagHelperAttribute("A", "AV"), new TagHelperAttribute("B", "BV") }); // Act & Assert var exception = Assert.Throws<ArgumentOutOfRangeException>("index", () => attributes[index]); }
public void Process_SrcDefaultsToTagHelperOutputSrcAttributeAddedByOtherTagHelper( string src, string srcOutput, string expectedSrcPrefix) { // Arrange var allAttributes = new TagHelperAttributeList( new TagHelperAttributeList { { "type", new HtmlString("text/javascript") }, { "asp-append-version", true }, }); var context = MakeTagHelperContext(allAttributes); var outputAttributes = new TagHelperAttributeList { { "type", new HtmlString("text/javascript") }, { "src", srcOutput }, }; var output = MakeTagHelperOutput("script", outputAttributes); var logger = new Mock<ILogger<ScriptTagHelper>>(); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); var urlHelper = new Mock<IUrlHelper>(); // Ensure expanded path does not look like an absolute path on Linux, avoiding // https://github.com/aspnet/External/issues/21 urlHelper .Setup(urlhelper => urlhelper.Content(It.IsAny<string>())) .Returns(new Func<string, string>(url => url.Replace("~/", "virtualRoot/"))); var helper = new ScriptTagHelper( logger.Object, hostingEnvironment, MakeCache(), new CommonTestEncoder(), new CommonTestEncoder(), urlHelper.Object) { ViewContext = viewContext, AppendVersion = true, Src = src, }; // Act helper.Process(context, output); // Assert Assert.Equal( expectedSrcPrefix + "?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", (string)output.Attributes["src"].Value, StringComparer.Ordinal); }
public void HandlesMultipleAttributesSameNameCorrectly(TagHelperAttributeList outputAttributes) { // Arrange var allAttributes = new TagHelperAttributeList( outputAttributes.Concat( new TagHelperAttributeList { { "rel", new HtmlString("stylesheet") }, { "href", "test.css" }, { "asp-fallback-href", "test.css" }, { "asp-fallback-test-class", "hidden" }, { "asp-fallback-test-property", "visibility" }, { "asp-fallback-test-value", "hidden" }, })); var context = MakeTagHelperContext(allAttributes); var combinedOutputAttributes = new TagHelperAttributeList( outputAttributes.Concat( new[] { new TagHelperAttribute("rel", new HtmlString("stylesheet")) })); var output = MakeTagHelperOutput("link", combinedOutputAttributes); var logger = new Mock<ILogger<LinkTagHelper>>(); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); var helper = new LinkTagHelper( logger.Object, hostingEnvironment, MakeCache(), new CommonTestEncoder(), new CommonTestEncoder(), MakeUrlHelper()) { ViewContext = viewContext, FallbackHref = "test.css", FallbackTestClass = "hidden", FallbackTestProperty = "visibility", FallbackTestValue = "hidden", Href = "test.css", }; var expectedAttributes = new TagHelperAttributeList(output.Attributes); expectedAttributes.Add(new TagHelperAttribute("href", "test.css")); // Act helper.Process(context, output); // Assert Assert.Equal(expectedAttributes, output.Attributes); }
public void IntIndexer_GetsExpectedAttribute( IEnumerable<TagHelperAttribute> initialAttributes, int indexToLookup, TagHelperAttribute expectedAttribute) { // Arrange var attributes = new TagHelperAttributeList(initialAttributes); // Act var attribute = attributes[indexToLookup]; // Assert Assert.Equal(expectedAttribute, attribute, CaseSensitiveTagHelperAttributeComparer.Default); }
public void IntIndexer_SetsAttributeAtExpectedIndex( IEnumerable<TagHelperAttribute> initialAttributes, int indexToSet, TagHelperAttribute setValue, IEnumerable<TagHelperAttribute> expectedAttributes) { // Arrange var attributes = new TagHelperAttributeList(initialAttributes); // Act attributes[indexToSet] = setValue; // Assert Assert.Equal(expectedAttributes, attributes, CaseSensitiveTagHelperAttributeComparer.Default); }
public async Task HandlesMultipleAttributesSameNameCorrectly( TagHelperAttributeList outputAttributes, string expectedAttributeString) { // Arrange var allAttributes = new TagHelperAttributeList( outputAttributes.Concat( new TagHelperAttributeList { ["data-extra"] = "something", ["src"] = "/blank.js", ["asp-fallback-src"] = "http://www.example.com/blank.js", ["asp-fallback-test"] = "isavailable()", })); var tagHelperContext = MakeTagHelperContext(allAttributes); var viewContext = MakeViewContext(); var combinedOutputAttributes = new TagHelperAttributeList( outputAttributes.Concat( new[] { new TagHelperAttribute("data-extra", new HtmlString("something")) })); var output = MakeTagHelperOutput("script", combinedOutputAttributes); var hostingEnvironment = MakeHostingEnvironment(); var helper = new ScriptTagHelper( CreateLogger(), hostingEnvironment, MakeCache(), new CommonTestEncoder(), new CommonTestEncoder()) { ViewContext = viewContext, FallbackSrc = "~/blank.js", FallbackTestExpression = "http://www.example.com/blank.js", Src = "/blank.js", }; // Act await helper.ProcessAsync(tagHelperContext, output); // Assert Assert.StartsWith( "<script " + expectedAttributeString + " data-extra=\"something\" " + "src=\"HtmlEncode[[/blank.js]]\"", output.Content.GetContent()); }
public async Task Reinitialize_AllowsOutputToBeReused() { // Arrange var initialOutputChildContent = new DefaultTagHelperContent(); initialOutputChildContent.SetContent("Initial output content."); var expectedGetChildContentContent = "Initial get child content content"; var initialGetChildContent = new DefaultTagHelperContent(); initialGetChildContent.SetContent(expectedGetChildContentContent); Func<bool, HtmlEncoder, Task<TagHelperContent>> initialGetChildContentAsync = (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(initialGetChildContent); var initialTagMode = TagMode.StartTagOnly; var initialAttributes = new TagHelperAttributeList { { "name", "value" } }; var initialTagName = "initialTagName"; var output = new TagHelperOutput(initialTagName, initialAttributes, initialGetChildContentAsync) { TagMode = initialTagMode, Content = initialOutputChildContent, }; output.PreContent.SetContent("something"); output.PostContent.SetContent("something"); output.PreElement.SetContent("something"); output.PostElement.SetContent("something"); var expectedTagName = "newTagName"; var expectedTagMode = TagMode.SelfClosing; // Act output.Reinitialize(expectedTagName, expectedTagMode); // Assert Assert.Equal(expectedTagName, output.TagName); Assert.Equal(expectedTagMode, output.TagMode); Assert.Empty(output.Attributes); var getChildContent = await output.GetChildContentAsync(); var content = getChildContent.GetContent(); // We're expecting the initial child content here because normally the TagHelper infrastructure would // swap out the inner workings of GetChildContentAsync to work with its reinitialized state. Assert.Equal(expectedGetChildContentContent, content); Assert.False(output.PreContent.IsModified); Assert.False(output.PostContent.IsModified); Assert.False(output.PreElement.IsModified); Assert.False(output.PostElement.IsModified); }
/// <summary> /// Instantiates a new instance of <see cref="TagHelperOutput"/>. /// </summary> /// <param name="tagName">The HTML element's tag name.</param> /// <param name="attributes">The HTML attributes.</param> /// <param name="getChildContentAsync">A delegate used to execute and retrieve the rendered child content /// asynchronously.</param> public TagHelperOutput( string tagName, TagHelperAttributeList attributes, Func<bool, Task<TagHelperContent>> getChildContentAsync) { if (attributes == null) { throw new ArgumentNullException(nameof(attributes)); } if (getChildContentAsync == null) { throw new ArgumentNullException(nameof(getChildContentAsync)); } TagName = tagName; Attributes = new TagHelperAttributeList(attributes); _getChildContentAsync = getChildContentAsync; }
public void TryDetermineMode_ReturnsFalseIfNoAttributeMatchesAllRequiredAttributes(string[] modeAttributes) { // Arrange var modeInfos = new[] { new ModeAttributes<Mode>(Mode.A, modeAttributes) }; var attributes = new TagHelperAttributeList { ["first-attr"] = "value", ["not-in-any-mode"] = "value" }; var context = MakeTagHelperContext(attributes); // Act Mode result; var modeMatch = AttributeMatcher.TryDetermineMode(context, modeInfos, Compare, out result); // Assert Assert.False(modeMatch); }
/// <summary> /// Instantiates a new <see cref="TagHelperExecutionContext"/>. /// </summary> /// <param name="tagName">The HTML tag name in the Razor source.</param> /// <param name="selfClosing"> /// <see cref="bool"/> indicating whether or not the tag in the Razor source was self-closing.</param> /// <param name="items">The collection of items used to communicate with other /// <see cref="ITagHelper"/>s</param> /// <param name="uniqueId">An identifier unique to the HTML element this context is for.</param> /// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param> /// <param name="startTagHelperWritingScope">A delegate used to start a writing scope in a Razor page.</param> /// <param name="endTagHelperWritingScope">A delegate used to end a writing scope in a Razor page.</param> public TagHelperExecutionContext( [NotNull] string tagName, bool selfClosing, [NotNull] IDictionary<object, object> items, [NotNull] string uniqueId, [NotNull] Func<Task> executeChildContentAsync, [NotNull] Action startTagHelperWritingScope, [NotNull] Func<TagHelperContent> endTagHelperWritingScope) { _tagHelpers = new List<ITagHelper>(); _executeChildContentAsync = executeChildContentAsync; _startTagHelperWritingScope = startTagHelperWritingScope; _endTagHelperWritingScope = endTagHelperWritingScope; SelfClosing = selfClosing; HTMLAttributes = new TagHelperAttributeList(); AllAttributes = new TagHelperAttributeList(); TagName = tagName; Items = items; UniqueId = uniqueId; }
/// <summary> /// Instantiates a new <see cref="TagHelperContext"/>. /// </summary> /// <param name="allAttributes">Every attribute associated with the current HTML element.</param> /// <param name="items">Collection of items used to communicate with other <see cref="ITagHelper"/>s.</param> /// <param name="uniqueId">The unique identifier for the source element this <see cref="TagHelperContext" /> /// applies to.</param> public TagHelperContext( TagHelperAttributeList allAttributes, IDictionary<object, object> items, string uniqueId) { if (items == null) { throw new ArgumentNullException(nameof(items)); } if (uniqueId == null) { throw new ArgumentNullException(nameof(uniqueId)); } if (allAttributes == null) { throw new ArgumentNullException(nameof(allAttributes)); } _allAttributes = allAttributes; Items = items; UniqueId = uniqueId; }
/// <summary> /// 获取结果 /// </summary> private string GetResult(TagHelperAttributeList contextAttributes = null, TagHelperAttributeList outputAttributes = null, TagHelperContent content = null, IDictionary <object, object> items = null) { return(Helper.GetResult(_output, _component, contextAttributes, outputAttributes, content, items)); }
protected virtual bool IsInputCheckbox(TagHelperContext context, TagHelperOutput output, TagHelperAttributeList attributes) { return(attributes.Any(a => a.Value != null && a.Name == "type" && a.Value.ToString() == "checkbox")); }
public async Task ProcessAsync_CallsGenerateRadioButton_WithExpectedParameters( string inputTypeName, string model) { // Arrange var value = "match"; // Real generator would use this for comparison with For.Metadata.Model. var contextAttributes = new TagHelperAttributeList { { "class", "form-control" }, { "value", value }, }; if (!string.IsNullOrEmpty(inputTypeName)) { contextAttributes.SetAttribute("type", inputTypeName); // Support restoration of type attribute, if any. } var expectedAttributes = new TagHelperAttributeList { { "class", "form-control radio-control" }, { "value", value }, { "type", inputTypeName ?? "radio" }, // Generator restores type attribute; adds "radio" if none. }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var expectedPostContent = "original post-content"; var expectedTagName = "not-input"; var context = new TagHelperContext( allAttributes: contextAttributes, items: new Dictionary <object, object>(), uniqueId: "test"); var originalAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var output = new TagHelperOutput( expectedTagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }) { TagMode = TagMode.StartTagOnly, }; output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent(expectedPostContent); var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict); var tagHelper = GetTagHelper(htmlGenerator.Object, model, nameof(Model.Text)); tagHelper.InputTypeName = inputTypeName; tagHelper.Value = value; var tagBuilder = new TagBuilder("input") { Attributes = { { "class", "radio-control" }, }, }; htmlGenerator .Setup(mock => mock.GenerateRadioButton( tagHelper.ViewContext, tagHelper.For.ModelExplorer, tagHelper.For.Name, value, null, // isChecked null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); // Act await tagHelper.ProcessAsync(context, output); // Assert htmlGenerator.Verify(); Assert.Equal(TagMode.StartTagOnly, output.TagMode); Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public async Task Process_GeneratesExpectedOutput( object container, Type containerType, object model, NameAndId nameAndId, string expectedContent) { // Arrange var expectedAttributes = new TagHelperAttributeList { { "class", "form-control" }, { "id", nameAndId.Id }, { "name", nameAndId.Name }, { "valid", "from validation attributes" }, }; var expectedTagName = "not-textarea"; var metadataProvider = new TestModelMetadataProvider(); var containerMetadata = metadataProvider.GetMetadataForType(containerType); var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, container); var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text"); var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, model); var htmlGenerator = new TestableHtmlGenerator(metadataProvider) { ValidationAttributes = { { "valid", "from validation attributes" }, } }; // Property name is either nameof(Model.Text) or nameof(NestedModel.Text). var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer); var tagHelper = new TextAreaTagHelper(htmlGenerator) { For = modelExpression, }; var tagHelperContext = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test", getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var htmlAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var output = new TagHelperOutput(expectedTagName, htmlAttributes) { TagMode = TagMode.SelfClosing, }; output.Content.SetContent("original content"); var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); tagHelper.ViewContext = viewContext; // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(TagMode.SelfClosing, output.TagMode); Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedContent, HtmlContentUtilities.HtmlContentToString(output.Content)); Assert.Equal(expectedTagName, output.TagName); }
public static IHtmlContent LocalizedEditor <TModel, TLocalizedModelLocal>(this IHtmlHelper <TModel> helper, string name, Func <int, HelperResult> localizedTemplate, Func <TModel, HelperResult> masterTemplate) where TModel : ILocalizedModel <TLocalizedModelLocal> where TLocalizedModelLocal : ILocalizedLocaleModel { var locales = helper.ViewData.Model.Locales; var hasMasterTemplate = masterTemplate != null; if (locales.Count > 1) { var services = helper.ViewContext.HttpContext.RequestServices; var db = services.GetRequiredService <SmartDbContext>(); var languageService = services.GetRequiredService <ILanguageService>(); var localizationService = services.GetRequiredService <ILocalizationService>(); var tabs = new List <TabItem>(locales.Count + 1); var languages = new List <Language>(locales.Count + 1); // Create the parent tabstrip var strip = new TabStripTagHelper { ViewContext = helper.ViewContext, Id = name, SmartTabSelection = false, Style = TabsStyle.Tabs, PublishEvent = false }; if (hasMasterTemplate) { var masterLanguage = db.Languages.FindById(languageService.GetMasterLanguageId(), false); languages.Add(masterLanguage); // Add the first default tab for the master template tabs.Add(new TabItem { Selected = true, Text = localizationService.GetResource("Admin.Common.Standard") }); } // Add all language specific tabs for (var i = 0; i < locales.Count; i++) { var locale = locales[i]; var language = db.Languages.FindById(locale.LanguageId, false); languages.Add(language); tabs.Add(new TabItem { Selected = !hasMasterTemplate && i == 0, Text = language.Name, ImageUrl = "~/images/flags/" + language.FlagImageFileName }); } // Create TagHelperContext for tabstrip. var stripContext = new TagHelperContext("tabstrip", new TagHelperAttributeList(), new Dictionary <object, object>(), CommonHelper.GenerateRandomDigitCode(10)); // Must init tabstrip, otherwise "Parent" is null inside tab helpers. strip.Init(stripContext); // Create tab factory var tabFactory = new TabFactory(strip, stripContext); // Create AttributeList for tabstrip var stripOutputAttrList = new TagHelperAttributeList { new TagHelperAttribute("class", "nav-locales") }; // Emulate tabstrip output var stripOutput = new TagHelperOutput("tabstrip", stripOutputAttrList, (_, _) => { // getChildContentAsync for tabstrip for (var i = 0; i < tabs.Count; i++) { var isMaster = hasMasterTemplate && i == 0; var language = languages[i]; tabFactory.AddAsync(builder => { builder.Item = tabs[i]; builder .Content(isMaster ? masterTemplate(helper.ViewData.Model) : localizedTemplate(hasMasterTemplate ? i - 1 : i)) .HtmlAttributes("title", language.Name, !isMaster) .ContentHtmlAttributes(new { @class = "locale-editor-content", data_lang = language.LanguageCulture, data_rtl = language.Rtl.ToString().ToLower() }); }).GetAwaiter().GetResult(); } // We don't need the child content for tabstrip. It builds everything without any child content. return(Task.FromResult <TagHelperContent>(new DefaultTagHelperContent())); }); // Process parent tabstrip strip.ProcessAsync(stripContext, stripOutput).GetAwaiter().GetResult(); var wrapper = new TagBuilder("div"); wrapper.Attributes.Add("class", "locale-editor"); return(stripOutput.WrapElementWith(wrapper)); } else if (hasMasterTemplate) { return(masterTemplate(helper.ViewData.Model)); } return(HtmlString.Empty); }
public async Task ProcessAsync_CallsGenerateTextBox_AddsExpectedAttributesForRfc3339( string propertyName, Html5DateRenderingMode dateRenderingMode, string expectedFormat, string expectedType) { // Arrange var expectedAttributes = new TagHelperAttributeList { { "type", expectedType }, // Calculated; not passed to HtmlGenerator. }; var expectedTagName = "not-input"; var context = new TagHelperContext( allAttributes: new TagHelperAttributeList( Enumerable.Empty <TagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList(), getChildContentAsync: (useCachedResult, encoder) => Task.FromResult <TagHelperContent>( new DefaultTagHelperContent())) { TagMode = TagMode.SelfClosing, }; var htmlAttributes = new Dictionary <string, object> { { "type", expectedType } }; var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict); var tagHelper = GetTagHelper( htmlGenerator.Object, model: null, propertyName: propertyName, metadataProvider: metadataProvider); tagHelper.ViewContext.Html5DateRenderingMode = dateRenderingMode; var tagBuilder = new TagBuilder("input"); htmlGenerator .Setup(mock => mock.GenerateTextBox( tagHelper.ViewContext, tagHelper.For.ModelExplorer, tagHelper.For.Name, null, // value expectedFormat, htmlAttributes)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); // Act await tagHelper.ProcessAsync(context, output); // Assert htmlGenerator.Verify(); Assert.Equal(TagMode.SelfClosing, output.TagMode); Assert.Equal(expectedAttributes, output.Attributes); Assert.Empty(output.PreContent.GetContent()); Assert.Equal(string.Empty, output.Content.GetContent()); Assert.Empty(output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public void AddMinimizedHtmlAttribute_MaintainsHTMLAttributes_SomeMinimized() { // Arrange var executionContext = new TagHelperExecutionContext("input", tagMode: TagMode.SelfClosing); var expectedAttributes = new TagHelperAttributeList { { "class", "btn" }, { "foo", "bar" } }; expectedAttributes.Add(new TagHelperAttribute { Name = "checked", Minimized = true }); expectedAttributes.Add(new TagHelperAttribute { Name = "visible", Minimized = true }); // Act executionContext.AddHtmlAttribute("class", "btn"); executionContext.AddHtmlAttribute("foo", "bar"); executionContext.AddMinimizedHtmlAttribute("checked"); executionContext.AddMinimizedHtmlAttribute("visible"); // Assert Assert.Equal( expectedAttributes, executionContext.HTMLAttributes, CaseSensitiveTagHelperAttributeComparer.Default); }
private void BuildFallbackBlock(TagHelperAttributeList attributes, TagHelperContent builder) { EnsureGlobbingUrlBuilder(); var fallbackHrefs = GlobbingUrlBuilder.BuildUrlList( FallbackHref, FallbackHrefInclude, FallbackHrefExclude); if (fallbackHrefs.Count == 0) { return; } builder.AppendHtml(HtmlString.NewLine); // Build the <meta /> tag that's used to test for the presence of the stylesheet builder .AppendHtml("<meta name=\"x-stylesheet-fallback-test\" content=\"\" class=\"") .Append(FallbackTestClass) .AppendHtml("\" />"); // Build the <script /> tag that checks the effective style of <meta /> tag above and renders the extra // <link /> tag to load the fallback stylesheet if the test CSS property value is found to be false, // indicating that the primary stylesheet failed to load. // GetEmbeddedJavaScript returns JavaScript to which we add '"{0}","{1}",{2});' builder .AppendHtml("<script>") .AppendHtml(JavaScriptResources.GetEmbeddedJavaScript(FallbackJavaScriptResourceName)) .AppendHtml("\"") .AppendHtml(JavaScriptEncoder.Encode(FallbackTestProperty)) .AppendHtml("\",\"") .AppendHtml(JavaScriptEncoder.Encode(FallbackTestValue)) .AppendHtml("\","); AppendFallbackHrefs(builder, fallbackHrefs); builder.AppendHtml(", \""); // Perf: Avoid allocating enumerator for (var i = 0; i < attributes.Count; i++) { var attribute = attributes[i]; if (string.Equals(attribute.Name, HrefAttributeName, StringComparison.OrdinalIgnoreCase)) { continue; } if (SuppressFallbackIntegrity && string.Equals(attribute.Name, IntegrityAttributeName, StringComparison.OrdinalIgnoreCase)) { continue; } attribute.WriteTo(StringWriter, HtmlEncoder); StringWriter.Write(' '); } var stringBuilder = StringWriter.GetStringBuilder(); var scriptTags = stringBuilder.ToString(); stringBuilder.Clear(); var encodedScriptTags = JavaScriptEncoder.Encode(scriptTags); builder.AppendHtml(encodedScriptTags); builder.AppendHtml("\");</script>"); }
private void BuildFallbackBlock(TagHelperAttributeList attributes, TagHelperContent builder) { EnsureGlobbingUrlBuilder(); var fallbackSrcs = GlobbingUrlBuilder.BuildUrlList(FallbackSrc, FallbackSrcInclude, FallbackSrcExclude); if (fallbackSrcs.Count > 0) { // Build the <script> tag that checks the test method and if it fails, renders the extra script. builder.AppendHtml(Environment.NewLine) .AppendHtml("<script>(") .AppendHtml(FallbackTestExpression) .AppendHtml("||document.write(\""); foreach (var src in fallbackSrcs) { // Fallback "src" values come from bound attributes and globbing. Must always be non-null. Debug.Assert(src != null); StringWriter.Write("<script"); var addSrc = true; // Perf: Avoid allocating enumerator for (var i = 0; i < attributes.Count; i++) { var attribute = attributes[i]; if (!attribute.Name.Equals(SrcAttributeName, StringComparison.OrdinalIgnoreCase)) { if (SuppressFallbackIntegrity && string.Equals(IntegrityAttributeName, attribute.Name, StringComparison.OrdinalIgnoreCase)) { continue; } StringWriter.Write(' '); attribute.WriteTo(StringWriter, HtmlEncoder); } else { addSrc = false; WriteVersionedSrc(attribute.Name, src, attribute.ValueStyle, StringWriter); } } if (addSrc) { WriteVersionedSrc(SrcAttributeName, src, HtmlAttributeValueStyle.DoubleQuotes, StringWriter); } StringWriter.Write("></script>"); } var stringBuilder = StringWriter.GetStringBuilder(); var scriptTags = stringBuilder.ToString(); stringBuilder.Clear(); var encodedScriptTags = JavaScriptEncoder.Encode(scriptTags); builder.AppendHtml(encodedScriptTags); builder.AppendHtml("\"));</script>"); } }
public MarkdownHelperToTheTagHelpers() { _inputAttributes = new List <IReadOnlyTagHelperAttribute>(); _outputAttributes = new TagHelperAttributeList(); }
public async Task ProcessAsync_GeneratesExpectedOutput_WithDisplayName( string displayName, string originalChildContent, string htmlFieldPrefix, string expectedContent, string expectedId) { // Arrange var expectedAttributes = new TagHelperAttributeList { { "for", expectedId } }; var name = nameof(NestedModel.Text); var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForProperty <NestedModel>(name) .DisplayDetails(metadata => metadata.DisplayName = () => displayName); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); var viewData = new ViewDataDictionary <NestedModel>(metadataProvider, viewContext.ModelState); viewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; viewContext.ViewData = viewData; var containerExplorer = metadataProvider.GetModelExplorerForType(typeof(NestedModel), model: null); var modelExplorer = containerExplorer.GetExplorerForProperty(name); var modelExpression = new ModelExpression(name, modelExplorer); var tagHelper = new LabelTagHelper(htmlGenerator) { For = modelExpression, ViewContext = viewContext, }; var tagHelperContext = new TagHelperContext( tagName: "label", allAttributes: new TagHelperAttributeList(), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( "label", new TagHelperAttributeList(), getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.AppendHtml(originalChildContent); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedContent, HtmlContentUtilities.HtmlContentToString(output.Content)); }
public async Task ProcessAsync_GeneratesExpectedOutput( object container, Type containerType, object model, NameAndId nameAndId, string expectedValue) { // Arrange var expectedAttributes = new TagHelperAttributeList { { "class", "form-control" }, { "type", "text" }, { "id", nameAndId.Id }, { "name", nameAndId.Name }, { "valid", "from validation attributes" }, { "value", expectedValue }, }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var expectedPostContent = "original post-content"; var expectedTagName = "not-input"; var context = new TagHelperContext( allAttributes: new TagHelperAttributeList( Enumerable.Empty <TagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var originalAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var output = new TagHelperOutput( expectedTagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }) { TagMode = TagMode.StartTagOnly, }; output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent(expectedPostContent); var htmlGenerator = new TestableHtmlGenerator(new EmptyModelMetadataProvider()) { ValidationAttributes = { { "valid", "from validation attributes" }, } }; // Property name is either nameof(Model.Text) or nameof(NestedModel.Text). var tagHelper = GetTagHelper( htmlGenerator, container, containerType, model, propertyName: nameof(Model.Text), expressionName: nameAndId.Name); // Act await tagHelper.ProcessAsync(context, output); // Assert Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(TagMode.StartTagOnly, output.TagMode); Assert.Equal(expectedTagName, output.TagName); }
public ITagHelper Create(ITagHelperFactory factory, ViewContext context, FilterArguments arguments, out TagHelperAttributeList contextAttributes, out TagHelperAttributeList outputAttributes) { contextAttributes = new TagHelperAttributeList(); outputAttributes = new TagHelperAttributeList(); ITagHelper tagHelper; if (_activatorByService != null) { tagHelper = _activatorByService(context); } else { tagHelper = _activatorByFactory(factory, context); } var expresionProvider = context.HttpContext.RequestServices.GetRequiredService <ModelExpressionProvider>(); var viewData = context.ViewData as ViewDataDictionary <object>; if (viewData == null) { viewData = new ViewDataDictionary <object>(context.ViewData); } foreach (var name in arguments.Names) { var propertyName = name.ToPascalCaseUnderscore(); var dictionaryName = String.Empty; var dictionaryKey = String.Empty; if (!_setters.TryGetValue(propertyName, out var setter)) { var index = name.LastIndexOf('_'); if (index > -1) { dictionaryName = name.Substring(0, index + 1); dictionaryKey = name.Substring(index + 1); if (dictionaryName.Length > 0 && dictionaryKey.Length > 0) { _setters.TryGetValue(dictionaryName, out setter); } } } var found = false; if (setter != null) { try { setter(tagHelper, expresionProvider, viewData, dictionaryKey, arguments[name]); found = true; } catch (ArgumentException e) { throw new ArgumentException("Incorrect value type assigned to a tag.", name, e); } } var attribute = new TagHelperAttribute(name.Replace('_', '-'), arguments[name].ToObjectValue()); contextAttributes.Add(attribute); if (!found) { outputAttributes.Add(attribute); } } return(tagHelper); }
/// <summary> /// 获取结果 /// </summary> private string GetResult(TagHelperAttributeList contextAttributes = null, TagHelperAttributeList outputAttributes = null, TagHelperContent content = null) { contextAttributes = contextAttributes ?? new TagHelperAttributeList(); contextAttributes.Add(UiConst.Type, TextBoxType.Number); return(Helper.GetResult(_output, _component, contextAttributes, outputAttributes, content)); }
public async Task ProcessAsync_CallsGenerateTextBox_WithExpectedParameters( string dataTypeName, string inputTypeName, string model) { // Arrange var contextAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; if (!string.IsNullOrEmpty(inputTypeName)) { contextAttributes.SetAttribute("type", inputTypeName); // Support restoration of type attribute, if any. } var expectedAttributes = new TagHelperAttributeList { { "class", "form-control text-control" }, { "type", inputTypeName ?? "text" }, // Generator restores type attribute; adds "text" if none. }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var expectedPostContent = "original post-content"; var expectedTagName = "not-input"; var context = new TagHelperContext( allAttributes: contextAttributes, items: new Dictionary <object, object>(), uniqueId: "test"); var originalAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var output = new TagHelperOutput( expectedTagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }) { TagMode = TagMode.StartTagOnly, }; output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent(expectedPostContent); var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForProperty <Model>("Text").DisplayDetails(dd => dd.DataTypeName = dataTypeName); var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict); var tagHelper = GetTagHelper( htmlGenerator.Object, model, nameof(Model.Text), metadataProvider: metadataProvider); tagHelper.InputTypeName = inputTypeName; var tagBuilder = new TagBuilder("input") { Attributes = { { "class", "text-control" }, }, }; htmlGenerator .Setup(mock => mock.GenerateTextBox( tagHelper.ViewContext, tagHelper.For.ModelExplorer, tagHelper.For.Name, model, // value null, // format It.Is <Dictionary <string, object> >(m => m.ContainsKey("type")))) // htmlAttributes .Returns(tagBuilder) .Verifiable(); // Act await tagHelper.ProcessAsync(context, output); // Assert htmlGenerator.Verify(); Assert.Equal(TagMode.StartTagOnly, output.TagMode); Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
private bool CanBeActive(TagHelperAttributeList attributes) => ActiveClass != null && attributes.ContainsName("href") && attributes["href"].Value != null;
/// <summary> /// 获取结果 /// </summary> /// <typeparam name="TTagHelper">TagHelper组件类型</typeparam> /// <param name="outputHelper">输出工具</param> /// <param name="component">TagHelper组件</param> /// <param name="contextAttributes">上下文属性集合</param> /// <param name="outputAttributes">输出属性集合</param> /// <param name="content">内容</param> /// <param name="items">项集合</param> public static string GetResult <TTagHelper>(ITestOutputHelper outputHelper, TTagHelper component, TagHelperAttributeList contextAttributes = null, TagHelperAttributeList outputAttributes = null, TagHelperContent content = null, IDictionary <object, object> items = null) where TTagHelper : TagHelper { var context = new TagHelperContext("", contextAttributes ?? new TagHelperAttributeList(), items ?? new Dictionary <object, object>(), Id.Guid()); var output = new TagHelperOutput("", outputAttributes ?? new TagHelperAttributeList(), (useCachedResult, encoder) => Task.FromResult(content)); component.ProcessAsync(context, output); var writer = new StringWriter(); output.WriteTo(writer, HtmlEncoder.Default); var result = writer.ToString(); outputHelper.WriteLine(result); return(result); }
public async Task ProcessAsync_DoesNotUseGenerator_IfSelectedNullOrNoSelectedValues( string originalContent, string selected, string value, IEnumerable<string> selectedValues, TagHelperOutput ignored) { // Arrange var originalAttributes = new TagHelperAttributeList { { "label", "my-label" }, { "selected", selected }, }; var originalTagName = "not-option"; var contextAttributes = new TagHelperAttributeList { { "label", "my-label" }, { "selected", selected }, { "value", value }, }; var originalPreContent = "original pre-content"; var originalPostContent = "original post-content"; var tagHelperContext = new TagHelperContext( contextAttributes, items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent(originalContent); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var output = new TagHelperOutput(originalTagName, originalAttributes) { TagMode = TagMode.StartTagAndEndTag, }; output.PreContent.SetContent(originalPreContent); output.Content.SetContent(originalContent); output.PostContent.SetContent(originalPostContent); var metadataProvider = new EmptyModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); viewContext.FormContext.FormData[SelectTagHelper.SelectedValuesFormDataKey] = selectedValues; var tagHelper = new OptionTagHelper(htmlGenerator) { Value = value, ViewContext = viewContext, }; // Act & Assert (does not throw) // Tag helper would throw an NRE if it used Generator value. await tagHelper.ProcessAsync(tagHelperContext, output); }
public TagBuilder GenerateTextArea(ViewContext viewContext, ModelExpression modelExpression, TagHelperAttributeList attributes, Localization localization = null, string additionalCssClass = null) { TagBuilder tb = new TagBuilder("textarea"); if (!string.IsNullOrEmpty(additionalCssClass)) { tb.AddCssClass(additionalCssClass); } tb.AddCssClass("text-area"); if (!this.IsValid(viewContext, modelExpression, localization)) { tb.AddCssClass("input-validation-error"); } tb.MergeAttribute("id", this.GetIdentity(modelExpression, localization)); tb.MergeAttribute("name", this.GetIdentity(modelExpression, localization)); if (localization != null) { tb.MergeAttribute("data-culture", localization.Culture.Code); } this.MergeRequiredAttribute(tb, modelExpression, "text-area--required"); this.MergeStringLengthAttribute(tb, modelExpression); this.MergeOtherAttribute(tb, attributes); string value = this.GetValue(viewContext, modelExpression, localization); if (!string.IsNullOrEmpty(value)) { tb.InnerHtml.Clear(); tb.InnerHtml.Append(value); } return(tb); }
public async Task ProcessAsync_GeneratesExpectedOutput_WithPropertyErrors() { // Arrange var expectedError0 = "I am an error."; var expectedError2 = "I am also an error."; var expectedTagName = "not-div"; var expectedAttributes = new TagHelperAttributeList { new TagHelperAttribute("class", "form-control validation-summary-errors"), new TagHelperAttribute("data-valmsg-summary", "true"), }; var metadataProvider = new TestModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var validationSummaryTagHelper = new ValidationSummaryTagHelper(htmlGenerator) { ValidationSummary = ValidationSummary.All, }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var tagHelperContext = new TagHelperContext( tagName: "not-div", allAttributes: new TagHelperAttributeList(), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "class", "form-control" } }, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent("Custom Content"); var model = new Model(); var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); validationSummaryTagHelper.ViewContext = viewContext; var modelState = viewContext.ModelState; SetValidModelState(modelState); modelState.AddModelError(key: $"{nameof(Model.Strings)}[0]", errorMessage: expectedError0); modelState.AddModelError(key: $"{nameof(Model.Strings)}[2]", errorMessage: expectedError2); // Act await validationSummaryTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(expectedAttributes, output.Attributes, CaseSensitiveTagHelperAttributeComparer.Default); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal( $"Custom Content<ul><li>{expectedError0}</li>{Environment.NewLine}" + $"<li>{expectedError2}</li>{Environment.NewLine}</ul>", output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
private static TagHelperOutput MakeImageTagHelperOutput(TagHelperAttributeList attributes) { attributes = attributes ?? new TagHelperAttributeList(); return new TagHelperOutput("img", attributes); }
protected virtual string RenderTagHelper(TagHelperAttributeList attributeList, TagHelperContext context, TagHelper tagHelper, HtmlEncoder htmlEncoder, string tagName = "div", TagMode tagMode = TagMode.SelfClosing, bool runAsync = false) { var innerOutput = GetInnerTagHelper(attributeList, context, tagHelper, tagName, tagMode, runAsync); return(RenderTagHelperOutput(innerOutput, htmlEncoder)); }
public async Task ProcessAsync_DoesNotUseViewContext_IfSelectedNotNull( string originalContent, string selected, string value, IEnumerable<string> ignoredValues, TagHelperOutput ignoredOutput) { // Arrange var originalAttributes = new TagHelperAttributeList { { "label", "my-label" }, { "selected", selected }, }; var originalTagName = "not-option"; var contextAttributes = new TagHelperAttributeList { { "label", "my-label" }, { "selected", selected }, { "value", value }, }; var originalPreContent = "original pre-content"; var originalPostContent = "original post-content"; var tagHelperContext = new TagHelperContext( contextAttributes, items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent(originalContent); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var output = new TagHelperOutput(originalTagName, originalAttributes) { SelfClosing = false, }; output.PreContent.SetContent(originalPreContent); output.Content.SetContent(originalContent); output.PostContent.SetContent(originalPostContent); var metadataProvider = new EmptyModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var tagHelper = new OptionTagHelper(htmlGenerator) { Value = value, }; // Act & Assert (does not throw) // Tag helper would throw an NRE if it used ViewContext or Generator values. await tagHelper.ProcessAsync(tagHelperContext, output); }
public static async Task <string> RenderAsync(this TagHelper tagHelper, TagHelperAttributeList attributeList, TagHelperContext context, HtmlEncoder htmlEncoder, string tagName = "div", TagMode tagMode = TagMode.SelfClosing) { var innerOutput = await tagHelper.ProcessAndGetOutputAsync(attributeList, context, tagName, tagMode); return(innerOutput.Render(htmlEncoder)); }
public async Task ProcessAsync_CallsGeneratorWithExpectedValues_ItemsAndAttribute( IEnumerable <SelectListItem> inputItems, string attributeName, string attributeValue, IEnumerable <SelectListItem> expectedItems) { // Arrange var contextAttributes = new TagHelperAttributeList { // Provided for completeness. Select tag helper does not confirm AllAttributes set is consistent. { attributeName, attributeValue }, }; var originalAttributes = new TagHelperAttributeList { { attributeName, attributeValue }, }; var propertyName = "Property1"; var expectedTagName = "select"; var tagHelperContext = new TagHelperContext( tagName: "select", allAttributes: contextAttributes, items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var metadataProvider = new EmptyModelMetadataProvider(); string model = null; var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(string), model); var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict); var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider); // Simulate a (model => model) scenario. E.g. the calling helper may appear in a low-level template. var modelExpression = new ModelExpression(string.Empty, modelExplorer); viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = propertyName; var currentValues = new string[0]; htmlGenerator .Setup(real => real.GetCurrentValues( viewContext, modelExplorer, string.Empty, // expression false)) // allowMultiple .Returns(currentValues) .Verifiable(); htmlGenerator .Setup(real => real.GenerateSelect( viewContext, modelExplorer, null, // optionLabel string.Empty, // expression expectedItems, currentValues, false, // allowMultiple null)) // htmlAttributes .Returns((TagBuilder)null) .Verifiable(); var tagHelper = new SelectTagHelper(htmlGenerator.Object) { For = modelExpression, Items = inputItems, ViewContext = viewContext, }; // Act tagHelper.Init(tagHelperContext); await tagHelper.ProcessAsync(tagHelperContext, output); // Assert htmlGenerator.Verify(); var keyValuePair = Assert.Single( tagHelperContext.Items, entry => (Type)entry.Key == typeof(SelectTagHelper)); var actualCurrentValues = Assert.IsType <CurrentValues>(keyValuePair.Value); Assert.Same(currentValues, actualCurrentValues.Values); }
public async Task TagHelper_CallsGeneratorWithExpectedValues_RealModelType( Type modelType, object model, bool allowMultiple) { // Arrange var contextAttributes = new TagHelperAttributeList( Enumerable.Empty <TagHelperAttribute>()); var originalAttributes = new TagHelperAttributeList(); var propertyName = "Property1"; var tagName = "select"; var tagHelperContext = new TagHelperContext( tagName: "select", allAttributes: contextAttributes, items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( tagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var metadataProvider = new EmptyModelMetadataProvider(); var modelExplorer = metadataProvider.GetModelExplorerForType(modelType, model); var modelExpression = new ModelExpression(propertyName, modelExplorer); var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict); var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider); var currentValues = new string[0]; htmlGenerator .Setup(real => real.GetCurrentValues( viewContext, modelExplorer, propertyName, // expression allowMultiple)) .Returns(currentValues) .Verifiable(); htmlGenerator .Setup(real => real.GenerateSelect( viewContext, modelExplorer, null, // optionLabel propertyName, // expression It.IsAny <IEnumerable <SelectListItem> >(), currentValues, allowMultiple, null)) // htmlAttributes .Returns((TagBuilder)null) .Verifiable(); var tagHelper = new SelectTagHelper(htmlGenerator.Object) { For = modelExpression, ViewContext = viewContext, }; // Act tagHelper.Init(tagHelperContext); await tagHelper.ProcessAsync(tagHelperContext, output); // Assert htmlGenerator.Verify(); var keyValuePair = Assert.Single( tagHelperContext.Items, entry => (Type)entry.Key == typeof(SelectTagHelper)); var actualCurrentValues = Assert.IsType <CurrentValues>(keyValuePair.Value); Assert.Same(currentValues, actualCurrentValues.Values); }
/// <summary> /// 获取结果 /// </summary> private string GetResult(TagHelperAttributeList contextAttributes = null, TagHelperAttributeList outputAttributes = null, TagHelperContent content = null) { return(Helper.GetResult(_output, _component, contextAttributes, outputAttributes, content)); }
private List <TagHelperAttribute> GetTabAttributesByPrefix(TagHelperAttributeList attributes, string prefix) { return(attributes.Where(a => a.Name.StartsWith(prefix)) .Select(a => new TagHelperAttribute(a.Name.Substring(prefix.Length), a.Value)).ToList()); }
public async Task ProcessAsync_CallsGenerateCheckBox_WithExpectedParameters() { // Arrange var originalContent = "original content"; var originalTagName = "not-input"; var expectedPreContent = "original pre-content"; var expectedContent = originalContent + "<input class=\"HtmlEncode[[form-control]]\" /><hidden />"; var expectedPostContent = "original post-content"; var context = new TagHelperContext( allAttributes: new TagHelperAttributeList( Enumerable.Empty <TagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var originalAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var output = new TagHelperOutput( originalTagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }) { TagMode = TagMode.SelfClosing, }; output.PreContent.AppendHtml(expectedPreContent); output.Content.AppendHtml(originalContent); output.PostContent.AppendHtml(expectedPostContent); var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict); var tagHelper = GetTagHelper(htmlGenerator.Object, model: false, propertyName: nameof(Model.IsACar)); var tagBuilder = new TagBuilder("input") { Attributes = { { "class", "form-control" }, }, TagRenderMode = TagRenderMode.SelfClosing }; htmlGenerator .Setup(mock => mock.GenerateCheckBox( tagHelper.ViewContext, tagHelper.For.ModelExplorer, tagHelper.For.Name, null, // isChecked It.IsAny <object>())) // htmlAttributes .Returns(tagBuilder) .Verifiable(); htmlGenerator .Setup(mock => mock.GenerateHiddenForCheckbox( tagHelper.ViewContext, tagHelper.For.ModelExplorer, tagHelper.For.Name)) .Returns(new TagBuilder("hidden") { TagRenderMode = TagRenderMode.SelfClosing }) .Verifiable(); // Act await tagHelper.ProcessAsync(context, output); // Assert htmlGenerator.Verify(); Assert.Empty(output.Attributes); // Moved to Content and cleared Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, HtmlContentUtilities.HtmlContentToString(output.Content)); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(TagMode.SelfClosing, output.TagMode); Assert.Null(output.TagName); // Cleared }
public void TagHelperExecutionContext_MaintainsAllAttributes() { // Arrange var executionContext = new TagHelperExecutionContext("p", TagMode.StartTagAndEndTag); var expectedAttributes = new TagHelperAttributeList { { "class", "btn" }, { "something", true }, { "foo", "bar" } }; // Act executionContext.AddHtmlAttribute("class", "btn"); executionContext.AddTagHelperAttribute("something", true); executionContext.AddHtmlAttribute("foo", "bar"); // Assert Assert.Equal( expectedAttributes, executionContext.AllAttributes, CaseSensitiveTagHelperAttributeComparer.Default); }
public async Task ProcessAsync_GeneratesExpectedOutput( object model, Type containerType, Func <object> modelAccessor, string propertyPath, TagHelperOutputContent tagHelperOutputContent) { // Arrange var expectedTagName = "not-label"; var expectedAttributes = new TagHelperAttributeList { { "class", "form-control" }, { "for", tagHelperOutputContent.ExpectedId } }; var metadataProvider = new TestModelMetadataProvider(); var containerMetadata = metadataProvider.GetMetadataForType(containerType); var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model); var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text"); var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor()); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var modelExpression = new ModelExpression(propertyPath, modelExplorer); var tagHelper = new LabelTagHelper(htmlGenerator) { For = modelExpression, }; var expectedPreContent = "original pre-content"; var expectedPostContent = "original post-content"; var tagHelperContext = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test", getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent(tagHelperOutputContent.OriginalChildContent); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var htmlAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var output = new TagHelperOutput(expectedTagName, htmlAttributes); output.PreContent.SetContent(expectedPreContent); output.PostContent.SetContent(expectedPostContent); // LabelTagHelper checks IsContentModified so we don't want to forcibly set it if // tagHelperOutputContent.OriginalContent is going to be null or empty. if (!string.IsNullOrEmpty(tagHelperOutputContent.OriginalContent)) { output.Content.SetContent(tagHelperOutputContent.OriginalContent); } var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); tagHelper.ViewContext = viewContext; // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal( tagHelperOutputContent.ExpectedContent, HtmlContentUtilities.HtmlContentToString(output.Content)); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); Assert.Equal(expectedTagName, output.TagName); }
private static int IndexOfFirstMatch(string name, TagHelperAttributeList attributes) { for (var i = 0; i < attributes.Count; i++) { if (string.Equals(name, attributes[i].Name, StringComparison.OrdinalIgnoreCase)) { return i; } } return -1; }
public async Task ProcessAsync_GeneratesExpectedOutput( string originalContent, string selected, string value, ICollection <string> currentValues, TagHelperOutput expectedTagHelperOutput) { // Arrange var originalAttributes = new TagHelperAttributeList { { "label", "my-label" }, }; if (selected != null) { originalAttributes.Add("selected", selected); } var contextAttributes = new TagHelperAttributeList(originalAttributes); if (value != null) { contextAttributes.Add("value", value); } var tagHelperContext = new TagHelperContext( tagName: "option", allAttributes: contextAttributes, items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagHelperOutput.TagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { // GetChildContentAsync should not be invoked since we are setting the content below. Assert.True(false); return(Task.FromResult <TagHelperContent>(null)); }) { TagMode = TagMode.StartTagAndEndTag }; output.Content.SetContent(originalContent); var metadataProvider = new EmptyModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); tagHelperContext.Items[typeof(SelectTagHelper)] = currentValues == null ? null : new CurrentValues(currentValues); var tagHelper = new OptionTagHelper(htmlGenerator) { Value = value, ViewContext = viewContext, }; // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(expectedTagHelperOutput.TagName, output.TagName); Assert.Equal(expectedTagHelperOutput.Content.GetContent(), output.Content.GetContent()); Assert.Equal(expectedTagHelperOutput.Attributes.Count, output.Attributes.Count); foreach (var attribute in output.Attributes) { Assert.Contains(attribute, expectedTagHelperOutput.Attributes); } }
private static TagHelperContext MakeTagHelperContext( TagHelperAttributeList attributes) { return new TagHelperContext( attributes, items: new Dictionary<object, object>(), uniqueId: Guid.NewGuid().ToString("N"), getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent(default(string)); return Task.FromResult<TagHelperContent>(tagHelperContent); }); }
public async Task ProcessAsync_DoesNotUseGenerator_IfSelectedNullOrNoSelectedValues( string originalContent, string selected, string value, ICollection <string> currentValues, TagHelperOutput _) { // Arrange var originalAttributes = new TagHelperAttributeList { { "label", "my-label" }, { "selected", selected }, }; var originalTagName = "not-option"; var contextAttributes = new TagHelperAttributeList { { "label", "my-label" }, { "selected", selected }, { "value", value }, }; var originalPreContent = "original pre-content"; var originalPostContent = "original post-content"; var tagHelperContext = new TagHelperContext( tagName: "option", allAttributes: contextAttributes, items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( originalTagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent(originalContent); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }) { TagMode = TagMode.StartTagAndEndTag, }; output.PreContent.SetContent(originalPreContent); output.Content.SetContent(originalContent); output.PostContent.SetContent(originalPostContent); var metadataProvider = new EmptyModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); tagHelperContext.Items[typeof(SelectTagHelper)] = currentValues == null ? null : new CurrentValues(currentValues); var tagHelper = new OptionTagHelper(htmlGenerator) { Value = value, ViewContext = viewContext, }; // Act & Assert (does not throw) // Tag helper would throw an NRE if it used Generator value. await tagHelper.ProcessAsync(tagHelperContext, output); }
public async Task ProcessAsync_GeneratesExpectedOutput( string originalContent, string selected, string value, IEnumerable<string> selectedValues, TagHelperOutput expectedTagHelperOutput) { // Arrange var originalAttributes = new TagHelperAttributeList { { "label", "my-label" }, }; if (selected != null) { originalAttributes.Add("selected", selected); } var contextAttributes = new TagHelperAttributeList(originalAttributes); if (value != null) { contextAttributes.Add("value", value); } var tagHelperContext = new TagHelperContext( contextAttributes, items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: () => { // GetChildContentAsync should not be invoked since we are setting the content below. Assert.True(false); return Task.FromResult<TagHelperContent>(null); }); var output = new TagHelperOutput(expectedTagHelperOutput.TagName, originalAttributes) { SelfClosing = false, }; output.Content.SetContent(originalContent); var metadataProvider = new EmptyModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); viewContext.FormContext.FormData[SelectTagHelper.SelectedValuesFormDataKey] = selectedValues; var tagHelper = new OptionTagHelper(htmlGenerator) { Value = value, ViewContext = viewContext, }; // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(expectedTagHelperOutput.TagName, output.TagName); Assert.Equal(expectedTagHelperOutput.Content.GetContent(), output.Content.GetContent()); Assert.Equal(expectedTagHelperOutput.Attributes.Count, output.Attributes.Count); foreach (var attribute in output.Attributes) { Assert.Contains(attribute, expectedTagHelperOutput.Attributes); } }
private TagHelperOutput MakeTagHelperOutput(string tagName, TagHelperAttributeList attributes = null) { attributes = attributes ?? new TagHelperAttributeList(); return(new TagHelperOutput(tagName, attributes)); }
private static TagHelperOutput GetTagHelperOutput( string tagName, TagHelperAttributeList attributes, string content) { var tagHelperOutput = new TagHelperOutput(tagName, attributes); tagHelperOutput.Content.SetContent(content); return tagHelperOutput; }
public async Task ProcessAsyncInTemplate_WithItems_GeneratesExpectedOutput_DoesNotChangeSelectList( object model, Type containerType, Func <object> modelAccessor, NameAndId nameAndId, string expectedOptions) { // Arrange var originalAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var originalPostContent = "original content"; var expectedAttributes = new TagHelperAttributeList(originalAttributes) { { "id", nameAndId.Id }, { "name", nameAndId.Name }, { "valid", "from validation attributes" }, }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var expectedPostContent = originalPostContent + expectedOptions; var expectedTagName = "select"; var metadataProvider = new TestModelMetadataProvider(); var containerMetadata = metadataProvider.GetMetadataForType(containerType); var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model); var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text"); var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor()); var modelExpression = new ModelExpression(name: string.Empty, modelExplorer: modelExplorer); var tagHelperContext = new TagHelperContext( tagName: "select", allAttributes: new TagHelperAttributeList( Enumerable.Empty <TagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.AppendHtml("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }) { TagMode = TagMode.SelfClosing, }; output.PreContent.AppendHtml(expectedPreContent); output.Content.AppendHtml(expectedContent); output.PostContent.AppendHtml(originalPostContent); var htmlGenerator = new TestableHtmlGenerator(metadataProvider) { ValidationAttributes = { { "valid", "from validation attributes" }, } }; var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = nameAndId.Name; var items = new SelectList(new[] { "", "outer text", "inner text", "other text" }); var savedDisabled = items.Select(item => item.Disabled).ToList(); var savedGroup = items.Select(item => item.Group).ToList(); var savedSelected = items.Select(item => item.Selected).ToList(); var savedText = items.Select(item => item.Text).ToList(); var savedValue = items.Select(item => item.Value).ToList(); var tagHelper = new SelectTagHelper(htmlGenerator) { For = modelExpression, Items = items, ViewContext = viewContext, }; // Act tagHelper.Init(tagHelperContext); await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(TagMode.SelfClosing, output.TagMode); Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedPostContent, HtmlContentUtilities.HtmlContentToString(output.PostContent)); Assert.Equal(expectedTagName, output.TagName); Assert.Single( tagHelperContext.Items, entry => (Type)entry.Key == typeof(SelectTagHelper)); Assert.Equal(savedDisabled, items.Select(item => item.Disabled)); Assert.Equal(savedGroup, items.Select(item => item.Group)); Assert.Equal(savedSelected, items.Select(item => item.Selected)); Assert.Equal(savedText, items.Select(item => item.Text)); Assert.Equal(savedValue, items.Select(item => item.Value)); }