Add tests of `TextAreaTagHelper`
- new Microsoft.AspNet.Mvc.TagHelpers.Test project - bit of test infrastructure -- `TestableHtmlGenerator` - short-curcuits validation attribute and AntiForgery additions - should help when testing all MVC tag helpers
This commit is contained in:
parent
a9c2c4c5eb
commit
ba8b3d14a4
15
Mvc.sln
15
Mvc.sln
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.22115.0
|
||||
VisualStudioVersion = 14.0.22209.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
||||
EndProject
|
||||
|
|
@ -102,6 +102,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TagHelperSample.Web", "samp
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TagHelpers", "src\Microsoft.AspNet.Mvc.TagHelpers\Microsoft.AspNet.Mvc.TagHelpers.kproj", "{B2347320-308E-4D2B-AEC8-005DFA68B0C9}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TagHelpers.Test", "test\Microsoft.AspNet.Mvc.TagHelpers.Test\Microsoft.AspNet.Mvc.TagHelpers.Test.kproj", "{860119ED-3DB1-424D-8D0A-30132A8A7D96}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -542,6 +544,16 @@ Global
|
|||
{B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -591,5 +603,6 @@ Global
|
|||
{5DE8E4D9-AACD-4B5F-819F-F091383FB996} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{2223120F-D675-40DA-8CD8-11DC14A0B2C7} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
|
||||
{B2347320-308E-4D2B-AEC8-005DFA68B0C9} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>860119ed-3db1-424d-8d0a-30132a8a7d96</ProjectGuid>
|
||||
<RootNamespace>Microsoft.AspNet.Mvc.TagHelpers.Test</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Security.DataProtection;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||
{
|
||||
public class TestableHtmlGenerator : DefaultHtmlGenerator
|
||||
{
|
||||
private IDictionary<string, object> _validationAttributes;
|
||||
|
||||
public TestableHtmlGenerator(IModelMetadataProvider metadataProvider)
|
||||
: this(metadataProvider, Mock.Of<IUrlHelper>())
|
||||
{
|
||||
}
|
||||
|
||||
public TestableHtmlGenerator(IModelMetadataProvider metadataProvider, IUrlHelper urlHelper)
|
||||
: this(
|
||||
metadataProvider,
|
||||
urlHelper,
|
||||
validationAttributes: new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
}
|
||||
|
||||
public TestableHtmlGenerator(
|
||||
IModelMetadataProvider metadataProvider,
|
||||
IUrlHelper urlHelper,
|
||||
IDictionary<string, object> validationAttributes)
|
||||
: base(Mock.Of<IActionBindingContextProvider>(), GetAntiForgery(), metadataProvider, urlHelper)
|
||||
{
|
||||
_validationAttributes = validationAttributes;
|
||||
}
|
||||
|
||||
public IDictionary<string, object> ValidationAttributes
|
||||
{
|
||||
get { return _validationAttributes; }
|
||||
}
|
||||
|
||||
public static ViewContext GetViewContext(
|
||||
object model,
|
||||
IHtmlGenerator htmlGenerator,
|
||||
IModelMetadataProvider metadataProvider)
|
||||
{
|
||||
var serviceProvider = new Mock<IServiceProvider>();
|
||||
serviceProvider
|
||||
.Setup(provider => provider.GetService(typeof(IHtmlGenerator)))
|
||||
.Returns(htmlGenerator);
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext
|
||||
.Setup(context => context.RequestServices)
|
||||
.Returns(serviceProvider.Object);
|
||||
|
||||
var actionContext = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
||||
var viewData = new ViewDataDictionary(metadataProvider)
|
||||
{
|
||||
Model = model,
|
||||
};
|
||||
var viewContext = new ViewContext(actionContext, Mock.Of<IView>(), viewData, new StringWriter());
|
||||
|
||||
return viewContext;
|
||||
}
|
||||
|
||||
public override TagBuilder GenerateAntiForgery(ViewContext viewContext)
|
||||
{
|
||||
return new TagBuilder("input")
|
||||
{
|
||||
Attributes =
|
||||
{
|
||||
{ "name", "__RequestVerificationToken" },
|
||||
{ "type", "hidden" },
|
||||
{ "value", "olJlUDjrouRNWLen4tQJhauj1Z1rrvnb3QD65cmQU1Ykqi6S4" }, // 50 chars of a token.
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override IDictionary<string, object> GetValidationAttributes(
|
||||
ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
string name)
|
||||
{
|
||||
return ValidationAttributes;
|
||||
}
|
||||
|
||||
private static AntiForgery GetAntiForgery()
|
||||
{
|
||||
// AntiForgery must be passed to TestableHtmlGenerator constructor but will never be called.
|
||||
var optionsAccessor = new Mock<IOptionsAccessor<MvcOptions>>();
|
||||
optionsAccessor
|
||||
.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
var antiForgery = new AntiForgery(
|
||||
Mock.Of<IClaimUidExtractor>(),
|
||||
Mock.Of<IDataProtectionProvider>(),
|
||||
Mock.Of<IAntiForgeryAdditionalDataProvider>(),
|
||||
optionsAccessor.Object);
|
||||
|
||||
return antiForgery;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Razor;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||
{
|
||||
public class TextAreaTagHelperTest
|
||||
{
|
||||
// Model (List<Model> or Model instance), container type (Model or NestModel), model accessor,
|
||||
// property path, expected content.
|
||||
public static TheoryData<object, Type, Func<object>, string, string> TestDataSet
|
||||
{
|
||||
get
|
||||
{
|
||||
var modelWithNull = new Model
|
||||
{
|
||||
NestedModel = new NestedModel
|
||||
{
|
||||
Text = null,
|
||||
},
|
||||
Text = null,
|
||||
};
|
||||
var modelWithText = new Model
|
||||
{
|
||||
NestedModel = new NestedModel
|
||||
{
|
||||
Text = "inner text",
|
||||
},
|
||||
Text = "outer text",
|
||||
};
|
||||
var models = new List<Model>
|
||||
{
|
||||
modelWithNull,
|
||||
modelWithText,
|
||||
};
|
||||
|
||||
return new TheoryData<object, Type, Func<object>, string, string>
|
||||
{
|
||||
{ null, typeof(Model), () => null, "Text",
|
||||
Environment.NewLine },
|
||||
|
||||
{ modelWithNull, typeof(Model), () => modelWithNull.Text, "Text",
|
||||
Environment.NewLine },
|
||||
{ modelWithText, typeof(Model), () => modelWithText.Text, "Text",
|
||||
Environment.NewLine + "outer text" },
|
||||
|
||||
{ modelWithNull, typeof(NestedModel), () => modelWithNull.NestedModel.Text, "NestedModel.Text",
|
||||
Environment.NewLine },
|
||||
{ modelWithText, typeof(NestedModel), () => modelWithText.NestedModel.Text, "NestedModel.Text",
|
||||
Environment.NewLine + "inner text" },
|
||||
|
||||
// Top-level indexing does not work end-to-end due to code generation issue #1345.
|
||||
// TODO: Remove above comment when #1345 is fixed.
|
||||
{ models, typeof(Model), () => models[0].Text, "[0].Text",
|
||||
Environment.NewLine },
|
||||
{ models, typeof(Model), () => models[1].Text, "[1].Text",
|
||||
Environment.NewLine + "outer text" },
|
||||
|
||||
{ models, typeof(NestedModel), () => models[0].NestedModel.Text, "[0].NestedModel.Text",
|
||||
Environment.NewLine },
|
||||
{ models, typeof(NestedModel), () => models[1].NestedModel.Text, "[1].NestedModel.Text",
|
||||
Environment.NewLine + "inner text" },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestDataSet))]
|
||||
public async Task Process_GeneratesExpectedOutput(
|
||||
object model,
|
||||
Type containerType,
|
||||
Func<object> modelAccessor,
|
||||
string propertyPath,
|
||||
string expectedContent)
|
||||
{
|
||||
// Arrange
|
||||
var expectedAttributes = new Dictionary<string, string>
|
||||
{
|
||||
{ "class", "form-control" },
|
||||
{ "id", propertyPath },
|
||||
{ "name", propertyPath },
|
||||
{ "valid", "from validation attributes" },
|
||||
};
|
||||
var expectedTagName = "textarea";
|
||||
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
|
||||
// Property name is either nameof(Model.Text) or nameof(NestedModel.Text).
|
||||
var metadata = metadataProvider.GetMetadataForProperty(modelAccessor, containerType, propertyName: "Text");
|
||||
var modelExpression = new ModelExpression(propertyPath, metadata);
|
||||
var tagHelper = new TextAreaTagHelper
|
||||
{
|
||||
For = modelExpression,
|
||||
};
|
||||
|
||||
var tagHelperContext = new TagHelperContext(new Dictionary<string, object>());
|
||||
var htmlAttributes = new Dictionary<string, string>
|
||||
{
|
||||
{ "class", "form-control" },
|
||||
};
|
||||
var output = new TagHelperOutput("original tag name", htmlAttributes, "original content")
|
||||
{
|
||||
SelfClosing = true,
|
||||
};
|
||||
|
||||
var htmlGenerator = new TestableHtmlGenerator(metadataProvider)
|
||||
{
|
||||
ValidationAttributes =
|
||||
{
|
||||
{ "valid", "from validation attributes" },
|
||||
}
|
||||
};
|
||||
var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
|
||||
var activator = new DefaultTagHelperActivator();
|
||||
activator.Activate(tagHelper, viewContext);
|
||||
|
||||
// Act
|
||||
await tagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedAttributes, output.Attributes);
|
||||
Assert.Equal(expectedContent, output.Content);
|
||||
Assert.False(output.SelfClosing);
|
||||
Assert.Equal(expectedTagName, output.TagName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TagHelper_LeavesOutputUnchanged_IfForNotBound()
|
||||
{
|
||||
// Arrange
|
||||
var expectedAttributes = new Dictionary<string, string>
|
||||
{
|
||||
{ "class", "form-control" },
|
||||
};
|
||||
var expectedContent = "original content";
|
||||
var expectedTagName = "original tag name";
|
||||
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = metadataProvider.GetMetadataForProperty(
|
||||
modelAccessor: () => null,
|
||||
containerType: typeof(Model),
|
||||
propertyName: nameof(Model.Text));
|
||||
var modelExpression = new ModelExpression(nameof(Model.Text), metadata);
|
||||
var tagHelper = new TextAreaTagHelper();
|
||||
|
||||
var tagHelperContext = new TagHelperContext(new Dictionary<string, object>());
|
||||
var output = new TagHelperOutput(expectedTagName, expectedAttributes, expectedContent)
|
||||
{
|
||||
SelfClosing = true,
|
||||
};
|
||||
|
||||
var htmlGenerator = new TestableHtmlGenerator(metadataProvider)
|
||||
{
|
||||
ValidationAttributes =
|
||||
{
|
||||
{ "valid", "from validation attributes" },
|
||||
}
|
||||
};
|
||||
Model model = null;
|
||||
var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
|
||||
var activator = new DefaultTagHelperActivator();
|
||||
activator.Activate(tagHelper, viewContext);
|
||||
|
||||
// Act
|
||||
await tagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedAttributes, output.Attributes);
|
||||
Assert.Equal(expectedContent, output.Content);
|
||||
Assert.True(output.SelfClosing);
|
||||
Assert.Equal(expectedTagName, output.TagName);
|
||||
}
|
||||
|
||||
private class Model
|
||||
{
|
||||
public string Text { get; set; }
|
||||
|
||||
public NestedModel NestedModel { get; set; }
|
||||
}
|
||||
|
||||
private class NestedModel
|
||||
{
|
||||
public string Text { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"commands": {
|
||||
"test": "Xunit.KRunner"
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-*",
|
||||
"Microsoft.AspNet.Testing": "1.0.0-*",
|
||||
"Xunit.KRunner": "1.0.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"aspnet50": {
|
||||
"dependencies": {
|
||||
"Moq": "4.2.1312.1622"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue