Skip to content

Commit a5444a7

Browse files
committed
Add failing test with type-level validations
1 parent a7e8fa4 commit a5444a7

File tree

4 files changed

+138
-5
lines changed

4 files changed

+138
-5
lines changed

src/Components/test/E2ETest/ServerRenderingTests/AddValidationIntegrationTest.cs

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ public AddValidationIntegrationTest(BrowserFixture browserFixture, BasicTestAppS
2020
{
2121
}
2222

23-
protected override void InitializeAsyncCore()
24-
{
25-
Navigate("subdir/forms/add-validation-form");
26-
Browser.Exists(By.Id("is-interactive"));
27-
}
23+
public override Task InitializeAsync()
24+
=> InitializeAsync(BrowserFixture.StreamingContext);
2825

2926
[Fact]
3027
public void FormWithNestedValidation_Works()
3128
{
29+
Navigate("subdir/forms/add-validation-form");
30+
Browser.Exists(By.Id("is-interactive"));
31+
3232
Browser.Exists(By.Id("submit-form")).Click();
3333

3434
Browser.Exists(By.Id("is-invalid"));
@@ -58,4 +58,53 @@ public void FormWithNestedValidation_Works()
5858

5959
Assert.Equal(expected, individual);
6060
}
61+
62+
[Fact]
63+
public void FormWithTypeLevelValidations_Works()
64+
{
65+
// This is the new way of initializing test page
66+
Navigate("subdir/forms/type-level-validation-form");
67+
Browser.Exists(By.Id("is-interactive"));
68+
69+
// These have been replaced to use Browser.FindElement directly
70+
var isCatCheckbox = Browser.FindElement(By.ClassName("cattiness")).FindElement(By.TagName("input"));
71+
var ageInput = Browser.FindElement(By.ClassName("age")).FindElement(By.TagName("input"));
72+
var submitButton = Browser.FindElement(By.CssSelector("button[type=submit]"));
73+
var modelMessagesAccessor = CreateValidationMessagesAccessor(
74+
Browser.FindElement(By.ClassName("model-errors")),
75+
"ul.model-summary-custom-class > .validation-message"); // This shows we can override the ul's CSS class
76+
var allMessagesAccessor = CreateValidationMessagesAccessor(
77+
Browser.FindElement(By.ClassName("all-errors")));
78+
79+
//// Cause a property-level validation error
80+
ageInput.Clear();
81+
ageInput.SendKeys("-1");
82+
submitButton.Click();
83+
Browser.Collection(allMessagesAccessor, x => Assert.Equal("Under-zeros should not be filling out forms", x));
84+
Browser.Empty(modelMessagesAccessor);
85+
86+
//// Cause a model-level validation error
87+
ageInput.Clear();
88+
ageInput.SendKeys("10");
89+
submitButton.Click();
90+
Browser.Collection(allMessagesAccessor, x => Assert.Equal("Sorry, you're not old enough as a non-cat", x));
91+
Browser.Collection(modelMessagesAccessor, x => Assert.Equal("Sorry, you're not old enough as a non-cat", x));
92+
93+
//// Become valid
94+
isCatCheckbox.Click();
95+
submitButton.Click();
96+
Browser.Empty(allMessagesAccessor);
97+
Browser.Empty(modelMessagesAccessor);
98+
99+
Func<string[]> logEntries = () => Browser.FindElements(By.ClassName("submission-log-entry")).Select(x => x.Text).ToArray();
100+
Browser.Collection(logEntries, x => Assert.Equal("OnValidSubmit", x));
101+
}
102+
103+
private Func<string[]> CreateValidationMessagesAccessor(IWebElement appElement, string messageSelector = ".validation-message")
104+
{
105+
return () => appElement.FindElements(By.CssSelector(messageSelector))
106+
.Select(x => x.Text)
107+
.OrderBy(x => x)
108+
.ToArray();
109+
}
61110
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@page "/forms/type-level-validation-form"
2+
@rendermode RenderMode.InteractiveServer
3+
4+
<h3>This form demostrates using `AddValidation` from Microsoft.Extensions.Validation with type-level validations</h3>
5+
6+
<TypeLevelValidationComponent></TypeLevelValidationComponent>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
@using System.ComponentModel.DataAnnotations
2+
@using BasicTestApp.ValidationModels
3+
@using Microsoft.AspNetCore.Components.Forms
4+
5+
@if (RendererInfo.IsInteractive)
6+
{
7+
<p id="is-interactive"></p>
8+
}
9+
10+
<EditForm Model="@person" OnValidSubmit="@HandleValidSubmit">
11+
<DataAnnotationsValidator />
12+
13+
<h2>We only accept cats over 3 years of age, or non-cats over 18 years of age.</h2>
14+
15+
<p class="cattiness">
16+
<label>
17+
<InputCheckbox @bind-Value="person.IsACat" /> I am a cat
18+
</label>
19+
</p>
20+
21+
<p class="age">
22+
Age (years): <InputNumber @bind-Value="person.AgeInYears" placeholder="Enter your age" />
23+
</p>
24+
25+
<button type="submit">Submit</button>
26+
27+
<p class="model-errors">
28+
<ValidationSummary Model="person" class="model-summary-custom-class" />
29+
</p>
30+
31+
<p class="all-errors">
32+
<ValidationSummary />
33+
</p>
34+
</EditForm>
35+
36+
<ul>@foreach (var entry in submissionLog) {
37+
<li class="submission-log-entry">@entry</li>
38+
}
39+
</ul>
40+
41+
@code {
42+
Person person = new Person();
43+
44+
List<string> submissionLog = new List<string>(); // So we can assert about the callbacks
45+
46+
void HandleValidSubmit()
47+
{
48+
submissionLog.Add("OnValidSubmit");
49+
}
50+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.ComponentModel.DataAnnotations;
5+
using Microsoft.Extensions.Validation;
6+
7+
namespace BasicTestApp.ValidationModels;
8+
#pragma warning disable ASP0029 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
9+
[ValidatableType]
10+
#pragma warning restore ASP0029 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
11+
public class Person : IValidatableObject
12+
{
13+
[Required]
14+
public bool IsACat { get; set; }
15+
16+
[Range(0, int.MaxValue, ErrorMessage = "Under-zeros should not be filling out forms")]
17+
public int AgeInYears { get; set; }
18+
19+
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
20+
{
21+
var minAge = IsACat ? 3 : 18;
22+
if (AgeInYears < minAge)
23+
{
24+
// Supply a model-level error (i.e., not attached to a specific property)
25+
yield return new ValidationResult($"Sorry, you're not old enough as a {(IsACat ? "cat" : "non-cat")}");
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)