Skip to content

Commit

Permalink
Merge pull request #133 from MRCollective/html-helper-for-method
Browse files Browse the repository at this point in the history
Ability to change the context of a form model
  • Loading branch information
robdmoore committed Jan 18, 2016
2 parents 27fe2a5 + 725ee92 commit e902b27
Show file tree
Hide file tree
Showing 29 changed files with 1,028 additions and 61 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ _ReSharper.*
~$*
*~
*.log
packages
packages
*.received.*
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
<Compile Include="AssemblyFixture.cs" />
<Compile Include="Helpers\ObjectMother.cs" />
<Compile Include="Helpers\ViewModelEqualsConstraint.cs" />
<Compile Include="ModelBinding\ChangingContextTests.cs" />
<Compile Include="ModelBinding\ModelBindingTests.cs" />
<Compile Include="ModelBinding\Pages\ChameleonFormsPage.cs" />
<Compile Include="ModelBinding\Pages\Fields\BinaryInputField.cs" />
Expand All @@ -135,6 +136,7 @@
<Compile Include="ModelBinding\Pages\Fields\SelectField.cs" />
<Compile Include="ModelBinding\Pages\Fields\TextInputField.cs" />
<Compile Include="ModelBinding\Pages\HomePage.cs" />
<Compile Include="ModelBinding\Pages\ChangingContextPage.cs" />
<Compile Include="ModelBinding\Pages\ModelBindingExamplePage.cs" />
<Compile Include="ModelBinding\Pages\ModelFieldType.cs" />
<Compile Include="ModelBinding\Pages\ModelFieldValue.cs" />
Expand Down Expand Up @@ -177,4 +179,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>
42 changes: 42 additions & 0 deletions ChameleonForms.AcceptanceTests/Helpers/ObjectMother.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,47 @@ public static ModelBindingViewModel BasicValid
}
}
}

