From 80d46a67221bb1deb79a058e2c81f8a84ad1a7c6 Mon Sep 17 00:00:00 2001
From: luetm
Date: Wed, 21 Feb 2024 14:03:35 +0100
Subject: [PATCH 01/11] Created tests for the first to features in the README.
---
Blazored.FluentValidation.sln | 17 +++
README.md | 2 +-
.../AssemblyScanning/Component.razor | 34 ++++++
.../AssemblyScanning/Readme.md | 7 ++
.../AssemblyScanning/Tests.cs | 64 ++++++++++
.../BasicValidation/Component.razor | 44 +++++++
.../BasicValidation/Readme.md | 7 ++
.../BasicValidation/Tests.cs | 110 ++++++++++++++++++
.../Blazored.FluentValidation.Tests.csproj | 41 +++++++
.../GlobalUsings.cs | 3 +
.../Model/Address.cs | 27 +++++
.../Model/Person.cs | 58 +++++++++
.../Model/ValidationResultType.cs | 8 ++
.../_Imports.razor | 14 +++
14 files changed, 435 insertions(+), 1 deletion(-)
create mode 100644 tests/Blazored.FluentValidation.Tests/AssemblyScanning/Component.razor
create mode 100644 tests/Blazored.FluentValidation.Tests/AssemblyScanning/Readme.md
create mode 100644 tests/Blazored.FluentValidation.Tests/AssemblyScanning/Tests.cs
create mode 100644 tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor
create mode 100644 tests/Blazored.FluentValidation.Tests/BasicValidation/Readme.md
create mode 100644 tests/Blazored.FluentValidation.Tests/BasicValidation/Tests.cs
create mode 100644 tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
create mode 100644 tests/Blazored.FluentValidation.Tests/GlobalUsings.cs
create mode 100644 tests/Blazored.FluentValidation.Tests/Model/Address.cs
create mode 100644 tests/Blazored.FluentValidation.Tests/Model/Person.cs
create mode 100644 tests/Blazored.FluentValidation.Tests/Model/ValidationResultType.cs
create mode 100644 tests/Blazored.FluentValidation.Tests/_Imports.razor
diff --git a/Blazored.FluentValidation.sln b/Blazored.FluentValidation.sln
index 5b8ce3e..bc1abab 100644
--- a/Blazored.FluentValidation.sln
+++ b/Blazored.FluentValidation.sln
@@ -20,6 +20,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorServer", "samples\Bla
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharedModels", "samples\Shared\SharedModels\SharedModels.csproj", "{42276235-5139-41D6-923D-18B7EB5E3E44}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{DACAA0DB-2B93-4FE1-9D21-F45A4E63A640}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazored.FluentValidation.Tests", "tests\Blazored.FluentValidation.Tests\Blazored.FluentValidation.Tests.csproj", "{C92DF59B-B760-4FCC-A34C-A4007529BCC5}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -78,6 +82,18 @@ Global
{42276235-5139-41D6-923D-18B7EB5E3E44}.Release|x64.Build.0 = Release|Any CPU
{42276235-5139-41D6-923D-18B7EB5E3E44}.Release|x86.ActiveCfg = Release|Any CPU
{42276235-5139-41D6-923D-18B7EB5E3E44}.Release|x86.Build.0 = Release|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|x64.Build.0 = Debug|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Debug|x86.Build.0 = Debug|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|x64.ActiveCfg = Release|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|x64.Build.0 = Release|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|x86.ActiveCfg = Release|Any CPU
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -86,6 +102,7 @@ Global
{8BC1065A-A71E-4568-8A67-9C3AF039F73A} = {D5C6DCA9-C2BD-4117-BCCC-19E36E8406AB}
{2459CF4B-6548-4031-B784-43E943E270A9} = {D5C6DCA9-C2BD-4117-BCCC-19E36E8406AB}
{42276235-5139-41D6-923D-18B7EB5E3E44} = {D5C6DCA9-C2BD-4117-BCCC-19E36E8406AB}
+ {C92DF59B-B760-4FCC-A34C-A4007529BCC5} = {DACAA0DB-2B93-4FE1-9D21-F45A4E63A640}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {42B22D99-6E59-4B30-88AD-B9CC07E0DA49}
diff --git a/README.md b/README.md
index 02b1e46..1ce13f1 100644
--- a/README.md
+++ b/README.md
@@ -132,7 +132,7 @@ The second is when manually validating the model using the `Validate` or `Valida
```
## Access to full `ValidationFailure`
-If you need details about the specifics of a validation result (e.g. its `Severity), you can access the result of the
+If you need details about the specifics of a validation result (e.g. its `Severity`), you can access the result of the
last validation by calling the `GetFailuresFromLastValidation` method on the `FluentValidationValidator` component.
```razor
diff --git a/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Component.razor b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Component.razor
new file mode 100644
index 0000000..476cd48
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Component.razor
@@ -0,0 +1,34 @@
+@using Blazored.FluentValidation.Tests.Model
+
+
+ @if (DisableAssemblyScanning is null)
+ {
+
+ }
+ else
+ {
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+@code {
+ [Parameter] public bool? DisableAssemblyScanning { get; set; }
+ private readonly Person _person = new();
+
+ internal ValidationResultType Result { get; private set; } = ValidationResultType.Valid;
+
+ private void ValidSubmit() => Result = ValidationResultType.Valid;
+ private void InvalidSubmit() => Result = ValidationResultType.Error;
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Readme.md b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Readme.md
new file mode 100644
index 0000000..a332f37
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Readme.md
@@ -0,0 +1,7 @@
+### What does this test?
+This test checks if the assembly scanning works. It leverages, that this test
+assembly does not register any `AbstractValidator` by default.
+
+ - Setting the `DisableAssemblyScanning` to `true` should not find any validators and ignore errors.
+ - Setting the `DisableAssemblyScanning` to `false` or not setting the attribute at all, should
+ find the validators in the assembly and validate normally.
diff --git a/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Tests.cs b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Tests.cs
new file mode 100644
index 0000000..7f4ba4c
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Tests.cs
@@ -0,0 +1,64 @@
+using Blazored.FluentValidation.Tests.Model;
+
+namespace Blazored.FluentValidation.Tests.AssemblyScanning;
+
+public class Tests : TestContext
+{
+ private readonly Fixture _fixture = new();
+
+ [Fact]
+ public void DisableAssemblyScanning_SetToTrue_NoValidationHappens()
+ {
+ // Arrange
+ var cut = RenderComponent(p => p.Add(c => c.DisableAssemblyScanning, true));
+ var person = _fixture.InvalidPerson();
+
+ // Act
+ cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Valid);
+ }
+
+ [Fact]
+ public void DisableAssemblyScanning_SetToFalse_ValidationHappens()
+ {
+ // Arrange
+ var cut = RenderComponent(p => p.Add(c => c.DisableAssemblyScanning, false));
+ var person = _fixture.InvalidPerson();
+
+ // Act
+ cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Error);
+ }
+
+ [Fact]
+ public void DisableAssemblyScanning_NotSet_ValidationHappens()
+ {
+ // Arrange
+ var cut = RenderComponent(p => p.Add(c => c.DisableAssemblyScanning, null));
+ var person = _fixture.InvalidPerson();
+
+ // Act
+ cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Error);
+ }
+
+ private class Fixture
+ {
+ public Person InvalidPerson() => new()
+ {
+ FirstName = "",
+ LastName = "Doe",
+ EmailAddress = "john.doe@blazored.org",
+ Age = 30
+ };
+ }
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor b/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor
new file mode 100644
index 0000000..7a12405
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor
@@ -0,0 +1,44 @@
+@using Blazored.FluentValidation.Tests.Model
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@code {
+ private readonly Person _person = new();
+ internal ValidationResultType Result { get; private set; } = ValidationResultType.Valid;
+
+ private void ValidSubmit() => Result = ValidationResultType.Valid;
+ private void InvalidSubmit() => Result = ValidationResultType.Error;
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/BasicValidation/Readme.md b/tests/Blazored.FluentValidation.Tests/BasicValidation/Readme.md
new file mode 100644
index 0000000..4ab205e
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/BasicValidation/Readme.md
@@ -0,0 +1,7 @@
+### What does this test?
+This test checks if the basic validation works.
+
+ - Does a valid model pass the validation?
+ - Do basic validation rules get picked up?
+ - Do validation errors get displayed correctly in the UI?
+ - Are nested rules validated correctly?
diff --git a/tests/Blazored.FluentValidation.Tests/BasicValidation/Tests.cs b/tests/Blazored.FluentValidation.Tests/BasicValidation/Tests.cs
new file mode 100644
index 0000000..ae461af
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/BasicValidation/Tests.cs
@@ -0,0 +1,110 @@
+using Blazored.FluentValidation.Tests.Model;
+
+namespace Blazored.FluentValidation.Tests.BasicValidation;
+
+public class Tests : TestContext
+{
+ private readonly Fixture _fixture = new();
+
+ [Fact]
+ public void Validate_DataIsValid_ValidSubmit()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson();
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Valid);
+ }
+
+ [Fact]
+ public void Validate_FirstNameMissing_InvalidSubmit()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson() with { FirstName = string.Empty };
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Error);
+ }
+
+ [Fact]
+ public void Validate_FirstNameMissing_ValidationErrorsPresent()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson() with { FirstName = string.Empty };
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameRequired);
+ cut.Find("li.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameRequired);
+ }
+
+ [Fact]
+ public void Validate_AgeTooOld_ValidationErrorsPresent()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson() with { Age = 250 };
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(PersonValidator.AgeMax);
+ }
+
+ [Fact]
+ public void Validate_AddressLine1Missing_ValidationErrorsPresent()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson() with { Address = new() { Line1 = string.Empty } };
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(AddressValidator.Line1Required);
+ }
+
+ private static void FillForm(IRenderedComponent cut, Person person)
+ {
+ cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
+ cut.Find($"input[name={nameof(Person.LastName)}]").Change(person.LastName);
+ cut.Find($"input[name={nameof(Person.EmailAddress)}]").Change(person.EmailAddress);
+ cut.Find($"input[name={nameof(Person.Age)}]").Change(person.Age.ToString());
+ cut.Find($"input[name={nameof(Person.Address.Line1)}]").Change(person.Address.Line1);
+ }
+
+ private class Fixture
+ {
+ public Person ValidPerson() => new()
+ {
+ FirstName = "John",
+ LastName = "Doe",
+ EmailAddress = "john.doe@blazored.org",
+ Age = 30,
+ Address = new()
+ {
+ Line1 = "123 Main St",
+ Town = "Springfield",
+ Postcode = "12345"
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
new file mode 100644
index 0000000..8269342
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
@@ -0,0 +1,41 @@
+
+
+
+ net7.0
+ enable
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Blazored.FluentValidation.Tests/GlobalUsings.cs b/tests/Blazored.FluentValidation.Tests/GlobalUsings.cs
new file mode 100644
index 0000000..6b9b9b4
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/GlobalUsings.cs
@@ -0,0 +1,3 @@
+global using System.Threading.Tasks;
+global using FluentAssertions;
+global using FluentValidation;
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/Model/Address.cs b/tests/Blazored.FluentValidation.Tests/Model/Address.cs
new file mode 100644
index 0000000..d7a5332
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/Model/Address.cs
@@ -0,0 +1,27 @@
+namespace Blazored.FluentValidation.Tests.Model
+{
+ public record Address
+ {
+ public string? Line1 { get; set; }
+ public string? Line2 { get; set; }
+ public string? Town { get; set; }
+ public string? County { get; set; }
+ public string? Postcode { get; set; }
+ }
+
+ public class AddressValidator : AbstractValidator
+ {
+ public const string Line1Required = "You must enter Line 1";
+ public const string TownRequired = "You must enter a town";
+ public const string CountyRequired = "You must enter a county";
+ public const string PostcodeRequired = "You must enter a postcode";
+
+ public AddressValidator()
+ {
+ RuleFor(p => p.Line1).NotEmpty().WithMessage(Line1Required);
+ RuleFor(p => p.Town).NotEmpty().WithMessage(TownRequired);
+ RuleFor(p => p.County).NotEmpty().WithMessage(CountyRequired);
+ RuleFor(p => p.Postcode).NotEmpty().WithMessage(PostcodeRequired);
+ }
+ }
+}
diff --git a/tests/Blazored.FluentValidation.Tests/Model/Person.cs b/tests/Blazored.FluentValidation.Tests/Model/Person.cs
new file mode 100644
index 0000000..e84b1b7
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/Model/Person.cs
@@ -0,0 +1,58 @@
+namespace Blazored.FluentValidation.Tests.Model
+{
+ public record Person
+ {
+ public string? FirstName { get; set; }
+ public string? LastName { get; set; }
+ public int? Age { get; set; }
+ public string? EmailAddress { get; set; }
+ public Address Address { get; set; } = new();
+ }
+
+ public class PersonValidator : AbstractValidator
+ {
+ public const string FirstNameRequired = "You must enter your first name";
+ public const string FirstNameMaxLength = "First name cannot be longer than 50 characters";
+ public const string LastNameRequired = "You must enter your last name";
+ public const string LastNameMaxLength = "Last name cannot be longer than 50 characters";
+ public const string AgeRequired = "You must enter your age";
+ public const string AgeMin = "Age must be greater than 0";
+ public const string AgeMax = "Age cannot be greater than 150";
+ public const string EmailRequired = "You must enter an email address";
+ public const string EmailValid = "You must provide a valid email address";
+ public const string EmailUnique = "Email address must be unique";
+ public const string DuplicateEmail = "mail@my.com";
+
+ public PersonValidator()
+ {
+ RuleSet("Names", () =>
+ {
+ RuleFor(p => p.FirstName)
+ .NotEmpty().WithMessage(FirstNameRequired)
+ .MaximumLength(50).WithMessage(FirstNameMaxLength);
+
+ RuleFor(p => p.LastName)
+ .NotEmpty().WithMessage(LastNameRequired)
+ .MaximumLength(50).WithMessage(LastNameMaxLength);
+ });
+
+ RuleFor(p => p.Age)
+ .NotNull().WithMessage(AgeRequired)
+ .GreaterThanOrEqualTo(0).WithMessage(AgeMin)
+ .LessThan(150).WithMessage(AgeMax);
+
+ RuleFor(p => p.EmailAddress)
+ .NotEmpty().WithMessage(EmailRequired)
+ .EmailAddress().WithMessage(EmailValid)
+ .MustAsync(async (email, _) => await IsUniqueAsync(email)).WithMessage(EmailUnique);
+
+ RuleFor(p => p.Address).SetValidator(new AddressValidator());
+ }
+
+ private static async Task IsUniqueAsync(string? email)
+ {
+ await Task.Delay(300);
+ return email?.ToLower() != DuplicateEmail;
+ }
+ }
+}
diff --git a/tests/Blazored.FluentValidation.Tests/Model/ValidationResultType.cs b/tests/Blazored.FluentValidation.Tests/Model/ValidationResultType.cs
new file mode 100644
index 0000000..e35c667
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/Model/ValidationResultType.cs
@@ -0,0 +1,8 @@
+namespace Blazored.FluentValidation.Tests.Model;
+
+public enum ValidationResultType
+{
+ Valid,
+ Warning,
+ Error
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/_Imports.razor b/tests/Blazored.FluentValidation.Tests/_Imports.razor
new file mode 100644
index 0000000..6d4953f
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/_Imports.razor
@@ -0,0 +1,14 @@
+@using Blazored.FluentValidation
+
+@using Bunit
+@using Bunit.TestDoubles
+
+@using Microsoft.AspNetCore.Components.Forms
+@using Microsoft.AspNetCore.Components.Routing
+@using Microsoft.AspNetCore.Components.Web
+@using Microsoft.Extensions.DependencyInjection
+@using Microsoft.JSInterop
+@using System.Net.Http
+@using System.Net.Http.Json
+
+@using Xunit
\ No newline at end of file
From 8071461b0b5a3376ae7a4d5859ff6060d5a77629 Mon Sep 17 00:00:00 2001
From: luetm
Date: Wed, 21 Feb 2024 14:11:12 +0100
Subject: [PATCH 02/11] Added IoC test case to assembly scanning tests.
---
.../AssemblyScanning/Readme.md | 2 ++
.../AssemblyScanning/Tests.cs | 16 ++++++++++++++++
.../Blazored.FluentValidation.Tests.csproj | 4 ++++
3 files changed, 22 insertions(+)
diff --git a/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Readme.md b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Readme.md
index a332f37..4540b8d 100644
--- a/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Readme.md
+++ b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Readme.md
@@ -5,3 +5,5 @@ assembly does not register any `AbstractValidator` by default.
- Setting the `DisableAssemblyScanning` to `true` should not find any validators and ignore errors.
- Setting the `DisableAssemblyScanning` to `false` or not setting the attribute at all, should
find the validators in the assembly and validate normally.
+ - Setting the `DisableAssemblyScanning` to `true` and registering the validators manually should
+ find the validators and validate normally.
diff --git a/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Tests.cs b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Tests.cs
index 7f4ba4c..32be18a 100644
--- a/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Tests.cs
+++ b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Tests.cs
@@ -51,6 +51,22 @@ public void DisableAssemblyScanning_NotSet_ValidationHappens()
cut.Instance.Result.Should().Be(ValidationResultType.Error);
}
+ [Fact]
+ public void DisableAssemblyScanning_SetToTrueButValidatorsRegistered_ValidationHappens()
+ {
+ // Arrange
+ Services.AddTransient, PersonValidator>();
+ var cut = RenderComponent(p => p.Add(c => c.DisableAssemblyScanning, null));
+ var person = _fixture.InvalidPerson();
+
+ // Act
+ cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Error);
+ }
+
private class Fixture
{
public Person InvalidPerson() => new()
diff --git a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
index 8269342..b52f9e7 100644
--- a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
+++ b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
@@ -36,6 +36,10 @@
+
+
+
+
From 12eb3d2fc59d31d46eadd700d26e9782c0941681 Mon Sep 17 00:00:00 2001
From: luetm
Date: Wed, 21 Feb 2024 14:28:13 +0100
Subject: [PATCH 03/11] Added some `ValidateAsync` tests, one is failing for
some reason, need to investigate.
---
.../AssemblyScanning/Component.razor | 3 +-
.../AsyncValidation/Component.razor | 41 ++++++++++
.../AsyncValidation/Readme.md | 1 +
.../AsyncValidation/Tests.cs | 80 +++++++++++++++++++
.../BasicValidation/Component.razor | 3 +-
.../Blazored.FluentValidation.Tests.csproj | 4 -
.../_Imports.razor | 1 +
7 files changed, 125 insertions(+), 8 deletions(-)
create mode 100644 tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
create mode 100644 tests/Blazored.FluentValidation.Tests/AsyncValidation/Readme.md
create mode 100644 tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs
diff --git a/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Component.razor b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Component.razor
index 476cd48..e501004 100644
--- a/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Component.razor
+++ b/tests/Blazored.FluentValidation.Tests/AssemblyScanning/Component.razor
@@ -1,5 +1,4 @@
-@using Blazored.FluentValidation.Tests.Model
-
diff --git a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
new file mode 100644
index 0000000..9889587
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@code {
+ private readonly Person _person = new();
+ private FluentValidationValidator? _fluentValidationValidator;
+
+ public ValidationResultType Result { get; private set; }
+
+ private async Task SubmitFormAsync()
+ {
+ var result = await _fluentValidationValidator!.ValidateAsync();
+ Result = result ? ValidationResultType.Valid : ValidationResultType.Error;
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Readme.md b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Readme.md
new file mode 100644
index 0000000..3e49f9c
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Readme.md
@@ -0,0 +1 @@
+### What does this test?
diff --git a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs
new file mode 100644
index 0000000..1556ac1
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs
@@ -0,0 +1,80 @@
+using Blazored.FluentValidation.Tests.Model;
+
+namespace Blazored.FluentValidation.Tests.AsyncValidation;
+
+public class Tests : TestContext
+{
+ private readonly Fixture _fixture = new();
+
+ [Fact]
+ public void AsyncValidate_PersonIsValid_ResultIsValid()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson();
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Valid);
+ }
+
+ [Fact]
+ public void AsyncValidate_FirstNameTooLong_ResultIsError()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson() with
+ {
+ FirstName = "This is a very long first name that is over 50 characters long"
+ };
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Error);
+ }
+
+ [Fact]
+ public void AsyncValidate_FirstNameTooLong_ValidationMessagesPresent()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson() with
+ {
+ FirstName = "This is a very long first name that is over 50 characters long",
+ LastName = "",
+ };
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameMaxLength);
+ cut.Find("li.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameMaxLength);
+ }
+
+ private void FillForm(IRenderedComponent cut, Person person)
+ {
+ cut.Find("input[name=FirstName]").Change(person.FirstName);
+ cut.Find("input[name=LastName]").Change(person.LastName);
+ cut.Find("input[name=Age]").Change(person.Age.ToString());
+ cut.Find("input[name=EmailAddress]").Change(person.EmailAddress);
+ }
+
+ private class Fixture
+ {
+ public Person ValidPerson() => new()
+ {
+ FirstName = "John",
+ LastName = "Doe",
+ Age = 30,
+ EmailAddress = "john.doe@blazored.com"
+ };
+ }
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor b/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor
index 7a12405..82093d8 100644
--- a/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor
+++ b/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor
@@ -1,5 +1,4 @@
-@using Blazored.FluentValidation.Tests.Model
-
diff --git a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
index b52f9e7..8269342 100644
--- a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
+++ b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
@@ -36,10 +36,6 @@
-
-
-
-
diff --git a/tests/Blazored.FluentValidation.Tests/_Imports.razor b/tests/Blazored.FluentValidation.Tests/_Imports.razor
index 6d4953f..b5e1119 100644
--- a/tests/Blazored.FluentValidation.Tests/_Imports.razor
+++ b/tests/Blazored.FluentValidation.Tests/_Imports.razor
@@ -1,4 +1,5 @@
@using Blazored.FluentValidation
+@using Blazored.FluentValidation.Tests.Model
@using Bunit
@using Bunit.TestDoubles
From 1e11c18cc90285f760b5b31bccbdb1c46a529270 Mon Sep 17 00:00:00 2001
From: luetm
Date: Wed, 21 Feb 2024 14:53:46 +0100
Subject: [PATCH 04/11] Test now passes, however the behavior is strange: When
doing normal validation, all rules are automatically included, but when doing
it with `ValidateAsync`, they need to be included manually.
---
.../AsyncValidation/Component.razor | 3 +-
.../AsyncValidation/Tests.cs | 29 ++++++++-----------
.../BasicValidation/Component.razor | 4 +--
.../BasicValidation/Tests.cs | 2 +-
.../Model/Person.cs | 6 ++--
5 files changed, 20 insertions(+), 24 deletions(-)
diff --git a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
index 9889587..ff4f9eb 100644
--- a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
+++ b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
@@ -30,12 +30,11 @@
private readonly Person _person = new();
private FluentValidationValidator? _fluentValidationValidator;
- public ValidationResultType Result { get; private set; }
+ public ValidationResultType? Result { get; private set; }
private async Task SubmitFormAsync()
{
var result = await _fluentValidationValidator!.ValidateAsync();
Result = result ? ValidationResultType.Valid : ValidationResultType.Error;
}
-
}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs
index 1556ac1..453cec4 100644
--- a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs
+++ b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs
@@ -1,11 +1,10 @@
using Blazored.FluentValidation.Tests.Model;
-
namespace Blazored.FluentValidation.Tests.AsyncValidation;
public class Tests : TestContext
{
private readonly Fixture _fixture = new();
-
+
[Fact]
public void AsyncValidate_PersonIsValid_ResultIsValid()
{
@@ -16,47 +15,43 @@ public void AsyncValidate_PersonIsValid_ResultIsValid()
// Act
FillForm(cut, person);
cut.Find("button").Click();
+ cut.WaitForState(() => cut.Instance.Result is not null);
// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Valid);
}
-
+
[Fact]
- public void AsyncValidate_FirstNameTooLong_ResultIsError()
+ public void AsyncValidate_AgeNegative_ResultIsError()
{
// Arrange
var cut = RenderComponent();
- var person = _fixture.ValidPerson() with
- {
- FirstName = "This is a very long first name that is over 50 characters long"
- };
+ var person = _fixture.ValidPerson() with { Age = -5 };
// Act
FillForm(cut, person);
cut.Find("button").Click();
+ cut.WaitForState(() => cut.Instance.Result is not null);
// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Error);
}
-
+
[Fact]
- public void AsyncValidate_FirstNameTooLong_ValidationMessagesPresent()
+ public void AsyncValidate_AgeNegative_ValidationMessagesPresent()
{
// Arrange
var cut = RenderComponent();
- var person = _fixture.ValidPerson() with
- {
- FirstName = "This is a very long first name that is over 50 characters long",
- LastName = "",
- };
+ var person = _fixture.ValidPerson() with { Age = -5 };
// Act
FillForm(cut, person);
cut.Find("button").Click();
+ cut.WaitForState(() => cut.Instance.Result is not null);
// Assert
- cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameMaxLength);
- cut.Find("li.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameMaxLength);
+ cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(PersonValidator.AgeMin);
+ cut.Find("li.validation-message").TextContent.Should().Contain(PersonValidator.AgeMin);
}
private void FillForm(IRenderedComponent cut, Person person)
diff --git a/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor b/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor
index 82093d8..17b2f0f 100644
--- a/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor
+++ b/tests/Blazored.FluentValidation.Tests/BasicValidation/Component.razor
@@ -28,14 +28,14 @@
-
+
@code {
- private readonly Person _person = new();
+ private readonly Person _person = new() { Address = new() };
internal ValidationResultType Result { get; private set; } = ValidationResultType.Valid;
private void ValidSubmit() => Result = ValidationResultType.Valid;
diff --git a/tests/Blazored.FluentValidation.Tests/BasicValidation/Tests.cs b/tests/Blazored.FluentValidation.Tests/BasicValidation/Tests.cs
index ae461af..fdcef88 100644
--- a/tests/Blazored.FluentValidation.Tests/BasicValidation/Tests.cs
+++ b/tests/Blazored.FluentValidation.Tests/BasicValidation/Tests.cs
@@ -88,7 +88,7 @@ private static void FillForm(IRenderedComponent cut, Person person)
cut.Find($"input[name={nameof(Person.LastName)}]").Change(person.LastName);
cut.Find($"input[name={nameof(Person.EmailAddress)}]").Change(person.EmailAddress);
cut.Find($"input[name={nameof(Person.Age)}]").Change(person.Age.ToString());
- cut.Find($"input[name={nameof(Person.Address.Line1)}]").Change(person.Address.Line1);
+ cut.Find($"input[name={nameof(Person.Address.Line1)}]").Change(person.Address!.Line1);
}
private class Fixture
diff --git a/tests/Blazored.FluentValidation.Tests/Model/Person.cs b/tests/Blazored.FluentValidation.Tests/Model/Person.cs
index e84b1b7..93a61a1 100644
--- a/tests/Blazored.FluentValidation.Tests/Model/Person.cs
+++ b/tests/Blazored.FluentValidation.Tests/Model/Person.cs
@@ -6,7 +6,7 @@ public record Person
public string? LastName { get; set; }
public int? Age { get; set; }
public string? EmailAddress { get; set; }
- public Address Address { get; set; } = new();
+ public Address? Address { get; set; }
}
public class PersonValidator : AbstractValidator
@@ -46,7 +46,9 @@ public PersonValidator()
.EmailAddress().WithMessage(EmailValid)
.MustAsync(async (email, _) => await IsUniqueAsync(email)).WithMessage(EmailUnique);
- RuleFor(p => p.Address).SetValidator(new AddressValidator());
+ RuleFor(p => p.Address!)
+ .SetValidator(new AddressValidator())
+ .When(p => p.Address is not null);
}
private static async Task IsUniqueAsync(string? email)
From 0771d422e885a15b5bafdc8bd083764ca9aad80b Mon Sep 17 00:00:00 2001
From: luetm
Date: Wed, 21 Feb 2024 14:58:18 +0100
Subject: [PATCH 05/11] Forgot Readme.md.
---
.../Blazored.FluentValidation.Tests/AsyncValidation/Readme.md | 3 +++
.../Blazored.FluentValidation.Tests.csproj | 4 ++++
2 files changed, 7 insertions(+)
diff --git a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Readme.md b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Readme.md
index 3e49f9c..e1363a0 100644
--- a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Readme.md
+++ b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Readme.md
@@ -1 +1,4 @@
### What does this test?
+This test checks if the `ValidateAsync` method works correctly,
+specifically that the `bool` returned is `false` when validation fails,
+and `true` otherwise.
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
index 8269342..dbfbe06 100644
--- a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
+++ b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
@@ -36,6 +36,10 @@
+
+
+
+
From 7d2df1b7702112cbdc27f765beb17452d8b11587 Mon Sep 17 00:00:00 2001
From: luetm
Date: Wed, 21 Feb 2024 15:46:09 +0100
Subject: [PATCH 06/11] Tests for rule sets (.razor variant bugged?)
---
.../AsyncValidation/Component.razor | 1 -
.../Blazored.FluentValidation.Tests.csproj | 4 --
.../RuleSets/Component.razor | 37 ++++++++++++++
.../RuleSets/Tests.cs | 50 +++++++++++++++++++
4 files changed, 87 insertions(+), 5 deletions(-)
create mode 100644 tests/Blazored.FluentValidation.Tests/RuleSets/Component.razor
create mode 100644 tests/Blazored.FluentValidation.Tests/RuleSets/Tests.cs
diff --git a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
index ff4f9eb..2acb1a0 100644
--- a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
+++ b/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
@@ -23,7 +23,6 @@
-
@code {
diff --git a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
index dbfbe06..8269342 100644
--- a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
+++ b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
@@ -36,10 +36,6 @@
-
-
-
-
diff --git a/tests/Blazored.FluentValidation.Tests/RuleSets/Component.razor b/tests/Blazored.FluentValidation.Tests/RuleSets/Component.razor
new file mode 100644
index 0000000..e8b633b
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/RuleSets/Component.razor
@@ -0,0 +1,37 @@
+
+
+ @if (IncludeWithAttribute)
+ {
+ @* Can't implement.. bugged?
*@
+ }
+ else
+ {
+
+ }
+
+
+
+
+
+
+
+
+
+
+@code {
+ [Parameter] public bool IncludeWithAttribute { get; set; }
+ [Parameter] public bool IncludeWithCode { get; set; }
+
+ private readonly Person _person = new();
+ private FluentValidationValidator? _fluentValidationValidator;
+
+ public ValidationResultType? Result { get; private set; }
+
+ protected void Submit()
+ {
+ var result = _fluentValidationValidator!.Validate(o => o.IncludeRuleSets("Names"));
+ Result = result ? ValidationResultType.Valid : ValidationResultType.Error;
+ }
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/RuleSets/Tests.cs b/tests/Blazored.FluentValidation.Tests/RuleSets/Tests.cs
new file mode 100644
index 0000000..dc8d5c7
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/RuleSets/Tests.cs
@@ -0,0 +1,50 @@
+using Blazored.FluentValidation.Tests.Model;
+
+namespace Blazored.FluentValidation.Tests.RuleSets;
+
+public class Tests : TestContext
+{
+ private readonly Fixture _fixture = new();
+
+ [Fact]
+ public void AddedByAttribute_PersonFirstNameTooLong_ValidationFails()
+ {
+ // Arrange
+ var person = _fixture.ValidPerson() with
+ {
+ FirstName = "This name is clearly longer than 50 characters and thus should fail."
+ };
+ var cut = RenderComponent(p => p.Add(c => c.IncludeWithCode, true));
+
+ // Act
+ cut.Find("input[name=FirstName]").Change(person.FirstName);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Error);
+ }
+
+ [Fact]
+ public void AddedByAttribute_PersonFirstNameTooLong_ValidationMessagesPresent()
+ {
+ // Arrange
+ var person = _fixture.ValidPerson() with
+ {
+ FirstName = "This name is clearly longer than 50 characters and thus should fail."
+ };
+ var cut = RenderComponent(p => p.Add(c => c.IncludeWithCode, true));
+
+ // Act
+ cut.Find("input[name=FirstName]").Change(person.FirstName);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameMaxLength);
+ cut.Find("li.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameMaxLength);
+ }
+
+ private class Fixture
+ {
+ public Person ValidPerson() => new() { FirstName = "John" };
+ }
+}
\ No newline at end of file
From 7f4c4eb8536f52f429b12680b1390d62a4737288 Mon Sep 17 00:00:00 2001
From: luetm
Date: Wed, 21 Feb 2024 15:57:14 +0100
Subject: [PATCH 07/11] Re-added code I destroyed.
---
.../RuleSets/Component.razor | 22 +++++++--
.../RuleSets/Tests.cs | 45 +++++++++++++++----
2 files changed, 56 insertions(+), 11 deletions(-)
diff --git a/tests/Blazored.FluentValidation.Tests/RuleSets/Component.razor b/tests/Blazored.FluentValidation.Tests/RuleSets/Component.razor
index e8b633b..fa209c7 100644
--- a/tests/Blazored.FluentValidation.Tests/RuleSets/Component.razor
+++ b/tests/Blazored.FluentValidation.Tests/RuleSets/Component.razor
@@ -1,7 +1,7 @@
-
+
@if (IncludeWithAttribute)
{
@* Can't implement.. bugged?
*@
@@ -17,21 +17,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@code {
[Parameter] public bool IncludeWithAttribute { get; set; }
[Parameter] public bool IncludeWithCode { get; set; }
-
+
private readonly Person _person = new();
private FluentValidationValidator? _fluentValidationValidator;
public ValidationResultType? Result { get; private set; }
-
+
protected void Submit()
{
var result = _fluentValidationValidator!.Validate(o => o.IncludeRuleSets("Names"));
Result = result ? ValidationResultType.Valid : ValidationResultType.Error;
}
+
}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/RuleSets/Tests.cs b/tests/Blazored.FluentValidation.Tests/RuleSets/Tests.cs
index dc8d5c7..d0f7ab5 100644
--- a/tests/Blazored.FluentValidation.Tests/RuleSets/Tests.cs
+++ b/tests/Blazored.FluentValidation.Tests/RuleSets/Tests.cs
@@ -6,6 +6,21 @@ public class Tests : TestContext
{
private readonly Fixture _fixture = new();
+ [Fact]
+ public void AddedByAttribute_PersonValid_ValidationPasses()
+ {
+ // Arrange
+ var person = _fixture.ValidPerson();
+ var cut = RenderComponent(p => p.Add(c => c.IncludeWithCode, true));
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Valid);
+ }
+
[Fact]
public void AddedByAttribute_PersonFirstNameTooLong_ValidationFails()
{
@@ -15,15 +30,15 @@ public void AddedByAttribute_PersonFirstNameTooLong_ValidationFails()
FirstName = "This name is clearly longer than 50 characters and thus should fail."
};
var cut = RenderComponent(p => p.Add(c => c.IncludeWithCode, true));
-
+
// Act
- cut.Find("input[name=FirstName]").Change(person.FirstName);
+ FillForm(cut, person);
cut.Find("button").Click();
-
+
// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Error);
}
-
+
[Fact]
public void AddedByAttribute_PersonFirstNameTooLong_ValidationMessagesPresent()
{
@@ -33,18 +48,32 @@ public void AddedByAttribute_PersonFirstNameTooLong_ValidationMessagesPresent()
FirstName = "This name is clearly longer than 50 characters and thus should fail."
};
var cut = RenderComponent(p => p.Add(c => c.IncludeWithCode, true));
-
+
// Act
- cut.Find("input[name=FirstName]").Change(person.FirstName);
+ FillForm(cut, person);
cut.Find("button").Click();
-
+
// Assert
cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameMaxLength);
cut.Find("li.validation-message").TextContent.Should().Contain(PersonValidator.FirstNameMaxLength);
}
+ private static void FillForm(IRenderedComponent cut, Person person)
+ {
+ cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
+ cut.Find($"input[name={nameof(Person.LastName)}]").Change(person.LastName);
+ cut.Find($"input[name={nameof(Person.EmailAddress)}]").Change(person.EmailAddress);
+ cut.Find($"input[name={nameof(Person.Age)}]").Change(person.Age.ToString());
+ }
+
private class Fixture
{
- public Person ValidPerson() => new() { FirstName = "John" };
+ public Person ValidPerson() => new()
+ {
+ FirstName = "John",
+ LastName = "Doe",
+ EmailAddress = "john.doe@blazored.com",
+ Age = 30
+ };
}
}
\ No newline at end of file
From d472eaa9673feaa18042e2a2660dca9035ca4d91 Mon Sep 17 00:00:00 2001
From: luetm
Date: Wed, 21 Feb 2024 16:27:14 +0100
Subject: [PATCH 08/11] Created readme for rule sets. Added tests for
validation failure access.
---
.../FullFailureAccess/AsyncComponent.razor | 55 +++++++++++++
.../FullFailureAccess/AsyncTests.cs | 77 +++++++++++++++++++
.../FullFailureAccess/Readme.md | 5 ++
.../FullFailureAccess/SyncComponent.razor | 54 +++++++++++++
.../FullFailureAccess/SyncTests.cs | 74 ++++++++++++++++++
.../Model/Person.cs | 6 ++
.../RuleSets/Readme.md | 17 ++++
7 files changed, 288 insertions(+)
create mode 100644 tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncComponent.razor
create mode 100644 tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncTests.cs
create mode 100644 tests/Blazored.FluentValidation.Tests/FullFailureAccess/Readme.md
create mode 100644 tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncComponent.razor
create mode 100644 tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncTests.cs
create mode 100644 tests/Blazored.FluentValidation.Tests/RuleSets/Readme.md
diff --git a/tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncComponent.razor b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncComponent.razor
new file mode 100644
index 0000000..144144b
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncComponent.razor
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@code {
+ private readonly Person _person = new();
+ private FluentValidationValidator? _fluentValidationValidator;
+
+ public ValidationResultType? Result { get; private set; }
+
+ protected async Task Submit()
+ {
+ await _fluentValidationValidator!.ValidateAsync();
+ var lastResult = _fluentValidationValidator!.GetFailuresFromLastValidation();
+ if (!lastResult.Any())
+ {
+ Result = ValidationResultType.Valid;
+ }
+ else if (lastResult.Any(failure => failure.Severity == Severity.Error))
+ {
+ Result = ValidationResultType.Error;
+ }
+ else
+ {
+ Result = ValidationResultType.Warning;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncTests.cs b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncTests.cs
new file mode 100644
index 0000000..8491b24
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncTests.cs
@@ -0,0 +1,77 @@
+using System;
+using Blazored.FluentValidation.Tests.Model;
+
+namespace Blazored.FluentValidation.Tests.FullFailureAccess;
+
+public class AsyncTests : TestContext
+{
+ private readonly Fixture _fixture = new();
+
+ [Fact]
+ public void GetFailuresFromLastValidation_PersonValid_ResultIsValid()
+ {
+ // Arrange
+ var person = _fixture.ValidPerson();
+ var cut = RenderComponent();
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+ cut.WaitForState(() => cut.Instance.Result is not null);
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Valid);
+ }
+
+ [Fact]
+ public void GetFailuresFromLastValidation_EmailInvalid_ResultIsError()
+ {
+ // Arrange
+ var person = _fixture.ValidPerson() with { EmailAddress = "invalid-email" };
+ var cut = RenderComponent();
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+ cut.WaitForState(() => cut.Instance.Result is not null);
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Error);
+ }
+
+ [Fact]
+ public void GetFailuresFromLastValidation_AgeSuspect_ResultIsWarning()
+ {
+ // Arrange
+ var person = _fixture.ValidPerson() with { Age = 69 };
+ var cut = RenderComponent();
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+ cut.WaitForState(() => cut.Instance.Result is not null);
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Warning);
+ }
+
+
+ private static void FillForm(IRenderedComponent cut, Person person)
+ {
+ cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
+ cut.Find($"input[name={nameof(Person.LastName)}]").Change(person.LastName);
+ cut.Find($"input[name={nameof(Person.EmailAddress)}]").Change(person.EmailAddress);
+ cut.Find($"input[name={nameof(Person.Age)}]").Change(person.Age.ToString());
+ }
+
+ private class Fixture
+ {
+ public Person ValidPerson() => new()
+ {
+ FirstName = "John",
+ LastName = "Doe",
+ EmailAddress = "john.doe@blazored.com",
+ Age = 30
+ };
+ }
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/FullFailureAccess/Readme.md b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/Readme.md
new file mode 100644
index 0000000..aff880a
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/Readme.md
@@ -0,0 +1,5 @@
+### What does this test?
+This test checks if the `GetFailuresFromLastValidation` method works correctly. It does so by both using `Validate`
+and `ValidateAsync`. The failures given back are then checked for severity.
+
+To test warnings, the age of a person can be set to 69.
diff --git a/tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncComponent.razor b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncComponent.razor
new file mode 100644
index 0000000..4958393
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncComponent.razor
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@code {
+ private readonly Person _person = new();
+ private FluentValidationValidator? _fluentValidationValidator;
+
+ public ValidationResultType? Result { get; private set; }
+
+ protected void Submit()
+ {
+ _fluentValidationValidator!.Validate();
+ var lastResult = _fluentValidationValidator!.GetFailuresFromLastValidation();
+ if (!lastResult.Any())
+ {
+ Result = ValidationResultType.Valid;
+ }
+ else if (lastResult.Any(failure => failure.Severity == Severity.Error))
+ {
+ Result = ValidationResultType.Error;
+ }
+ else
+ {
+ Result = ValidationResultType.Warning;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncTests.cs b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncTests.cs
new file mode 100644
index 0000000..78abfe9
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncTests.cs
@@ -0,0 +1,74 @@
+using System;
+using Blazored.FluentValidation.Tests.Model;
+
+namespace Blazored.FluentValidation.Tests.FullFailureAccess;
+
+public class SyncTests : TestContext
+{
+ private readonly Fixture _fixture = new();
+
+ [Fact]
+ public void GetFailuresFromLastValidation_PersonValid_ResultIsValid()
+ {
+ // Arrange
+ var person = _fixture.ValidPerson();
+ var cut = RenderComponent();
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Valid);
+ }
+
+ [Fact]
+ public void GetFailuresFromLastValidation_EmailInvalid_ResultIsError()
+ {
+ // Arrange
+ var person = _fixture.ValidPerson() with { EmailAddress = "invalid-email" };
+ var cut = RenderComponent();
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Error);
+ }
+
+ [Fact]
+ public void GetFailuresFromLastValidation_AgeSuspect_ResultIsWarning()
+ {
+ // Arrange
+ var person = _fixture.ValidPerson() with { Age = 69 };
+ var cut = RenderComponent();
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Warning);
+ }
+
+
+ private static void FillForm(IRenderedComponent cut, Person person)
+ {
+ cut.Find($"input[name={nameof(Person.FirstName)}]").Change(person.FirstName);
+ cut.Find($"input[name={nameof(Person.LastName)}]").Change(person.LastName);
+ cut.Find($"input[name={nameof(Person.EmailAddress)}]").Change(person.EmailAddress);
+ cut.Find($"input[name={nameof(Person.Age)}]").Change(person.Age.ToString());
+ }
+
+ private class Fixture
+ {
+ public Person ValidPerson() => new()
+ {
+ FirstName = "John",
+ LastName = "Doe",
+ EmailAddress = "john.doe@blazored.com",
+ Age = 30
+ };
+ }
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/Model/Person.cs b/tests/Blazored.FluentValidation.Tests/Model/Person.cs
index 93a61a1..fc8c0f5 100644
--- a/tests/Blazored.FluentValidation.Tests/Model/Person.cs
+++ b/tests/Blazored.FluentValidation.Tests/Model/Person.cs
@@ -18,6 +18,7 @@ public class PersonValidator : AbstractValidator
public const string AgeRequired = "You must enter your age";
public const string AgeMin = "Age must be greater than 0";
public const string AgeMax = "Age cannot be greater than 150";
+ public const string AgeSuspect = "Age is suspect. Troll?";
public const string EmailRequired = "You must enter an email address";
public const string EmailValid = "You must provide a valid email address";
public const string EmailUnique = "Email address must be unique";
@@ -49,6 +50,11 @@ public PersonValidator()
RuleFor(p => p.Address!)
.SetValidator(new AddressValidator())
.When(p => p.Address is not null);
+
+ RuleFor(p => p.Age)
+ .NotEqual(69)
+ .WithMessage(AgeSuspect)
+ .WithSeverity(Severity.Warning);
}
private static async Task IsUniqueAsync(string? email)
diff --git a/tests/Blazored.FluentValidation.Tests/RuleSets/Readme.md b/tests/Blazored.FluentValidation.Tests/RuleSets/Readme.md
new file mode 100644
index 0000000..afc393f
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/RuleSets/Readme.md
@@ -0,0 +1,17 @@
+### What does this test?
+This test checks if using the `IncludeRuleSets..` method work, once by attribute
+
+```html
+
+```
+
+and once by code
+
+```csharp
+@code {
+ private FluentValidationValidator? _fluentValidationValidator;
+
+ private void PartialValidate()
+ => _fluentValidationValidator?.Validate(options => options.IncludeRuleSets("Names"));
+}
+```
\ No newline at end of file
From 898e51b11eeee7b0cc2f2d086ed2b4b7d56b2d13 Mon Sep 17 00:00:00 2001
From: luetm
Date: Wed, 21 Feb 2024 16:32:35 +0100
Subject: [PATCH 09/11] Tested `Validate` in addition to `ValidateAsync`
---
.../AsyncComponent.razor} | 4 +-
.../AsyncTests.cs} | 19 ++---
.../Readme.md | 0
.../DirectValidation/SyncComponent.razor | 39 ++++++++++
.../DirectValidation/SyncTests.cs | 73 +++++++++++++++++++
5 files changed, 124 insertions(+), 11 deletions(-)
rename tests/Blazored.FluentValidation.Tests/{AsyncValidation/Component.razor => DirectValidation/AsyncComponent.razor} (91%)
rename tests/Blazored.FluentValidation.Tests/{AsyncValidation/Tests.cs => DirectValidation/AsyncTests.cs} (77%)
rename tests/Blazored.FluentValidation.Tests/{AsyncValidation => DirectValidation}/Readme.md (100%)
create mode 100644 tests/Blazored.FluentValidation.Tests/DirectValidation/SyncComponent.razor
create mode 100644 tests/Blazored.FluentValidation.Tests/DirectValidation/SyncTests.cs
diff --git a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor b/tests/Blazored.FluentValidation.Tests/DirectValidation/AsyncComponent.razor
similarity index 91%
rename from tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
rename to tests/Blazored.FluentValidation.Tests/DirectValidation/AsyncComponent.razor
index 2acb1a0..c0cafe7 100644
--- a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Component.razor
+++ b/tests/Blazored.FluentValidation.Tests/DirectValidation/AsyncComponent.razor
@@ -1,4 +1,4 @@
-
+
@@ -31,7 +31,7 @@
public ValidationResultType? Result { get; private set; }
- private async Task SubmitFormAsync()
+ private async Task SubmitAsync()
{
var result = await _fluentValidationValidator!.ValidateAsync();
Result = result ? ValidationResultType.Valid : ValidationResultType.Error;
diff --git a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs b/tests/Blazored.FluentValidation.Tests/DirectValidation/AsyncTests.cs
similarity index 77%
rename from tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs
rename to tests/Blazored.FluentValidation.Tests/DirectValidation/AsyncTests.cs
index 453cec4..634efe3 100644
--- a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Tests.cs
+++ b/tests/Blazored.FluentValidation.Tests/DirectValidation/AsyncTests.cs
@@ -1,15 +1,16 @@
using Blazored.FluentValidation.Tests.Model;
-namespace Blazored.FluentValidation.Tests.AsyncValidation;
-public class Tests : TestContext
+namespace Blazored.FluentValidation.Tests.DirectValidation;
+
+public class AsyncTests : TestContext
{
private readonly Fixture _fixture = new();
[Fact]
- public void AsyncValidate_PersonIsValid_ResultIsValid()
+ public void ValidateAsync_PersonIsValid_ResultIsValid()
{
// Arrange
- var cut = RenderComponent();
+ var cut = RenderComponent();
var person = _fixture.ValidPerson();
// Act
@@ -22,10 +23,10 @@ public void AsyncValidate_PersonIsValid_ResultIsValid()
}
[Fact]
- public void AsyncValidate_AgeNegative_ResultIsError()
+ public void ValidateAsync_AgeNegative_ResultIsError()
{
// Arrange
- var cut = RenderComponent();
+ var cut = RenderComponent();
var person = _fixture.ValidPerson() with { Age = -5 };
// Act
@@ -38,10 +39,10 @@ public void AsyncValidate_AgeNegative_ResultIsError()
}
[Fact]
- public void AsyncValidate_AgeNegative_ValidationMessagesPresent()
+ public void ValidateAsync_AgeNegative_ValidationMessagesPresent()
{
// Arrange
- var cut = RenderComponent();
+ var cut = RenderComponent();
var person = _fixture.ValidPerson() with { Age = -5 };
// Act
@@ -54,7 +55,7 @@ public void AsyncValidate_AgeNegative_ValidationMessagesPresent()
cut.Find("li.validation-message").TextContent.Should().Contain(PersonValidator.AgeMin);
}
- private void FillForm(IRenderedComponent cut, Person person)
+ private void FillForm(IRenderedComponent cut, Person person)
{
cut.Find("input[name=FirstName]").Change(person.FirstName);
cut.Find("input[name=LastName]").Change(person.LastName);
diff --git a/tests/Blazored.FluentValidation.Tests/AsyncValidation/Readme.md b/tests/Blazored.FluentValidation.Tests/DirectValidation/Readme.md
similarity index 100%
rename from tests/Blazored.FluentValidation.Tests/AsyncValidation/Readme.md
rename to tests/Blazored.FluentValidation.Tests/DirectValidation/Readme.md
diff --git a/tests/Blazored.FluentValidation.Tests/DirectValidation/SyncComponent.razor b/tests/Blazored.FluentValidation.Tests/DirectValidation/SyncComponent.razor
new file mode 100644
index 0000000..00a73e9
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/DirectValidation/SyncComponent.razor
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@code {
+ private readonly Person _person = new();
+ private FluentValidationValidator? _fluentValidationValidator;
+
+ public ValidationResultType? Result { get; private set; }
+
+ private void Submit()
+ {
+ var result = _fluentValidationValidator!.Validate();
+ Result = result ? ValidationResultType.Valid : ValidationResultType.Error;
+ }
+}
\ No newline at end of file
diff --git a/tests/Blazored.FluentValidation.Tests/DirectValidation/SyncTests.cs b/tests/Blazored.FluentValidation.Tests/DirectValidation/SyncTests.cs
new file mode 100644
index 0000000..cd48fcb
--- /dev/null
+++ b/tests/Blazored.FluentValidation.Tests/DirectValidation/SyncTests.cs
@@ -0,0 +1,73 @@
+using Blazored.FluentValidation.Tests.Model;
+
+namespace Blazored.FluentValidation.Tests.DirectValidation;
+
+public class SyncTests : TestContext
+{
+ private readonly Fixture _fixture = new();
+
+ [Fact]
+ public void Validate_PersonIsValid_ResultIsValid()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson();
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Valid);
+ }
+
+ [Fact]
+ public void Validate_AgeNegative_ResultIsError()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson() with { Age = -5 };
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Instance.Result.Should().Be(ValidationResultType.Error);
+ }
+
+ [Fact]
+ public void Validate_AgeNegative_ValidationMessagesPresent()
+ {
+ // Arrange
+ var cut = RenderComponent();
+ var person = _fixture.ValidPerson() with { Age = -5 };
+
+ // Act
+ FillForm(cut, person);
+ cut.Find("button").Click();
+
+ // Assert
+ cut.Find(".validation-errors>.validation-message").TextContent.Should().Contain(PersonValidator.AgeMin);
+ cut.Find("li.validation-message").TextContent.Should().Contain(PersonValidator.AgeMin);
+ }
+
+ private void FillForm(IRenderedComponent cut, Person person)
+ {
+ cut.Find("input[name=FirstName]").Change(person.FirstName);
+ cut.Find("input[name=LastName]").Change(person.LastName);
+ cut.Find("input[name=Age]").Change(person.Age.ToString());
+ cut.Find("input[name=EmailAddress]").Change(person.EmailAddress);
+ }
+
+ private class Fixture
+ {
+ public Person ValidPerson() => new()
+ {
+ FirstName = "John",
+ LastName = "Doe",
+ Age = 30,
+ EmailAddress = "john.doe@blazored.com"
+ };
+ }
+}
\ No newline at end of file
From d0c91f3cf2c73eba2c31988f9caa13b3d8aa2a7c Mon Sep 17 00:00:00 2001
From: Paul Welter
Date: Tue, 28 May 2024 14:39:30 -0500
Subject: [PATCH 10/11] add .net 8 support
---
.github/workflows/ci-main.yml | 14 ++++++-------
.github/workflows/ci-pr.yml | 2 +-
.../Blazored.FluentValidation.csproj | 16 +++++++++-----
.../EditContextFluentValidationExtensions.cs | 16 +++++++-------
.../FluentValidationsValidator.cs | 14 ++++++-------
.../AssemblyScanning/Component.razor | 8 +++----
.../AssemblyScanning/Tests.cs | 6 +++---
.../BasicValidation/Tests.cs | 10 ++++-----
.../Blazored.FluentValidation.Tests.csproj | 18 ++++++++--------
.../FullFailureAccess/AsyncTests.cs | 18 ++++++++--------
.../FullFailureAccess/SyncTests.cs | 21 +++++++++----------
.../Model/Address.cs | 2 +-
.../Model/Person.cs | 2 +-
13 files changed, 77 insertions(+), 70 deletions(-)
diff --git a/.github/workflows/ci-main.yml b/.github/workflows/ci-main.yml
index b513263..e2e24b6 100644
--- a/.github/workflows/ci-main.yml
+++ b/.github/workflows/ci-main.yml
@@ -7,7 +7,7 @@ on:
types: [ published ]
env:
- NETCORE_VERSION: '7.0.x'
+ NETCORE_VERSION: '8.0.x'
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
PROJECT_NAME: FluentValidation
@@ -42,12 +42,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
-
+
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: ${{ env.NETCORE_VERSION }}
-
+
- name: Create Release NuGet package
run: |
arrTag=(${GITHUB_REF//\// })
@@ -56,17 +56,17 @@ jobs:
VERSION="${VERSION:1}"
echo Clean Version: $VERSION
dotnet pack -v normal -c Release --include-symbols --include-source -p:PackageVersion=$VERSION -o nupkg src/Blazored.$PROJECT_NAME/Blazored.$PROJECT_NAME.csproj
-
+
- name: Push to NuGet Feed
run: dotnet nuget push ./nupkg/*.nupkg --source $NUGET_FEED --api-key $NUGET_KEY --skip-duplicate
-
+
- name: Publish Sample Site
run: dotnet publish -c Release samples/BlazorWebAssembly/BlazorWebAssembly.csproj
- name: Rewrite base href
uses: SteveSandersonMS/ghaction-rewrite-base-href@v1
with:
- html_path: samples/BlazorWebAssembly/bin/Release/net7.0/publish/wwwroot/index.html
+ html_path: samples/BlazorWebAssembly/bin/Release/net8.0/publish/wwwroot/index.html
base_href: /${{ env.PROJECT_NAME }}/
- name: Deploy to Github Pages
@@ -75,5 +75,5 @@ jobs:
ACCESS_TOKEN: $GITHUB_TOKEN
BASE_BRANCH: main # The branch the action should deploy from.
BRANCH: gh-pages # The branch the action should deploy to.
- FOLDER: samples/BlazorWebAssembly/bin/Release/net7.0/publish/wwwroot # The folder the action should deploy.
+ FOLDER: samples/BlazorWebAssembly/bin/Release/net8.0/publish/wwwroot # The folder the action should deploy.
SINGLE_COMMIT: true
diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml
index f3b4f98..864f0cf 100644
--- a/.github/workflows/ci-pr.yml
+++ b/.github/workflows/ci-pr.yml
@@ -6,7 +6,7 @@ on:
env:
PROJECT_NAME: Blazored.FluentValidation
- NETCORE_VERSION: '7.0.x'
+ NETCORE_VERSION: '8.0.x'
jobs:
build:
diff --git a/src/Blazored.FluentValidation/Blazored.FluentValidation.csproj b/src/Blazored.FluentValidation/Blazored.FluentValidation.csproj
index 90ebca6..8add0c8 100644
--- a/src/Blazored.FluentValidation/Blazored.FluentValidation.csproj
+++ b/src/Blazored.FluentValidation/Blazored.FluentValidation.csproj
@@ -1,7 +1,7 @@
- net6.0;net7.0
+ net6.0;net7.0;net8.0
enable
enable
@@ -31,14 +31,20 @@
+
+
+
+
-
-
+
-
-
+
+
+
+
+
diff --git a/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs b/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs
index 7ab8ab8..755a44b 100644
--- a/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs
+++ b/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs
@@ -1,8 +1,10 @@
using FluentValidation;
using FluentValidation.Internal;
using FluentValidation.Results;
+
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.Extensions.DependencyInjection;
+
using static FluentValidation.AssemblyScanner;
namespace Blazored.FluentValidation;
@@ -59,12 +61,12 @@ private static async Task ValidateModel(EditContext editContext,
messages.Clear();
fluentValidationValidator.LastValidationResult = new Dictionary>();
-
+
foreach (var validationResult in validationResults.Errors)
{
var fieldIdentifier = ToFieldIdentifier(editContext, validationResult.PropertyName);
messages.Add(fieldIdentifier, validationResult.ErrorMessage);
-
+
if (fluentValidationValidator.LastValidationResult.TryGetValue(fieldIdentifier, out var failures))
{
failures.Add(validationResult);
@@ -88,7 +90,7 @@ private static async Task ValidateField(EditContext editContext,
{
var properties = new[] { fieldIdentifier.FieldName };
var context = new ValidationContext
-
+
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
+
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncTests.cs b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncTests.cs
index 8491b24..aa6eb0a 100644
--- a/tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncTests.cs
+++ b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/AsyncTests.cs
@@ -13,48 +13,48 @@ public void GetFailuresFromLastValidation_PersonValid_ResultIsValid()
// Arrange
var person = _fixture.ValidPerson();
var cut = RenderComponent();
-
+
// Act
FillForm(cut, person);
cut.Find("button").Click();
cut.WaitForState(() => cut.Instance.Result is not null);
-
+
// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Valid);
}
-
+
[Fact]
public void GetFailuresFromLastValidation_EmailInvalid_ResultIsError()
{
// Arrange
var person = _fixture.ValidPerson() with { EmailAddress = "invalid-email" };
var cut = RenderComponent();
-
+
// Act
FillForm(cut, person);
cut.Find("button").Click();
cut.WaitForState(() => cut.Instance.Result is not null);
-
+
// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Error);
}
-
+
[Fact]
public void GetFailuresFromLastValidation_AgeSuspect_ResultIsWarning()
{
// Arrange
var person = _fixture.ValidPerson() with { Age = 69 };
var cut = RenderComponent();
-
+
// Act
FillForm(cut, person);
cut.Find("button").Click();
cut.WaitForState(() => cut.Instance.Result is not null);
-
+
// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Warning);
}
-
+
private static void FillForm(IRenderedComponent cut, Person person)
{
diff --git a/tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncTests.cs b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncTests.cs
index 78abfe9..107708b 100644
--- a/tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncTests.cs
+++ b/tests/Blazored.FluentValidation.Tests/FullFailureAccess/SyncTests.cs
@@ -1,5 +1,4 @@
-using System;
-using Blazored.FluentValidation.Tests.Model;
+using Blazored.FluentValidation.Tests.Model;
namespace Blazored.FluentValidation.Tests.FullFailureAccess;
@@ -13,45 +12,45 @@ public void GetFailuresFromLastValidation_PersonValid_ResultIsValid()
// Arrange
var person = _fixture.ValidPerson();
var cut = RenderComponent();
-
+
// Act
FillForm(cut, person);
cut.Find("button").Click();
-
+
// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Valid);
}
-
+
[Fact]
public void GetFailuresFromLastValidation_EmailInvalid_ResultIsError()
{
// Arrange
var person = _fixture.ValidPerson() with { EmailAddress = "invalid-email" };
var cut = RenderComponent();
-
+
// Act
FillForm(cut, person);
cut.Find("button").Click();
-
+
// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Error);
}
-
+
[Fact]
public void GetFailuresFromLastValidation_AgeSuspect_ResultIsWarning()
{
// Arrange
var person = _fixture.ValidPerson() with { Age = 69 };
var cut = RenderComponent();
-
+
// Act
FillForm(cut, person);
cut.Find("button").Click();
-
+
// Assert
cut.Instance.Result.Should().Be(ValidationResultType.Warning);
}
-
+
private static void FillForm(IRenderedComponent cut, Person person)
{
diff --git a/tests/Blazored.FluentValidation.Tests/Model/Address.cs b/tests/Blazored.FluentValidation.Tests/Model/Address.cs
index d7a5332..0eeebc2 100644
--- a/tests/Blazored.FluentValidation.Tests/Model/Address.cs
+++ b/tests/Blazored.FluentValidation.Tests/Model/Address.cs
@@ -15,7 +15,7 @@ public class AddressValidator : AbstractValidator
public const string TownRequired = "You must enter a town";
public const string CountyRequired = "You must enter a county";
public const string PostcodeRequired = "You must enter a postcode";
-
+
public AddressValidator()
{
RuleFor(p => p.Line1).NotEmpty().WithMessage(Line1Required);
diff --git a/tests/Blazored.FluentValidation.Tests/Model/Person.cs b/tests/Blazored.FluentValidation.Tests/Model/Person.cs
index fc8c0f5..0ab6ca6 100644
--- a/tests/Blazored.FluentValidation.Tests/Model/Person.cs
+++ b/tests/Blazored.FluentValidation.Tests/Model/Person.cs
@@ -23,7 +23,7 @@ public class PersonValidator : AbstractValidator
public const string EmailValid = "You must provide a valid email address";
public const string EmailUnique = "Email address must be unique";
public const string DuplicateEmail = "mail@my.com";
-
+
public PersonValidator()
{
RuleSet("Names", () =>
From 9b9834a76446cfaf3a64937805bfe1603f212ea2 Mon Sep 17 00:00:00 2001
From: Jason Finch
Date: Mon, 1 Jul 2024 08:25:55 +1000
Subject: [PATCH 11/11] -task (net8): Add net8 target to BlazorServer,
SharedModels. Bump FluentValidation to 11.9.2
---
samples/BlazorServer/BlazorServer.csproj | 2 +-
samples/BlazorWebAssembly/BlazorWebAssembly.csproj | 9 +++++++--
samples/Shared/SharedModels/SharedModels.csproj | 4 ++--
.../Blazored.FluentValidation.csproj | 2 +-
.../Blazored.FluentValidation.Tests.csproj | 2 +-
5 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/samples/BlazorServer/BlazorServer.csproj b/samples/BlazorServer/BlazorServer.csproj
index 4b3ab49..5056724 100644
--- a/samples/BlazorServer/BlazorServer.csproj
+++ b/samples/BlazorServer/BlazorServer.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net6.0;net7.0;net8.0
enable
enable
diff --git a/samples/BlazorWebAssembly/BlazorWebAssembly.csproj b/samples/BlazorWebAssembly/BlazorWebAssembly.csproj
index 8ee79b3..7c8cf58 100644
--- a/samples/BlazorWebAssembly/BlazorWebAssembly.csproj
+++ b/samples/BlazorWebAssembly/BlazorWebAssembly.csproj
@@ -1,16 +1,21 @@
- net7.0
+ net7.0;net8.0
enable
enable
-
+
+
+
+
+
+
diff --git a/samples/Shared/SharedModels/SharedModels.csproj b/samples/Shared/SharedModels/SharedModels.csproj
index 0337b08..7492bff 100644
--- a/samples/Shared/SharedModels/SharedModels.csproj
+++ b/samples/Shared/SharedModels/SharedModels.csproj
@@ -1,13 +1,13 @@
- net7.0
+ net6.0;net7.0;net8.0
enable
enable
-
+
diff --git a/src/Blazored.FluentValidation/Blazored.FluentValidation.csproj b/src/Blazored.FluentValidation/Blazored.FluentValidation.csproj
index 8add0c8..8d700f4 100644
--- a/src/Blazored.FluentValidation/Blazored.FluentValidation.csproj
+++ b/src/Blazored.FluentValidation/Blazored.FluentValidation.csproj
@@ -32,7 +32,7 @@
-
+
diff --git a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
index 495a7b2..c97d6b1 100644
--- a/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
+++ b/tests/Blazored.FluentValidation.Tests/Blazored.FluentValidation.Tests.csproj
@@ -16,7 +16,7 @@
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive