This repository has been archived by the owner on Dec 14, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Added tests to validate ValidationMessageTagHelper functionality. #1250
- Loading branch information
1 parent
57d1c54
commit 2729cdc
Showing
2 changed files
with
266 additions
and
0 deletions.
There are no files selected for viewing
55 changes: 55 additions & 0 deletions
55
src/Microsoft.AspNet.Mvc.TagHelpers/ValidationMessageTagHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using Microsoft.AspNet.Mvc.Rendering; | ||
using Microsoft.AspNet.Razor.Runtime.TagHelpers; | ||
using Microsoft.AspNet.Razor.TagHelpers; | ||
|
||
namespace Microsoft.AspNet.Mvc.TagHelpers | ||
{ | ||
/// <summary> | ||
/// <see cref="ITagHelper"/> implementation targeting <span> elements with <c>validation-for</c> attributes. | ||
/// </summary> | ||
[TagName("span")] | ||
[ContentBehavior(ContentBehavior.Modify)] | ||
public class ValidationMessageTagHelper : TagHelper | ||
{ | ||
[Activate] | ||
private ViewContext ViewContext { get; set; } | ||
|
||
[Activate] | ||
private IHtmlGenerator Generator { get; set; } | ||
|
||
/// <summary> | ||
/// Name to be validated on the current model. | ||
/// </summary> | ||
[HtmlAttributeName("validation-for")] | ||
public ModelExpression For { get; set; } | ||
|
||
/// <inheritdoc /> | ||
public override void Process(TagHelperContext context, TagHelperOutput output) | ||
{ | ||
if (For != null) | ||
{ | ||
var tagBuilder = Generator.GenerateValidationMessage(ViewContext, | ||
For.Name, | ||
message: null, | ||
tag: null, | ||
htmlAttributes: null); | ||
|
||
if (tagBuilder != null) | ||
{ | ||
output.MergeAttributes(tagBuilder); | ||
|
||
// We check for whitespace to detect scenarios such as: | ||
// <span validation-for="Name"> | ||
// </span> | ||
if (string.IsNullOrWhiteSpace(output.Content)) | ||
{ | ||
output.Content = tagBuilder.InnerHtml; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
211 changes: 211 additions & 0 deletions
211
test/Microsoft.AspNet.Mvc.TagHelpers.Test/ValidationMessageTagHelperTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Reflection; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNet.Http; | ||
using Microsoft.AspNet.Mvc.ModelBinding; | ||
using Microsoft.AspNet.Mvc.Razor; | ||
using Microsoft.AspNet.Mvc.Rendering; | ||
using Microsoft.AspNet.Razor.Runtime.TagHelpers; | ||
using Microsoft.AspNet.Routing; | ||
using Moq; | ||
using Xunit; | ||
|
||
namespace Microsoft.AspNet.Mvc.TagHelpers | ||
{ | ||
public class ValidationMessageTagHelperTest | ||
{ | ||
[Fact] | ||
public async Task ProcessAsync_GeneratesExpectedOutput() | ||
{ | ||
// Arrange | ||
var metadataProvider = new DataAnnotationsModelMetadataProvider(); | ||
var modelExpression = CreateModelExpression("Name"); | ||
var validationMessageTagHelper = new ValidationMessageTagHelper | ||
{ | ||
For = modelExpression | ||
}; | ||
|
||
var tagHelperContext = new TagHelperContext( | ||
allAttributes: new Dictionary<string, object> | ||
{ | ||
{ "id", "myvalidationmessage" }, | ||
{ "for", modelExpression }, | ||
}); | ||
var output = new TagHelperOutput( | ||
"original tag name", | ||
attributes: new Dictionary<string, string> | ||
{ | ||
{ "id", "myvalidationmessage" } | ||
}, | ||
content: "Something"); | ||
var htmlGenerator = new TestableHtmlGenerator(metadataProvider); | ||
var viewContext = TestableHtmlGenerator.GetViewContext(model: null, | ||
htmlGenerator: htmlGenerator, | ||
metadataProvider: metadataProvider); | ||
|
||
var activator = new DefaultTagHelperActivator(); | ||
activator.Activate(validationMessageTagHelper, viewContext); | ||
|
||
// Act | ||
await validationMessageTagHelper.ProcessAsync(tagHelperContext, output); | ||
|
||
// Assert | ||
Assert.Equal(4, output.Attributes.Count); | ||
var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("id")); | ||
Assert.Equal("myvalidationmessage", attribute.Value); | ||
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("class")); | ||
Assert.Equal("field-validation-valid", attribute.Value); | ||
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-valmsg-for")); | ||
Assert.Equal("Name", attribute.Value); | ||
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-valmsg-replace")); | ||
Assert.Equal("true", attribute.Value); | ||
Assert.Equal("Something", output.Content); | ||
Assert.Equal("original tag name", output.TagName); | ||
} | ||
|
||
[Fact] | ||
public async Task ProcessAsync_CallsIntoGenerateValidationMessageWithExpectedParameters() | ||
{ | ||
// Arrange | ||
var validationMessageTagHelper = new ValidationMessageTagHelper | ||
{ | ||
For = CreateModelExpression("Hello") | ||
}; | ||
var output = new TagHelperOutput( | ||
"span", | ||
attributes: new Dictionary<string, string>(), | ||
content: "Content of validation message"); | ||
var expectedViewContext = CreateViewContext(); | ||
var generator = new Mock<IHtmlGenerator>(); | ||
generator | ||
.Setup(mock => | ||
mock.GenerateValidationMessage(expectedViewContext, "Hello", null, null, null)) | ||
.Returns(new TagBuilder("span")) | ||
.Verifiable(); | ||
|
||
SetViewContextAndGenerator(validationMessageTagHelper, expectedViewContext, generator.Object); | ||
|
||
// Act & Assert | ||
await validationMessageTagHelper.ProcessAsync(context: null, output: output); | ||
|
||
generator.Verify(); | ||
Assert.Equal("span", output.TagName); | ||
Assert.Empty(output.Attributes); | ||
Assert.Equal("Content of validation message", output.Content); | ||
} | ||
|
||
[Theory] | ||
[InlineData("Content of validation message", "Content of validation message")] | ||
[InlineData("\r\n \r\n", "New HTML")] | ||
public async Task ProcessAsync_MergesTagBuilderFromGenerateValidationMessage( | ||
string outputContent, string expectedOutputContent) | ||
{ | ||
// Arrange | ||
var validationMessageTagHelper = new ValidationMessageTagHelper | ||
{ | ||
For = CreateModelExpression("Hello") | ||
}; | ||
var output = new TagHelperOutput( | ||
"span", | ||
attributes: new Dictionary<string, string>(), | ||
content: outputContent); | ||
var tagBuilder = new TagBuilder("span2") | ||
{ | ||
InnerHtml = "New HTML" | ||
}; | ||
tagBuilder.Attributes.Add("data-foo", "bar"); | ||
tagBuilder.Attributes.Add("data-hello", "world"); | ||
|
||
var expectedViewContext = CreateViewContext(); | ||
var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); | ||
var setup = generator | ||
.Setup(mock => mock.GenerateValidationMessage( | ||
It.IsAny<ViewContext>(), | ||
It.IsAny<string>(), | ||
It.IsAny<string>(), | ||
It.IsAny<string>(), | ||
It.IsAny<object>())) | ||
.Returns(tagBuilder); | ||
|
||
SetViewContextAndGenerator(validationMessageTagHelper, expectedViewContext, generator.Object); | ||
|
||
// Act | ||
await validationMessageTagHelper.ProcessAsync(context: null, output: output); | ||
|
||
// Assert | ||
Assert.Equal(output.TagName, "span"); | ||
Assert.Equal(2, output.Attributes.Count); | ||
var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-foo")); | ||
Assert.Equal("bar", attribute.Value); | ||
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-hello")); | ||
Assert.Equal("world", attribute.Value); | ||
Assert.Equal(expectedOutputContent, output.Content); | ||
} | ||
|
||
[Fact] | ||
public async Task ProcessAsync_DoesNothingIfNullFor() | ||
{ | ||
// Arrange | ||
var validationMessageTagHelper = new ValidationMessageTagHelper(); | ||
var output = new TagHelperOutput( | ||
"span", | ||
attributes: new Dictionary<string, string>(), | ||
content: "Content of validation message"); | ||
var expectedViewContext = CreateViewContext(); | ||
var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); | ||
|
||
SetViewContextAndGenerator(validationMessageTagHelper, expectedViewContext, generator.Object); | ||
|
||
// Act | ||
await validationMessageTagHelper.ProcessAsync(context: null, output: output); | ||
|
||
// Assert | ||
Assert.Equal("span", output.TagName); | ||
Assert.Empty(output.Attributes); | ||
Assert.Equal("Content of validation message", output.Content); | ||
} | ||
|
||
private static ModelExpression CreateModelExpression(string name) | ||
{ | ||
return new ModelExpression( | ||
name, | ||
new ModelMetadata( | ||
new Mock<IModelMetadataProvider>().Object, | ||
containerType: null, | ||
modelAccessor: null, | ||
modelType: typeof(object), | ||
propertyName: string.Empty)); | ||
} | ||
|
||
private static ViewContext CreateViewContext() | ||
{ | ||
var actionContext = new ActionContext( | ||
new Mock<HttpContext>().Object, | ||
new RouteData(), | ||
new ActionDescriptor()); | ||
|
||
return new ViewContext( | ||
actionContext, | ||
Mock.Of<IView>(), | ||
new ViewDataDictionary( | ||
new DataAnnotationsModelMetadataProvider()), | ||
new StringWriter()); | ||
} | ||
|
||
private static void SetViewContextAndGenerator(ITagHelper tagHelper, | ||
ViewContext viewContext, | ||
IHtmlGenerator generator) | ||
{ | ||
var tagHelperType = tagHelper.GetType(); | ||
|
||
tagHelperType.GetProperty("ViewContext", BindingFlags.NonPublic | BindingFlags.Instance) | ||
.SetValue(tagHelper, viewContext); | ||
tagHelperType.GetProperty("Generator", BindingFlags.NonPublic | BindingFlags.Instance) | ||
.SetValue(tagHelper, generator); | ||
} | ||
} | ||
} |