public static class ChangingContextViewModels
{
public static BasicViewModel DifferentViewModel
{
get
{
return new BasicViewModel
{
RequiredString = "req_string",
SomeCheckbox = true
};
}
}

public static ChildViewModel ChildViewModel
{
get
{
return new ChildViewModel
{
ChildField = "child_field_val",
SomeEnum = SomeEnum.ValueWithDescription
};
}
}

public static ParentViewModel ParentViewModel
{
get
{
return new ParentViewModel
{
Child = new ChildViewModel
{
ChildField = "child_field_val_from_parent",
SomeEnum = SomeEnum.SomeOtherValue
}
};
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Linq;
using System.Reflection;
using ChameleonForms.AcceptanceTests.ModelBinding.Pages;
using ChameleonForms.Example.Controllers;
using NUnit.Framework;
using NUnit.Framework.Constraints;

Expand All @@ -27,13 +26,19 @@ public ViewModelEqualsConstraint(object expectedViewModel)

public override bool Matches(object actualViewModel)
{
foreach (var property in typeof(ModelBindingViewModel).GetProperties(BindingFlags.Instance | BindingFlags.Public))
foreach (var property in actualViewModel.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (property.IsReadonly())
continue;
var expectedValue = property.GetValue(_expectedViewModel, null);
var actualValue = property.GetValue(actualViewModel, null);

if (!property.PropertyType.IsValueType && property.PropertyType != typeof(string) && !typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
Assert.That(actualValue, IsSame.ViewModelAs(expectedValue));
continue;
}

if (expectedValue is IEnumerable && !(expectedValue as IEnumerable).Cast<object>().Any())
Assert.That(actualValue, Is.Null.Or.Empty);
else
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using ChameleonForms.AcceptanceTests.Helpers;
using ChameleonForms.AcceptanceTests.ModelBinding.Pages;
using NUnit.Framework;
using TestStack.Seleno.Configuration;

namespace ChameleonForms.AcceptanceTests.ModelBinding
{
[TestFixture]
class ChangingContextShould
{
[Test]
public void Post_different_view_model_and_bind_on_postback()
{
var enteredViewModel = ObjectMother.ChangingContextViewModels.DifferentViewModel;

var page = Host.Instance.NavigateToInitialPage<HomePage>()
.GoToChangingContextPage2()
.PostDifferentModel(enteredViewModel);

Assert.That(page.ReadDifferentModel(), IsSame.ViewModelAs(enteredViewModel));
Assert.That(page.HasValidationErrors(), Is.False, "There are validation errors on the page");
}

[Test]
public void Post_child_view_model_and_bind_on_postback()
{
var enteredViewModel = ObjectMother.ChangingContextViewModels.ChildViewModel;

var page = Host.Instance.NavigateToInitialPage<HomePage>()
.GoToChangingContextPage2()
.PostChildModel(enteredViewModel);

Assert.That(page.ReadChildModel(), IsSame.ViewModelAs(enteredViewModel));
Assert.That(page.HasValidationErrors(), Is.False, "There are validation errors on the page");
}

[Test]
public void Post_child_view_model_and_bind_to_parent_on_postback()
{
var enteredViewModel = ObjectMother.ChangingContextViewModels.ParentViewModel;

var page = Host.Instance.NavigateToInitialPage<HomePage>()
.GoToChangingContextPage2()
.PostParentModel(enteredViewModel);

Assert.That(page.ReadParentModel(), IsSame.ViewModelAs(enteredViewModel));
Assert.That(page.HasValidationErrors(), Is.False, "There are validation errors on the page");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
Expand All @@ -14,27 +15,58 @@ namespace ChameleonForms.AcceptanceTests.ModelBinding.Pages
public abstract class ChameleonFormsPage<T> : Page<T> where T : class, new()
{
protected void InputModel(T model)
{
InputModel(model, "");
}

private void InputModel(object model, string prefix)
{
foreach (var property in model.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var propertyName = string.IsNullOrEmpty(prefix)
? property.Name
: string.Format("{0}.{1}", prefix, property.Name);

if (property.IsReadonly())
continue;

var elements = ((RemoteWebDriver)Browser).FindElementsByName(property.Name);
if (!property.PropertyType.IsValueType && property.PropertyType != typeof(string) && !typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
InputModel(property.GetValue(model, null), propertyName);
continue;
}

var elements = ((RemoteWebDriver)Browser).FindElementsByName(propertyName);
var format = GetFormatStringForProperty(property);
FieldFactory.Create(elements).Set(new ModelFieldValue(property.GetValue(model, null), format));
}
}

public T GetFormValues()
{
var vm = new T();
return (T) GetFormValues(typeof (T), "");
}

private object GetFormValues(Type typeOfModel, string prefix)
{
var vm = Activator.CreateInstance(typeOfModel);
foreach (var property in vm.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var propertyName = string.IsNullOrEmpty(prefix)
? property.Name
: string.Format("{0}.{1}", prefix, property.Name);

if (property.IsReadonly())
continue;

var elements = ((RemoteWebDriver)Browser).FindElementsByName(property.Name);
if (!property.PropertyType.IsValueType && property.PropertyType != typeof(string) && !typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
var childValue = GetFormValues(property.PropertyType, propertyName);
property.SetValue(vm, childValue, null);
continue;
}

var elements = ((RemoteWebDriver)Browser).FindElementsByName(propertyName);
var format = GetFormatStringForProperty(property);
property.SetValue(vm, FieldFactory.Create(elements).Get(new ModelFieldType(property.PropertyType, format)), null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using ChameleonForms.Example.Controllers;
using OpenQA.Selenium;

namespace ChameleonForms.AcceptanceTests.ModelBinding.Pages
{
public class ChangingContextPage : ChameleonFormsPage<ParentViewModel>
{
public BasicViewModel ReadDifferentModel()
{
return GetComponent<PageAsDifferentModel>().GetFormValues();
}

public ChangingContextPage PostDifferentModel(BasicViewModel vm)
{
GetComponent<PageAsDifferentModel>().Input(vm);
return Navigate.To<ChangingContextPage>(By.CssSelector("button[type=submit].different-model"));
}

public ChildViewModel ReadChildModel()
{
return GetComponent<PageAsChildModel>().GetFormValues();
}

public ChangingContextPage PostChildModel(ChildViewModel vm)
{
GetComponent<PageAsChildModel>().Input(vm);
return Navigate.To<ChangingContextPage>(By.CssSelector("button[type=submit].child-model"));
}

public ParentViewModel ReadParentModel()
{
return GetFormValues();
}

public ChangingContextPage PostParentModel(ParentViewModel vm)
{
InputModel(vm);
return Navigate.To<ChangingContextPage>(By.CssSelector("button[type=submit].parent-model"));
}

public class PageAsDifferentModel : ChameleonFormsPage<BasicViewModel>
{
public void Input(BasicViewModel vm)
{
InputModel(vm);
}
}
public class PageAsChildModel : ChameleonFormsPage<ChildViewModel>
{
public void Input(ChildViewModel vm)
{
InputModel(vm);
}
}
}
}
5 changes: 5 additions & 0 deletions ChameleonForms.AcceptanceTests/ModelBinding/Pages/HomePage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@ public ModelBindingExamplePage GoToModelBindingExamplePage2()
{
return Navigate.To<ModelBindingExamplePage>(By.LinkText("Model Binding Example with lists"));
}

public ChangingContextPage GoToChangingContextPage2()
{
return Navigate.To<ChangingContextPage>(By.LinkText("Changing HTML Helper context"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ <h1>Partials</h1>
<option value="2">B</option>
</select>in parent view <span class="field-validation-valid" data-valmsg-for="ListId" data-valmsg-replace="true"></span>
</dd>
<dt><label for="Child_ChildField">Child field</label></dt>
<dt><label for="Child_ChildField">Child field</label> <em class="required">*</em></dt>
<dd>
<input id="Child_ChildField" name="Child.ChildField" type="text" value="">From partial against child model <span class="field-validation-valid" data-valmsg-for="Child.ChildField" data-valmsg-replace="true"></span>
<input data-val="true" data-val-required="The Child field field is required." id="Child_ChildField" name="Child.ChildField" type="text" value="">From partial against child model <span class="field-validation-valid" data-valmsg-for="Child.ChildField" data-valmsg-replace="true"></span>
</dd>

<dt><label for="SomeCheckbox">Some checkbox</label> <em class="required">*</em></dt>
Expand Down
7 changes: 6 additions & 1 deletion ChameleonForms.Example/ChameleonForms.Example.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions" />
Expand Down Expand Up @@ -203,6 +207,7 @@
<Content Include="Views\Shared\_BootstrapLayout.cshtml" />
<Content Include="Views\ExampleForms\Partials.cshtml" />
<Content Include="Views\ExampleForms\_ChildPartial.cshtml" />
<Content Include="Views\ExampleForms\ChangingContext.cshtml" />
</ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
Expand Down Expand Up @@ -267,4 +272,4 @@
</Target>
<Target Name="AfterBuild">
</Target> -->
</Project>
</Project>
Loading

0 comments on commit e902b27

Please sign in to comment.