Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hexabit main #222

Closed
wants to merge 10 commits into from
17 changes: 17 additions & 0 deletions Blazored.FluentValidation.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<EditForm
Model="@_person"
OnValidSubmit="ValidSubmit"
OnInvalidSubmit="InvalidSubmit">

@if (DisableAssemblyScanning is null)
{
<FluentValidationValidator />
}
else
{
<FluentValidationValidator DisableAssemblyScanning="DisableAssemblyScanning.Value" />
}

<ValidationSummary/>

<p>
<label>First name: </label>
<InputText name="@nameof(_person.FirstName)" @bind-Value="@_person.FirstName"/>
</p>

<button type="submit">Save</button>
</EditForm>

@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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
### 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.
- Setting the `DisableAssemblyScanning` to `true` and registering the validators manually should
find the validators and validate normally.
80 changes: 80 additions & 0 deletions tests/Blazored.FluentValidation.Tests/AssemblyScanning/Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
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<Component>(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<Component>(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<Component>(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);
}

[Fact]
public void DisableAssemblyScanning_SetToTrueButValidatorsRegistered_ValidationHappens()
{
// Arrange
Services.AddTransient<AbstractValidator<Person>, PersonValidator>();
var cut = RenderComponent<Component>(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 = "[email protected]",
Age = 30
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<EditForm
Model="@_person"
OnValidSubmit="ValidSubmit"
OnInvalidSubmit="InvalidSubmit">

<FluentValidationValidator/>
<ValidationSummary/>

<p>
<label>First name: </label>
<InputText name="@nameof(_person.FirstName)" @bind-Value="@_person.FirstName"/>
</p>

<p>
<label>Last name: </label>
<InputText name="@nameof(_person.LastName)" @bind-Value="@_person.LastName"/>
</p>

<p>
<label>Age: </label>
<InputNumber name="@nameof(_person.Age)" @bind-Value="@_person.Age"/>
</p>

<p>
<label>Email Address: </label>
<InputText name="@nameof(_person.EmailAddress)" @bind-Value="@_person.EmailAddress"/>
</p>

<p>
<label>Address Line 1: </label>
<InputText name="@nameof(_person.Address.Line1)" @bind-Value="@_person.Address!.Line1"/>
</p>

<button type="submit">Save</button>
</EditForm>

@code {
private readonly Person _person = new() { Address = new() };
internal ValidationResultType Result { get; private set; } = ValidationResultType.Valid;

private void ValidSubmit() => Result = ValidationResultType.Valid;
private void InvalidSubmit() => Result = ValidationResultType.Error;
}
Original file line number Diff line number Diff line change
@@ -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?
110 changes: 110 additions & 0 deletions tests/Blazored.FluentValidation.Tests/BasicValidation/Tests.cs
Original file line number Diff line number Diff line change
@@ -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<Component>();
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<Component>();
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<Component>();
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<Component>();
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<Component>();
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<Component> 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 = "[email protected]",
Age = 30,
Address = new()
{
Line1 = "123 Main St",
Town = "Springfield",
Postcode = "12345"
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<Using Include="Bunit" />
<Using Include="Bunit.TestDoubles" />
<Using Include="Microsoft.Extensions.DependencyInjection" />
<Using Include="Xunit"/>
</ItemGroup>

<ItemGroup>
<PackageReference Include="bunit" Version="1.26.64" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="FluentValidation" Version="11.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<PackageReference Include="xunit" Version="2.6.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Blazored.FluentValidation\Blazored.FluentValidation.csproj" />
</ItemGroup>



</Project>
Loading
Loading