Skip to content

Commit

Permalink
Add tests for SetNullResultOnValidationError option
Browse files Browse the repository at this point in the history
  • Loading branch information
benmccallum committed Jun 14, 2021
1 parent fc3a65b commit a05871e
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 124 deletions.
247 changes: 123 additions & 124 deletions src/FairyBread.Tests/CustomizationTests.cs
Original file line number Diff line number Diff line change
@@ -1,124 +1,123 @@
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Threading.Tasks;
//using FluentValidation;
//using FluentValidation.Results;
//using HotChocolate;
//using HotChocolate.Execution;
//using HotChocolate.Language;
//using HotChocolate.Resolvers;
//using HotChocolate.Types;
//using Microsoft.Extensions.DependencyInjection;
//using VerifyXunit;
//using Xunit;

//namespace FairyBread.Tests
//{
// [UsesVerify]
// public class CustomizationTests
// {
// private const string Query = @"query { read(foo: { someInteger: 1, someString: ""hello"" }) }";

// private static async Task<IRequestExecutor> GetRequestExecutorAsync(
// Action<IServiceCollection> preBuildProviderAction)
// {
// var services = new ServiceCollection();
// services.AddValidatorsFromAssemblyContaining<CustomValidator>();
// preBuildProviderAction?.Invoke(services);

// return await services
// .AddGraphQL()
// .AddQueryType<QueryType>()
// .AddMutationType<MutationType>()
// .AddFairyBread(options =>
// {
// options.AssembliesToScanForValidators = new[] { typeof(CustomValidator).Assembly };
// options.ShouldValidate = (ctx, arg) => ctx.Operation.Operation == OperationType.Query;
// })
// .BuildRequestExecutorAsync();
// }

// [Fact]
// public async Task CustomValidationResultHandler_Works()
// {
// // Arrange
// var executor = await GetRequestExecutorAsync(services =>
// {
// services.AddSingleton<IValidationErrorsHandler, CustomValidationErrorsHandler>();
// });

// // Act
// var result = await executor.ExecuteAsync(Query);

// // Assert
// Assert.NotNull(result.Errors);
// Assert.NotEmpty(result.Errors);
// Assert.True(result.Errors!.All(e => e.Message == "lol"));
// }

// public class CustomValidationErrorsHandler : DefaultValidationErrorsHandler
// {
// protected override IErrorBuilder CreateErrorBuilder(IMiddlewareContext context, ValidationFailure failure) =>
// base.CreateErrorBuilder(context, failure)
// .SetMessage("lol");
// }

// [Fact]
// public async Task CustomValidatorProvider_Works()
// {
// // Arrange
// var executor = await GetRequestExecutorAsync(services =>
// {
// services.AddSingleton<IValidatorProvider, CustomValidatorProvider>();
// });

// // Act
// var result = await executor.ExecuteAsync(Query);

// // Assert
// await Verifier.Verify(result);
// }

// public class CustomValidatorProvider : DefaultValidatorProvider
// {
// public CustomValidatorProvider(IServiceProvider serviceProvider, IFairyBreadOptions options)
// : base(serviceProvider, options) { }

// public override IEnumerable<ResolvedValidator> GetValidators(IMiddlewareContext context, IInputField argument)
// => argument.RuntimeType == typeof(FooInputDto)
// ? (new ResolvedValidator[] { new ResolvedValidator(new CustomValidator()) })
// : base.GetValidators(context, argument);
// }

// public class QueryType
// {
// public string Read(FooInputDto foo) => $"{foo};";
// }

// public class MutationType
// {
// public string Write(FooInputDto foo) => $"{foo};";
// }

// public class FooInputDto
// {
// public int SomeInteger { get; set; }

// public string SomeString { get; set; } = "";

// public override string ToString() =>
// $"SomeInteger: {SomeInteger}, " +
// $"SomeString: {SomeString}";
// }

// public class CustomValidator : AbstractValidator<FooInputDto>
// {
// public CustomValidator()
// {
// RuleFor(x => x.SomeInteger)
// .GreaterThanOrEqualTo(999);
// }
// }
// }
//}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using FluentValidation;
using FluentValidation.Results;
using HotChocolate;
using HotChocolate.Execution;
using HotChocolate.Language;
using HotChocolate.Resolvers;
using HotChocolate.Types;
using Microsoft.Extensions.DependencyInjection;
using VerifyXunit;
using Xunit;

