@@ -23,10 +23,149 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
2323{
2424public class ValidationSummaryTagHelperTest
2525{
26+ public static TheoryData < ModelStateDictionary > ProcessAsync_GeneratesExpectedOutput_WithNoErrorsData
27+ {
28+ get
29+ {
30+ var emptyModelState = new ModelStateDictionary ( ) ;
31+
32+ var modelState = new ModelStateDictionary ( ) ;
33+ SetValidModelState ( modelState ) ;
34+
35+ return new TheoryData < ModelStateDictionary >
36+ {
37+ emptyModelState ,
38+ modelState ,
39+ } ;
40+ }
41+ }
42+
43+ [ Theory ]
44+ [ MemberData ( nameof ( ProcessAsync_GeneratesExpectedOutput_WithNoErrorsData ) ) ]
45+ public async Task ProcessAsync_GeneratesExpectedOutput_WithNoErrors (
46+ ModelStateDictionary modelState )
47+ {
48+ // Arrange
49+ var expectedTagName = "not-div" ;
50+ var metadataProvider = new TestModelMetadataProvider ( ) ;
51+ var htmlGenerator = new TestableHtmlGenerator ( metadataProvider ) ;
52+
53+ var expectedPreContent = "original pre-content" ;
54+ var expectedContent = "original content" ;
55+ var tagHelperContext = new TagHelperContext (
56+ allAttributes : new TagHelperAttributeList (
57+ Enumerable . Empty < TagHelperAttribute > ( ) ) ,
58+ items : new Dictionary < object , object > ( ) ,
59+ uniqueId : "test" ) ;
60+ var output = new TagHelperOutput (
61+ expectedTagName ,
62+ attributes : new TagHelperAttributeList
63+ {
64+ { "class" , "form-control" }
65+ } ,
66+ getChildContentAsync : ( useCachedResult , encoder ) =>
67+ {
68+ var tagHelperContent = new DefaultTagHelperContent ( ) ;
69+ tagHelperContent . SetContent ( "Something" ) ;
70+ return Task . FromResult < TagHelperContent > ( tagHelperContent ) ;
71+ } ) ;
72+ output . PreContent . SetContent ( expectedPreContent ) ;
73+ output . Content . SetContent ( expectedContent ) ;
74+ output . PostContent . SetContent ( "Custom Content" ) ;
75+
76+ var model = new Model ( ) ;
77+ var viewContext = TestableHtmlGenerator . GetViewContext ( model , htmlGenerator , metadataProvider , modelState ) ;
78+ var validationSummaryTagHelper = new ValidationSummaryTagHelper ( htmlGenerator )
79+ {
80+ ValidationSummary = ValidationSummary . All ,
81+ ViewContext = viewContext ,
82+ } ;
83+
84+ // Act
85+ await validationSummaryTagHelper . ProcessAsync ( tagHelperContext , output ) ;
86+
87+ // Assert
88+ Assert . Equal ( 2 , output . Attributes . Count ) ;
89+ var attribute = Assert . Single ( output . Attributes , attr=> attr . Name . Equals ( "class" ) ) ;
90+ Assert . Equal ( "form-control validation-summary-valid" , attribute . Value ) ;
91+ attribute = Assert . Single ( output . Attributes , attr=> attr . Name . Equals ( "data-valmsg-summary" ) ) ;
92+ Assert . Equal ( "true" , attribute . Value ) ;
93+ Assert . Equal ( expectedPreContent , output . PreContent . GetContent ( ) ) ;
94+ Assert . Equal ( expectedContent , output . Content . GetContent ( ) ) ;
95+ Assert . Equal (
96+ $ "Custom Content<ul><li style=\" display:none\" ></li>{ Environment . NewLine } </ul>",
97+ output . PostContent . GetContent ( ) ) ;
98+ Assert . Equal ( expectedTagName , output . TagName ) ;
99+ }
100+
101+ [ Theory ]
102+ [ InlineData ( ValidationSummary . All ) ]
103+ [ InlineData ( ValidationSummary . ModelOnly ) ]
104+ public async Task ProcessAsync_GeneratesExpectedOutput_WithModelError ( ValidationSummary validationSummary )
105+ {
106+ // Arrange
107+ var expectedError = "I am an error." ;
108+ var expectedTagName = "not-div" ;
109+ var metadataProvider = new TestModelMetadataProvider ( ) ;
110+ var htmlGenerator = new TestableHtmlGenerator ( metadataProvider ) ;
111+
112+ var validationSummaryTagHelper = new ValidationSummaryTagHelper ( htmlGenerator )
113+ {
114+ ValidationSummary = validationSummary ,
115+ } ;
116+
117+ var expectedPreContent = "original pre-content" ;
118+ var expectedContent = "original content" ;
119+ var tagHelperContext = new TagHelperContext (
120+ allAttributes : new TagHelperAttributeList (
121+ Enumerable . Empty < TagHelperAttribute > ( ) ) ,
122+ items : new Dictionary < object , object > ( ) ,
123+ uniqueId : "test" ) ;
124+ var output = new TagHelperOutput (
125+ expectedTagName ,
126+ attributes : new TagHelperAttributeList
127+ {
128+ { "class" , "form-control" }
129+ } ,
130+ getChildContentAsync : ( useCachedResult , encoder ) =>
131+ {
132+ var tagHelperContent = new DefaultTagHelperContent ( ) ;
133+ tagHelperContent . SetContent ( "Something" ) ;
134+ return Task . FromResult < TagHelperContent > ( tagHelperContent ) ;
135+ } ) ;
136+ output . PreContent . SetContent ( expectedPreContent ) ;
137+ output . Content . SetContent ( expectedContent ) ;
138+ output . PostContent . SetContent ( "Custom Content" ) ;
139+
140+ var model = new Model ( ) ;
141+ var viewContext = TestableHtmlGenerator . GetViewContext ( model , htmlGenerator , metadataProvider ) ;
142+ validationSummaryTagHelper . ViewContext = viewContext ;
143+
144+ var modelState = viewContext . ModelState ;
145+ SetValidModelState ( modelState ) ;
146+ modelState . AddModelError ( string . Empty , expectedError ) ;
147+
148+ // Act
149+ await validationSummaryTagHelper . ProcessAsync ( tagHelperContext , output ) ;
150+
151+ // Assert
152+ Assert . InRange ( output . Attributes . Count , low : 1 , high : 2 ) ;
153+ var attribute = Assert . Single ( output . Attributes , attr=> attr . Name . Equals ( "class" ) ) ;
154+ Assert . Equal ( "form-control validation-summary-errors" , attribute . Value ) ;
155+ Assert . Equal ( expectedPreContent , output . PreContent . GetContent ( ) ) ;
156+ Assert . Equal ( expectedContent , output . Content . GetContent ( ) ) ;
157+ Assert . Equal (
158+ $ "Custom Content<ul><li>{ expectedError } </li>{ Environment . NewLine } </ul>",
159+ output . PostContent . GetContent ( ) ) ;
160+ Assert . Equal ( expectedTagName , output . TagName ) ;
161+ }
162+
26163[ Fact ]
27- public async Task ProcessAsync_GeneratesExpectedOutput ( )
164+ public async Task ProcessAsync_GeneratesExpectedOutput_WithPropertyErrors ( )
28165{
29166// Arrange
167+ var expectedError0 = "I am an error." ;
168+ var expectedError2 = "I am also an error." ;
30169var expectedTagName = "not-div" ;
31170var metadataProvider = new TestModelMetadataProvider ( ) ;
32171var htmlGenerator = new TestableHtmlGenerator ( metadataProvider ) ;
@@ -59,23 +198,30 @@ public async Task ProcessAsync_GeneratesExpectedOutput()
59198output . Content . SetContent ( expectedContent ) ;
60199output . PostContent . SetContent ( "Custom Content" ) ;
61200
62- Model model = null ;
201+ var model = new Model ( ) ;
63202var viewContext = TestableHtmlGenerator . GetViewContext ( model , htmlGenerator , metadataProvider ) ;
64203validationSummaryTagHelper . ViewContext = viewContext ;
65204
205+ var modelState = viewContext . ModelState ;
206+ SetValidModelState ( modelState ) ;
207+ modelState . AddModelError ( key : $ "{ nameof ( Model . Strings ) } [0]", errorMessage : expectedError0 ) ;
208+ modelState . AddModelError ( key : $ "{ nameof ( Model . Strings ) } [2]", errorMessage : expectedError2 ) ;
209+
66210// Act
67211await validationSummaryTagHelper . ProcessAsync ( tagHelperContext , output ) ;
68212
69213// Assert
70214Assert . Equal ( 2 , output . Attributes . Count ) ;
71215var attribute = Assert . Single ( output . Attributes , attr=> attr . Name . Equals ( "class" ) ) ;
72- Assert . Equal ( "form-control validation-summary-valid " , attribute . Value ) ;
216+ Assert . Equal ( "form-control validation-summary-errors " , attribute . Value ) ;
73217attribute = Assert . Single ( output . Attributes , attr=> attr . Name . Equals ( "data-valmsg-summary" ) ) ;
74218Assert . Equal ( "true" , attribute . Value ) ;
75219Assert . Equal ( expectedPreContent , output . PreContent . GetContent ( ) ) ;
76220Assert . Equal ( expectedContent , output . Content . GetContent ( ) ) ;
77- Assert . Equal ( "Custom Content<ul><li style=\" display:none\" ></li>" + Environment . NewLine + "</ul>" ,
78- output . PostContent . GetContent ( ) ) ;
221+ Assert . Equal (
222+ $ "Custom Content<ul><li>{ expectedError0 } </li>{ Environment . NewLine } "+
223+ $ "<li>{ expectedError2 } </li>{ Environment . NewLine } </ul>",
224+ output . PostContent . GetContent ( ) ) ;
79225Assert . Equal ( expectedTagName , output . TagName ) ;
80226}
81227
@@ -339,9 +485,29 @@ private static ViewContext CreateViewContext()
339485new HtmlHelperOptions ( ) ) ;
340486}
341487
488+ private static void SetValidModelState ( ModelStateDictionary modelState )
489+ {
490+ modelState . SetModelValue ( key : nameof ( Model . Empty ) , rawValue : null , attemptedValue : null ) ;
491+ modelState . SetModelValue ( key : $ "{ nameof ( Model . Strings ) } [0]", rawValue : null , attemptedValue : null ) ;
492+ modelState . SetModelValue ( key : $ "{ nameof ( Model . Strings ) } [1]", rawValue : null , attemptedValue : null ) ;
493+ modelState . SetModelValue ( key : $ "{ nameof ( Model . Strings ) } [2]", rawValue : null , attemptedValue : null ) ;
494+ modelState . SetModelValue ( key : nameof ( Model . Text ) , rawValue : null , attemptedValue : null ) ;
495+
496+ foreach ( var key in modelState . Keys )
497+ {
498+ modelState . MarkFieldValid ( key ) ;
499+ }
500+ }
501+
342502private class Model
343503{
344504public string Text { get ; set ; }
505+
506+ public string [ ] Strings { get ; set ; }
507+
508+ // Exists to ensure #4989 does not regress. Issue specific to case where collection has a ModelStateEntry
509+ // but no element does.
510+ public byte [ ] Empty { get ; set ; }
345511}
346512}
347513}