public async Task ProcessAsync_ThrowsIfRouteAndActionOrControllerProvided(string propertyName) { // Arrange var formTagHelper = new FormTagHelper(new TestableHtmlGenerator(new EmptyModelMetadataProvider())) { Route = "Default", }; typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home"); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList(), getChildContentAsync: _ => Task.FromResult <TagHelperContent>(null)); var expectedErrorMessage = "Cannot determine an 'action' attribute for <form>. A <form> with a specified " + "'asp-route' must not have an 'asp-action' or 'asp-controller' attribute."; var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); // Act & Assert var ex = await Assert.ThrowsAsync <InvalidOperationException>( () => formTagHelper.ProcessAsync(context, output)); Assert.Equal(expectedErrorMessage, ex.Message); }
public async Task ProcessAsync_SupportsAntiForgeryIfActionIsSpecified( bool?antiForgery, string expectedContent) { // Arrange var viewContext = CreateViewContext(); var generator = new Mock <IHtmlGenerator>(); generator.Setup(mock => mock.GenerateAntiForgery(It.IsAny <ViewContext>())) .Returns(new TagBuilder("input")); var formTagHelper = new FormTagHelper { AntiForgery = antiForgery, Generator = generator.Object, ViewContext = viewContext, }; var output = new TagHelperOutput("form", attributes: new Dictionary <string, string> { { "aCTiON", "my-action" }, }, content: string.Empty); var context = new TagHelperContext(allAttributes: new Dictionary <string, object>()); // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); var attribute = Assert.Single(output.Attributes); Assert.Equal(new KeyValuePair <string, string>("aCTiON", "my-action"), attribute); Assert.Equal(expectedContent, output.Content); }
public async Task ProcessAsync_ThrowsIfActionConflictsWithBoundAttributes(string propertyName) { // Arrange var formTagHelper = new FormTagHelper { Method = "POST" }; var tagHelperOutput = new TagHelperOutput( "form", attributes: new Dictionary <string, string> { { "action", "my-action" }, }, content: string.Empty); if (propertyName == "asp-route-") { tagHelperOutput.Attributes.Add("asp-route-foo", "bar"); } else { typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home"); } var expectedErrorMessage = "Cannot override the 'action' attribute for <form>. A <form> with a specified " + "'action' must not have attributes starting with 'asp-route-' or an " + "'asp-action' or 'asp-controller' attribute."; // Act & Assert var ex = await Assert.ThrowsAsync <InvalidOperationException>( () => formTagHelper.ProcessAsync(context: null, output: tagHelperOutput)); Assert.Equal(expectedErrorMessage, ex.Message); }
public async Task ProcessAsync_RestoresBoundAttributesIfActionIsSpecified(string htmlAction) { // Arrange var formTagHelper = new FormTagHelper { Method = "POST" }; var output = new TagHelperOutput("form", attributes: new Dictionary <string, string> { { "aCTiON", htmlAction }, }, content: string.Empty); var context = new TagHelperContext( allAttributes: new Dictionary <string, object>() { { "METhod", "POST" } }); // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); Assert.Equal(2, output.Attributes.Count); var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("aCTiON")); Assert.Equal(htmlAction, attribute.Value); attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("METhod")); Assert.Equal("POST", attribute.Value); Assert.Empty(output.Content); }
public async Task ProcessAsync_CallsIntoGenerateFormWithExpectedParameters() { // Arrange var viewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new Dictionary <string, object>()); var output = new TagHelperOutput( "form", attributes: new Dictionary <string, string>(), content: string.Empty); var generator = new Mock <IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm(viewContext, "Index", "Home", null, "POST", null)) .Returns(new TagBuilder("form")) .Verifiable(); var formTagHelper = new FormTagHelper { Action = "Index", AntiForgery = false, Controller = "Home", Generator = generator.Object, Method = "POST", ViewContext = viewContext, }; // Act & Assert await formTagHelper.ProcessAsync(context, output); generator.Verify(); Assert.Equal("form", output.TagName); Assert.Empty(output.Attributes); Assert.Empty(output.Content); }
public async Task ProcessAsync_ThrowsIfActionConflictsWithBoundAttributes(string propertyName) { // Arrange var formTagHelper = new FormTagHelper(new TestableHtmlGenerator(new EmptyModelMetadataProvider())); var tagHelperOutput = new TagHelperOutput( "form", attributes: new TagHelperAttributeList { { "action", "my-action" }, }); if (propertyName == "asp-route-") { formTagHelper.RouteValues.Add("name", "value"); } else { typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home"); } var expectedErrorMessage = "Cannot override the 'action' attribute for <form>. A <form> with a specified " + "'action' must not have attributes starting with 'asp-route-' or an " + "'asp-action' or 'asp-controller' or 'asp-route' attribute."; // Act & Assert var ex = await Assert.ThrowsAsync <InvalidOperationException>( () => formTagHelper.ProcessAsync(context: null, output: tagHelperOutput)); Assert.Equal(expectedErrorMessage, ex.Message); }
public async Task ProcessAsync_CallsIntoGenerateRouteFormWithExpectedParameters() { // Arrange var viewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList(), getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var generator = new Mock <IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateRouteForm( viewContext, "Default", It.Is <Dictionary <string, object> >(m => string.Equals(m["name"], "value")), null, null)) .Returns(new TagBuilder("form")) .Verifiable(); var formTagHelper = new FormTagHelper(generator.Object) { Antiforgery = false, Route = "Default", ViewContext = viewContext, RouteValues = { { "name", "value" }, }, }; // Act & Assert await formTagHelper.ProcessAsync(context, output); generator.Verify(); Assert.Equal("form", output.TagName); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); Assert.Empty(output.Attributes); Assert.Empty(output.PreElement.GetContent()); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Empty(output.PostContent.GetContent()); Assert.Empty(output.PostElement.GetContent()); }
public async Task ProcessAsync_GeneratesAntiForgeryCorrectly( bool?antiForgery, string expectedPostContent) { // Arrange var viewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new Dictionary <string, object>(), items: new Dictionary <object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var output = new TagHelperOutput( "form", attributes: new Dictionary <string, object>()); var generator = new Mock <IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( It.IsAny <ViewContext>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <object>(), It.IsAny <string>(), It.IsAny <object>())) .Returns(new TagBuilder("form", new HtmlEncoder())); generator.Setup(mock => mock.GenerateAntiForgery(viewContext)) .Returns(new TagBuilder("input", new HtmlEncoder())); var formTagHelper = new FormTagHelper { Action = "Index", AntiForgery = antiForgery, Generator = generator.Object, ViewContext = viewContext, }; // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); Assert.False(output.SelfClosing); Assert.Empty(output.Attributes); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); }
public async Task ProcessAsync_GeneratesAntiforgeryCorrectly( bool?antiforgery, string expectedPostContent) { // Arrange var viewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList(), getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var generator = new Mock <IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( It.IsAny <ViewContext>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <object>(), It.IsAny <string>(), It.IsAny <object>())) .Returns(new TagBuilder("form")); generator.Setup(mock => mock.GenerateAntiforgery(viewContext)) .Returns(new HtmlString("<input />")); var formTagHelper = new FormTagHelper(generator.Object) { Action = "Index", Antiforgery = antiforgery, ViewContext = viewContext, }; // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); Assert.Empty(output.Attributes); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); }
public async Task ProcessAsync_CallsIntoGenerateFormWithExpectedParameters() { // Arrange var viewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList()); var generator = new Mock <IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( viewContext, "Index", "Home", It.IsAny <IDictionary <string, object> >(), null, null)) .Returns(new TagBuilder("form", new CommonTestEncoder())) .Verifiable(); var formTagHelper = new FormTagHelper(generator.Object) { Action = "Index", AntiForgery = false, Controller = "Home", ViewContext = viewContext, }; // Act & Assert await formTagHelper.ProcessAsync(context, output); generator.Verify(); Assert.Equal("form", output.TagName); Assert.False(output.SelfClosing); Assert.Empty(output.Attributes); Assert.Empty(output.PreElement.GetContent()); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Empty(output.PostContent.GetContent()); }
public async Task ProcessAsync_SupportsAntiforgeryIfActionIsSpecified( bool?antiforgery, string expectedPostContent) { // Arrange var viewContext = CreateViewContext(); var generator = new Mock <IHtmlGenerator>(); generator.Setup(mock => mock.GenerateAntiforgery(It.IsAny <ViewContext>())) .Returns(new HtmlString("<input />")); var formTagHelper = new FormTagHelper(generator.Object) { Antiforgery = antiforgery, ViewContext = viewContext, }; var output = new TagHelperOutput( tagName: "form", attributes: new TagHelperAttributeList { { "aCTiON", "my-action" }, }, getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); var attribute = Assert.Single(output.Attributes); Assert.Equal(new TagHelperAttribute("aCTiON", "my-action"), attribute); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); }
public async Task ProcessAsync_SupportsAntiForgeryIfActionIsSpecified( bool?antiForgery, string expectedPostContent) { // Arrange var viewContext = CreateViewContext(); var generator = new Mock <IHtmlGenerator>(); generator.Setup(mock => mock.GenerateAntiForgery(It.IsAny <ViewContext>())) .Returns(new TagBuilder("input", new HtmlEncoder())); var formTagHelper = new FormTagHelper { AntiForgery = antiForgery, Generator = generator.Object, ViewContext = viewContext, }; var output = new TagHelperOutput("form", attributes: new Dictionary <string, object> { { "aCTiON", "my-action" }, }); var context = new TagHelperContext( allAttributes: new Dictionary <string, object>(), items: new Dictionary <object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); Assert.False(output.SelfClosing); var attribute = Assert.Single(output.Attributes); Assert.Equal(new KeyValuePair <string, object>("aCTiON", "my-action"), attribute); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); }
public async Task ProcessAsync_ThrowsIfRouteAndActionOrControllerProvided(string propertyName) { // Arrange var formTagHelper = new FormTagHelper(new TestableHtmlGenerator(new EmptyModelMetadataProvider())) { Route = "Default", }; typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home"); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList()); var expectedErrorMessage = "Cannot determine an 'action' attribute for <form>. A <form> with a specified " + "'asp-route' must not have an 'asp-action' or 'asp-controller' attribute."; // Act & Assert var ex = await Assert.ThrowsAsync <InvalidOperationException>( () => formTagHelper.ProcessAsync(context: null, output: output)); Assert.Equal(expectedErrorMessage, ex.Message); }
public async Task ProcessAsync_GeneratesAntiForgeryCorrectly(bool?antiForgery, string expectedContent) { // Arrange var viewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new Dictionary <string, object>()); var output = new TagHelperOutput( "form", attributes: new Dictionary <string, string>(), content: string.Empty); var generator = new Mock <IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( It.IsAny <ViewContext>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <object>(), It.IsAny <string>(), It.IsAny <object>())) .Returns(new TagBuilder("form")); generator.Setup(mock => mock.GenerateAntiForgery(viewContext)) .Returns(new TagBuilder("input")); var formTagHelper = new FormTagHelper { Action = "Index", AntiForgery = antiForgery, Generator = generator.Object, ViewContext = viewContext, }; // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); Assert.Empty(output.Attributes); Assert.Equal(expectedContent, output.Content); }
public async Task ProcessAsync_ThrowsIfActionIsUrlWithSpecifiedController() { // Arrange var formTagHelper = new FormTagHelper { Action = "http://www.contoso.com", Controller = "Home", Method = "POST" }; var expectedErrorMessage = "Cannot determine an 'action' for <form>. A <form> with a URL-based 'action' " + "must not have attributes starting with 'route-' or a 'controller' attribute."; var tagHelperOutput = new TagHelperOutput( "form", attributes: new Dictionary <string, string>(), content: string.Empty); // Act & Assert var ex = await Assert.ThrowsAsync <InvalidOperationException>( () => formTagHelper.ProcessAsync(context: null, output: tagHelperOutput)); Assert.Equal(expectedErrorMessage, ex.Message); }
public async Task ProcessAsync_ThrowsIfActionConflictsWithBoundAttributes(string propertyName) { // Arrange var formTagHelper = new FormTagHelper(new TestableHtmlGenerator(new EmptyModelMetadataProvider())); var tagHelperOutput = new TagHelperOutput( "form", attributes: new TagHelperAttributeList { { "action", "my-action" }, }, getChildContentAsync: _ => Task.FromResult <TagHelperContent>(null)); if (propertyName == "asp-route-") { formTagHelper.RouteValues.Add("name", "value"); } else { typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home"); } var expectedErrorMessage = "Cannot override the 'action' attribute for <form>. A <form> with a specified " + "'action' must not have attributes starting with 'asp-route-' or an " + "'asp-action' or 'asp-controller' or 'asp-route' attribute."; var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); // Act & Assert var ex = await Assert.ThrowsAsync <InvalidOperationException>( () => formTagHelper.ProcessAsync(context, tagHelperOutput)); Assert.Equal(expectedErrorMessage, ex.Message); }
public async Task ProcessAsync_GeneratesExpectedOutput() { // Arrange var expectedTagName = "not-form"; var metadataProvider = new DataAnnotationsModelMetadataProvider(); var tagHelperContext = new TagHelperContext( allAttributes: new Dictionary <string, object> { { "id", "myform" }, { "asp-route-foo", "bar" }, { "asp-action", "index" }, { "asp-controller", "home" }, { "method", "post" }, { "asp-anti-forgery", true } }); var output = new TagHelperOutput( expectedTagName, attributes: new Dictionary <string, string> { { "id", "myform" }, { "asp-route-foo", "bar" }, }, content: "Something"); var urlHelper = new Mock <IUrlHelper>(); urlHelper .Setup(mock => mock.Action(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <object>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>())) .Returns("home/index"); var htmlGenerator = new TestableHtmlGenerator(metadataProvider, urlHelper.Object); var viewContext = TestableHtmlGenerator.GetViewContext(model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); var expectedContent = "Something" + htmlGenerator.GenerateAntiForgery(viewContext) .ToString(TagRenderMode.SelfClosing); var formTagHelper = new FormTagHelper { Action = "index", AntiForgery = true, Controller = "home", Generator = htmlGenerator, Method = "post", ViewContext = viewContext, }; // Act await formTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(3, output.Attributes.Count); var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("id")); Assert.Equal("myform", attribute.Value); attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("method")); Assert.Equal("post", attribute.Value); attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("action")); Assert.Equal("home/index", attribute.Value); Assert.Equal(expectedContent, output.Content); Assert.Equal(expectedTagName, output.TagName); }
public async Task ProcessAsync_GeneratesExpectedOutput() { // Arrange var expectedTagName = "not-form"; var metadataProvider = new TestModelMetadataProvider(); var tagHelperContext = new TagHelperContext( allAttributes: new TagHelperAttributeList { { "id", "myform" }, { "asp-route-name", "value" }, { "asp-action", "index" }, { "asp-controller", "home" }, { "method", "post" }, { "asp-antiforgery", true } }, items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "id", "myform" }, }, getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something Else"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); output.PostContent.SetContent("Something"); var urlHelper = new Mock <IUrlHelper>(); urlHelper .Setup(mock => mock.Action(It.IsAny <UrlActionContext>())).Returns("home/index"); var htmlGenerator = new TestableHtmlGenerator(metadataProvider, urlHelper.Object); var viewContext = TestableHtmlGenerator.GetViewContext(model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); var expectedPostContent = "Something" + HtmlContentUtilities.HtmlContentToString( htmlGenerator.GenerateAntiforgery(viewContext), new NullTestEncoder()); var formTagHelper = new FormTagHelper(htmlGenerator) { Action = "index", Antiforgery = true, Controller = "home", ViewContext = viewContext, RouteValues = { { "name", "value" }, }, }; // Act await formTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(3, output.Attributes.Count); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("id")); Assert.Equal("myform", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("method")); Assert.Equal("post", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("action")); Assert.Equal("home/index", attribute.Value); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public async Task ProcessAsync_BindsRouteValues() { // Arrange var testViewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var expectedAttribute = new TagHelperAttribute("asp-ROUTEE-NotRoute", "something"); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList(), getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); output.Attributes.Add(expectedAttribute); var generator = new Mock <IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( It.IsAny <ViewContext>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <object>(), It.IsAny <string>(), It.IsAny <object>())) .Callback <ViewContext, string, string, object, string, object>( (viewContext, actionName, controllerName, routeValues, method, htmlAttributes) => { // Fixes Roslyn bug with lambdas generator.ToString(); var routeValueDictionary = (Dictionary <string, object>)routeValues; Assert.Equal(2, routeValueDictionary.Count); var routeValue = Assert.Single(routeValueDictionary, attr => attr.Key.Equals("val")); Assert.Equal("hello", routeValue.Value); routeValue = Assert.Single(routeValueDictionary, attr => attr.Key.Equals("-Name")); Assert.Equal("Value", routeValue.Value); }) .Returns(new TagBuilder("form")) .Verifiable(); var formTagHelper = new FormTagHelper(generator.Object) { Action = "Index", Antiforgery = false, ViewContext = testViewContext, RouteValues = { { "val", "hello" }, { "-Name", "Value" }, }, }; // Act & Assert await formTagHelper.ProcessAsync(context, output); Assert.Equal("form", output.TagName); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); var attribute = Assert.Single(output.Attributes); Assert.Equal(expectedAttribute, attribute); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Empty(output.PostContent.GetContent()); generator.Verify(); }
public async Task ProcessAsync_ThrowsIfRouteAndActionOrControllerProvided(string propertyName) { // Arrange var formTagHelper = new FormTagHelper(new TestableHtmlGenerator(new EmptyModelMetadataProvider())) { Route = "Default", }; typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home"); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList()); var expectedErrorMessage = "Cannot determine an 'action' attribute for <form>. A <form> with a specified " + "'asp-route' must not have an 'asp-action' or 'asp-controller' attribute."; // Act & Assert var ex = await Assert.ThrowsAsync<InvalidOperationException>( () => formTagHelper.ProcessAsync(context: null, output: output)); Assert.Equal(expectedErrorMessage, ex.Message); }
public async Task ProcessAsync_GeneratesAntiForgeryCorrectly( bool? antiForgery, string expectedPostContent) { // Arrange var viewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new Dictionary<string, object>(), items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var output = new TagHelperOutput( "form", attributes: new Dictionary<string, object>()); var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( It.IsAny<ViewContext>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<object>(), It.IsAny<string>(), It.IsAny<object>())) .Returns(new TagBuilder("form", new HtmlEncoder())); generator.Setup(mock => mock.GenerateAntiForgery(viewContext)) .Returns(new TagBuilder("input", new HtmlEncoder())); var formTagHelper = new FormTagHelper { Action = "Index", AntiForgery = antiForgery, Generator = generator.Object, ViewContext = viewContext, }; // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); Assert.False(output.SelfClosing); Assert.Empty(output.Attributes); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); }
public async Task ProcessAsync_ThrowsIfActionConflictsWithBoundAttributes(string propertyName) { // Arrange var formTagHelper = new FormTagHelper(); var tagHelperOutput = new TagHelperOutput( "form", attributes: new Dictionary<string, object> { { "action", "my-action" }, }); if (propertyName == "asp-route-") { tagHelperOutput.Attributes.Add("asp-route-foo", "bar"); } else { typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home"); } var expectedErrorMessage = "Cannot override the 'action' attribute for <form>. A <form> with a specified " + "'action' must not have attributes starting with 'asp-route-' or an " + "'asp-action' or 'asp-controller' attribute."; // Act & Assert var ex = await Assert.ThrowsAsync<InvalidOperationException>( () => formTagHelper.ProcessAsync(context: null, output: tagHelperOutput)); Assert.Equal(expectedErrorMessage, ex.Message); }
public async Task ProcessAsync_ThrowsIfActionConflictsWithBoundAttributes(string propertyName) { // Arrange var formTagHelper = new FormTagHelper(new TestableHtmlGenerator(new EmptyModelMetadataProvider())); var tagHelperOutput = new TagHelperOutput( "form", attributes: new TagHelperAttributeList { { "action", "my-action" }, }, getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); if (propertyName == "asp-route-") { formTagHelper.RouteValues.Add("name", "value"); } else { typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home"); } var expectedErrorMessage = "Cannot override the 'action' attribute for <form>. A <form> with a specified " + "'action' must not have attributes starting with 'asp-route-' or an " + "'asp-action' or 'asp-controller' or 'asp-route' attribute."; var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>( Enumerable.Empty<IReadOnlyTagHelperAttribute>()), items: new Dictionary<object, object>(), uniqueId: "test"); // Act & Assert var ex = await Assert.ThrowsAsync<InvalidOperationException>( () => formTagHelper.ProcessAsync(context, tagHelperOutput)); Assert.Equal(expectedErrorMessage, ex.Message); }
public async Task ProcessAsync_CallsIntoGenerateRouteFormWithExpectedParameters() { // Arrange var viewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>( Enumerable.Empty<IReadOnlyTagHelperAttribute>()), items: new Dictionary<object, object>(), uniqueId: "test"); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList(), getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateRouteForm( viewContext, "Default", It.Is<Dictionary<string, object>>(m => string.Equals(m["name"], "value")), null, null)) .Returns(new TagBuilder("form")) .Verifiable(); var formTagHelper = new FormTagHelper(generator.Object) { Antiforgery = false, Route = "Default", ViewContext = viewContext, RouteValues = { { "name", "value" }, }, }; // Act & Assert await formTagHelper.ProcessAsync(context, output); generator.Verify(); Assert.Equal("form", output.TagName); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); Assert.Empty(output.Attributes); Assert.Empty(output.PreElement.GetContent()); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Empty(output.PostContent.GetContent()); Assert.Empty(output.PostElement.GetContent()); }
public async Task ProcessAsync_BindsRouteValues() { // Arrange var testViewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>( Enumerable.Empty<IReadOnlyTagHelperAttribute>()), items: new Dictionary<object, object>(), uniqueId: "test"); var expectedAttribute = new TagHelperAttribute("asp-ROUTEE-NotRoute", "something"); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList(), getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); output.Attributes.Add(expectedAttribute); var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( It.IsAny<ViewContext>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<object>(), It.IsAny<string>(), It.IsAny<object>())) .Callback<ViewContext, string, string, object, string, object>( (viewContext, actionName, controllerName, routeValues, method, htmlAttributes) => { // Fixes Roslyn bug with lambdas generator.ToString(); var routeValueDictionary = (Dictionary<string, object>)routeValues; Assert.Equal(2, routeValueDictionary.Count); var routeValue = Assert.Single(routeValueDictionary, attr => attr.Key.Equals("val")); Assert.Equal("hello", routeValue.Value); routeValue = Assert.Single(routeValueDictionary, attr => attr.Key.Equals("-Name")); Assert.Equal("Value", routeValue.Value); }) .Returns(new TagBuilder("form")) .Verifiable(); var formTagHelper = new FormTagHelper(generator.Object) { Action = "Index", Antiforgery = false, ViewContext = testViewContext, RouteValues = { { "val", "hello" }, { "-Name", "Value" }, }, }; // Act & Assert await formTagHelper.ProcessAsync(context, output); Assert.Equal("form", output.TagName); Assert.Equal(TagMode.StartTagAndEndTag ,output.TagMode); var attribute = Assert.Single(output.Attributes); Assert.Equal(expectedAttribute, attribute); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Empty(output.PostContent.GetContent()); generator.Verify(); }
public async Task ProcessAsync_BindsRouteValuesFromTagHelperOutput() { // Arrange var testViewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new Dictionary <string, object>(), items: new Dictionary <object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var expectedAttribute = new KeyValuePair <string, object>("asp-ROUTEE-NotRoute", "something"); var output = new TagHelperOutput( "form", attributes: new Dictionary <string, object>() { { "asp-route-val", "hello" }, { "asp-roUte--Foo", "bar" } }); output.Attributes.Add(expectedAttribute); var generator = new Mock <IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( It.IsAny <ViewContext>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <object>(), It.IsAny <string>(), It.IsAny <object>())) .Callback <ViewContext, string, string, object, string, object>( (viewContext, actionName, controllerName, routeValues, method, htmlAttributes) => { // Fixes Roslyn bug with lambdas generator.ToString(); var routeValueDictionary = (Dictionary <string, object>)routeValues; Assert.Equal(2, routeValueDictionary.Count); var routeValue = Assert.Single(routeValueDictionary, kvp => kvp.Key.Equals("val")); Assert.Equal("hello", routeValue.Value); routeValue = Assert.Single(routeValueDictionary, kvp => kvp.Key.Equals("-Foo")); Assert.Equal("bar", routeValue.Value); }) .Returns(new TagBuilder("form", new HtmlEncoder())) .Verifiable(); var formTagHelper = new FormTagHelper { Action = "Index", AntiForgery = false, Generator = generator.Object, ViewContext = testViewContext, }; // Act & Assert await formTagHelper.ProcessAsync(context, output); Assert.Equal("form", output.TagName); Assert.False(output.SelfClosing); var attribute = Assert.Single(output.Attributes); Assert.Equal(expectedAttribute, attribute); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Empty(output.PostContent.GetContent()); generator.Verify(); }
public async Task ProcessAsync_GeneratesAntiforgeryCorrectly( bool? antiforgery, string expectedPostContent) { // Arrange var viewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>( Enumerable.Empty<IReadOnlyTagHelperAttribute>()), items: new Dictionary<object, object>(), uniqueId: "test"); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList(), getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( It.IsAny<ViewContext>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<object>(), It.IsAny<string>(), It.IsAny<object>())) .Returns(new TagBuilder("form")); generator.Setup(mock => mock.GenerateAntiforgery(viewContext)) .Returns(new HtmlString("<input />")); var formTagHelper = new FormTagHelper(generator.Object) { Action = "Index", Antiforgery = antiforgery, ViewContext = viewContext, }; // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); Assert.Empty(output.Attributes); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); }
public async Task ProcessAsync_BindsRouteValuesFromTagHelperOutput() { // Arrange var testViewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new Dictionary<string, object>(), items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var expectedAttribute = new KeyValuePair<string, object>("asp-ROUTEE-NotRoute", "something"); var output = new TagHelperOutput( "form", attributes: new Dictionary<string, object>() { { "asp-route-val", "hello" }, { "asp-roUte--Foo", "bar" } }); output.Attributes.Add(expectedAttribute); var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( It.IsAny<ViewContext>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<object>(), It.IsAny<string>(), It.IsAny<object>())) .Callback<ViewContext, string, string, object, string, object>( (viewContext, actionName, controllerName, routeValues, method, htmlAttributes) => { // Fixes Roslyn bug with lambdas generator.ToString(); var routeValueDictionary = (Dictionary<string, object>)routeValues; Assert.Equal(2, routeValueDictionary.Count); var routeValue = Assert.Single(routeValueDictionary, kvp => kvp.Key.Equals("val")); Assert.Equal("hello", routeValue.Value); routeValue = Assert.Single(routeValueDictionary, kvp => kvp.Key.Equals("-Foo")); Assert.Equal("bar", routeValue.Value); }) .Returns(new TagBuilder("form", new HtmlEncoder())) .Verifiable(); var formTagHelper = new FormTagHelper { Action = "Index", AntiForgery = false, Generator = generator.Object, ViewContext = testViewContext, }; // Act & Assert await formTagHelper.ProcessAsync(context, output); Assert.Equal("form", output.TagName); Assert.False(output.SelfClosing); var attribute = Assert.Single(output.Attributes); Assert.Equal(expectedAttribute, attribute); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Empty(output.PostContent.GetContent()); generator.Verify(); }
public async Task ProcessAsync_GeneratesExpectedOutput() { // Arrange var expectedTagName = "not-form"; var metadataProvider = new TestModelMetadataProvider(); var tagHelperContext = new TagHelperContext( allAttributes: new TagHelperAttributeList { { "id", "myform" }, { "asp-route-name", "value" }, { "asp-action", "index" }, { "asp-controller", "home" }, { "method", "post" }, { "asp-antiforgery", true } }, items: new Dictionary<object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "id", "myform" }, }, getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something Else"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); output.PostContent.SetContent("Something"); var urlHelper = new Mock<IUrlHelper>(); urlHelper .Setup(mock => mock.Action(It.IsAny<UrlActionContext>())).Returns("home/index"); var htmlGenerator = new TestableHtmlGenerator(metadataProvider, urlHelper.Object); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); var expectedPostContent = "Something" + HtmlContentUtilities.HtmlContentToString( htmlGenerator.GenerateAntiforgery(viewContext), HtmlEncoder.Default); var formTagHelper = new FormTagHelper(htmlGenerator) { Action = "index", Antiforgery = true, Controller = "home", ViewContext = viewContext, RouteValues = { { "name", "value" }, }, }; // Act await formTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(3, output.Attributes.Count); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("id")); Assert.Equal("myform", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("method")); Assert.Equal("post", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("action")); Assert.Equal("home/index", attribute.Value); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public async Task ProcessAsync_CallsIntoGenerateFormWithExpectedParameters() { // Arrange var viewContext = CreateViewContext(); var context = new TagHelperContext( allAttributes: new Dictionary<string, object>(), items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var output = new TagHelperOutput( "form", attributes: new Dictionary<string, object>()); var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm(viewContext, "Index", "Home", null, null, null)) .Returns(new TagBuilder("form", new HtmlEncoder())) .Verifiable(); var formTagHelper = new FormTagHelper { Action = "Index", AntiForgery = false, Controller = "Home", Generator = generator.Object, ViewContext = viewContext, }; // Act & Assert await formTagHelper.ProcessAsync(context, output); generator.Verify(); Assert.Equal("form", output.TagName); Assert.False(output.SelfClosing); Assert.Empty(output.Attributes); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Empty(output.PostContent.GetContent()); }
public async Task ProcessAsync_SupportsAntiforgeryIfActionIsSpecified( bool? antiforgery, string expectedPostContent) { // Arrange var viewContext = CreateViewContext(); var generator = new Mock<IHtmlGenerator>(); generator.Setup(mock => mock.GenerateAntiforgery(It.IsAny<ViewContext>())) .Returns(new HtmlString("<input />")); var formTagHelper = new FormTagHelper(generator.Object) { Antiforgery = antiforgery, ViewContext = viewContext, }; var output = new TagHelperOutput( tagName: "form", attributes: new TagHelperAttributeList { { "aCTiON", "my-action" }, }, getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>( Enumerable.Empty<IReadOnlyTagHelperAttribute>()), items: new Dictionary<object, object>(), uniqueId: "test"); // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); var attribute = Assert.Single(output.Attributes); Assert.Equal(new TagHelperAttribute("aCTiON", "my-action"), attribute); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); }
public async Task ProcessAsync_SupportsAntiForgeryIfActionIsSpecified( bool? antiForgery, string expectedPostContent) { // Arrange var viewContext = CreateViewContext(); var generator = new Mock<IHtmlGenerator>(); generator.Setup(mock => mock.GenerateAntiForgery(It.IsAny<ViewContext>())) .Returns(new TagBuilder("input", new HtmlEncoder())); var formTagHelper = new FormTagHelper { AntiForgery = antiForgery, Generator = generator.Object, ViewContext = viewContext, }; var output = new TagHelperOutput("form", attributes: new Dictionary<string, object> { { "aCTiON", "my-action" }, }); var context = new TagHelperContext( allAttributes: new Dictionary<string, object>(), items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); // Act await formTagHelper.ProcessAsync(context, output); // Assert Assert.Equal("form", output.TagName); Assert.False(output.SelfClosing); var attribute = Assert.Single(output.Attributes); Assert.Equal(new KeyValuePair<string, object>("aCTiON", "my-action"), attribute); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.IsEmpty); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); }
public async Task ProcessAsync_ThrowsIfRouteAndActionOrControllerProvided(string propertyName) { // Arrange var formTagHelper = new FormTagHelper(new TestableHtmlGenerator(new EmptyModelMetadataProvider())) { Route = "Default", }; typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home"); var output = new TagHelperOutput( "form", attributes: new TagHelperAttributeList(), getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); var expectedErrorMessage = "Cannot determine an 'action' attribute for <form>. A <form> with a specified " + "'asp-route' must not have an 'asp-action' or 'asp-controller' attribute."; var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>( Enumerable.Empty<IReadOnlyTagHelperAttribute>()), items: new Dictionary<object, object>(), uniqueId: "test"); // Act & Assert var ex = await Assert.ThrowsAsync<InvalidOperationException>( () => formTagHelper.ProcessAsync(context, output)); Assert.Equal(expectedErrorMessage, ex.Message); }
public async Task ProcessAsync_BindsRouteValuesFromTagHelperOutput() { // Arrange var testViewContext = CreateViewContext(); var formTagHelper = new FormTagHelper { Action = "Index", AntiForgery = false }; var context = new TagHelperContext( allAttributes: new Dictionary <string, object>()); var expectedAttribute = new KeyValuePair <string, string>("ROUTEE-NotRoute", "something"); var output = new TagHelperOutput( "form", attributes: new Dictionary <string, string>() { { "route-val", "hello" }, { "roUte--Foo", "bar" } }, content: string.Empty); output.Attributes.Add(expectedAttribute); var generator = new Mock <IHtmlGenerator>(MockBehavior.Strict); generator .Setup(mock => mock.GenerateForm( It.IsAny <ViewContext>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <object>(), It.IsAny <string>(), It.IsAny <object>())) .Callback <ViewContext, string, string, object, string, object>( (viewContext, actionName, controllerName, routeValues, method, htmlAttributes) => { // Fixes Roslyn bug with lambdas generator.ToString(); var routeValueDictionary = (Dictionary <string, object>)routeValues; Assert.Equal(2, routeValueDictionary.Count); var routeValue = Assert.Single(routeValueDictionary, kvp => kvp.Key.Equals("val")); Assert.Equal("hello", routeValue.Value); routeValue = Assert.Single(routeValueDictionary, kvp => kvp.Key.Equals("-Foo")); Assert.Equal("bar", routeValue.Value); }) .Returns(new TagBuilder("form")) .Verifiable(); formTagHelper.ViewContext = testViewContext; formTagHelper.Generator = generator.Object; // Act & Assert await formTagHelper.ProcessAsync(context, output); Assert.Equal("form", output.TagName); var attribute = Assert.Single(output.Attributes); Assert.Equal(expectedAttribute, attribute); Assert.Empty(output.Content); generator.Verify(); }