namespace FairyBread.Tests
{
[UsesVerify]
public class CustomizationTests
{
private const string Query = @"query { read(foo: { someInteger: 1, someString: ""hello"" }) }";

private static async Task<IRequestExecutor> GetRequestExecutorAsync(
Action<IServiceCollection> preBuildProviderAction)
{
var services = new ServiceCollection();
services.AddValidatorsFromAssemblyContaining<CustomValidator>();
preBuildProviderAction?.Invoke(services);

return await services
.AddGraphQL()
.AddQueryType<QueryType>()
.AddMutationType<MutationType>()
.AddFairyBread(options =>
{
options.ShouldValidate = (ctx, arg) => ctx.Operation.Operation == OperationType.Query;
})
.BuildRequestExecutorAsync();
}

[Fact]
public async Task CustomValidationResultHandler_Works()
{
// Arrange
var executor = await GetRequestExecutorAsync(services =>
{
services.AddSingleton<IValidationErrorsHandler, CustomValidationErrorsHandler>();
});

// Act
var result = await executor.ExecuteAsync(Query);

// Assert
Assert.NotNull(result.Errors);
Assert.NotEmpty(result.Errors);
Assert.True(result.Errors!.All(e => e.Message == "lol"));
}

public class CustomValidationErrorsHandler : DefaultValidationErrorsHandler
{
protected override IErrorBuilder CreateErrorBuilder(IMiddlewareContext context, ValidationFailure failure) =>
base.CreateErrorBuilder(context, failure)
.SetMessage("lol");
}

[Fact]
public async Task CustomValidatorProvider_Works()
{
// Arrange
var executor = await GetRequestExecutorAsync(services =>
{
services.AddSingleton<IValidatorProvider, CustomValidatorProvider>();
});

// Act
var result = await executor.ExecuteAsync(Query);

// Assert
await Verifier.Verify(result);
}

public class CustomValidatorProvider : DefaultValidatorProvider
{
public CustomValidatorProvider(IServiceProvider serviceProvider, IFairyBreadOptions options)
: base(null!) { }

public override IEnumerable<ResolvedValidator> GetValidators(IMiddlewareContext context, IInputField argument)
=> argument.RuntimeType == typeof(FooInputDto)
? (new ResolvedValidator[] { new ResolvedValidator(new CustomValidator()) })
: base.GetValidators(context, argument);
}

public class QueryType
{
public string Read(FooInputDto foo) => $"{foo};";
}

public class MutationType
{
public string Write(FooInputDto foo) => $"{foo};";
}

public class FooInputDto
{
public int SomeInteger { get; set; }

public string SomeString { get; set; } = "";

public override string ToString() =>
$"SomeInteger: {SomeInteger}, " +
$"SomeString: {SomeString}";
}

public class CustomValidator : AbstractValidator<FooInputDto>
{
public CustomValidator()
{
RuleFor(x => x.SomeInteger)
.GreaterThanOrEqualTo(999);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
Data: {
read: 'Custom set result on error'
}
}
43 changes: 43 additions & 0 deletions src/FairyBread.Tests/InputValidationMiddlewareTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
using System.Linq;
using System.Threading.Tasks;
using FluentValidation;
using FluentValidation.Results;
using HotChocolate;
using HotChocolate.Execution;
using HotChocolate.Language;
using HotChocolate.Resolvers;
using HotChocolate.Types;
using Microsoft.Extensions.DependencyInjection;
using VerifyTests;
Expand Down Expand Up @@ -209,6 +211,39 @@ public async Task Should_Respect_ThrowIfNoValidatorsFound_Option(bool throwIfNoV
await Verifier.Verify(result, verifySettings);
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task Should_Respect_SetNullResultOnValidationError_Option(bool setNullResultOnValidationError)
{
// Arrange
var executor = await GetRequestExecutorAsync(
options =>
{
options.SetNullResultOnValidationError = setNullResultOnValidationError;
options.ShouldValidate = (ctx, arg) => ctx.Operation.Operation == OperationType.Query;
},
services =>
{
// Support those wanting to write data to context.Result in a custom
// `IValidationErrorsHandler` implementation
if (!setNullResultOnValidationError)
{
services.AddSingleton<IValidationErrorsHandler, CustomValidationErrorsHandler>();
}
});

var query = @"query { read(foo: { someInteger: -1, someString: ""hello"" }) }";

// Act
var result = await executor.ExecuteAsync(query);

// Assert
var verifySettings = new VerifySettings();
verifySettings.UseParameters(setNullResultOnValidationError);
await Verifier.Verify(result, verifySettings);
}

// TODO: Unit tests for:
// - cancellation

Expand Down Expand Up @@ -325,5 +360,13 @@ public BarInputDtoAsyncValidator()
.MustAsync((val, cancellationToken) => Task.FromResult(val == "[email protected]"));
}
}

public class CustomValidationErrorsHandler : IValidationErrorsHandler
{
public void Handle(IMiddlewareContext context, IEnumerable<ValidationResult> invalidResults)
{
context.Result = "Custom set result on error";
}
}
}
}

0 comments on commit a05871e

Please sign in to comment.