From a05871e5c6b22d564493cd97786003db3f75393b Mon Sep 17 00:00:00 2001 From: Ben McCallum Date: Mon, 14 Jun 2021 10:11:15 +0200 Subject: [PATCH] Add tests for SetNullResultOnValidationError option --- src/FairyBread.Tests/CustomizationTests.cs | 247 +++++++++--------- ...ResultOnValidationError=False.verified.txt | 5 + ...ResultOnValidationError=True.verified.txt} | 0 .../InputValidationMiddlewareTests.cs | 43 +++ 4 files changed, 171 insertions(+), 124 deletions(-) create mode 100644 src/FairyBread.Tests/InputValidationMiddlewareTests.Should_Respect_SetNullResultOnValidationError_Option_setNullResultOnValidationError=False.verified.txt rename src/FairyBread.Tests/{InputValidationMiddlewareTests.Should_Respect_AssembliesToScanForValidators_Option.verified.txt => InputValidationMiddlewareTests.Should_Respect_SetNullResultOnValidationError_Option_setNullResultOnValidationError=True.verified.txt} (100%) diff --git a/src/FairyBread.Tests/CustomizationTests.cs b/src/FairyBread.Tests/CustomizationTests.cs index d565cc6..5e6ea09 100644 --- a/src/FairyBread.Tests/CustomizationTests.cs +++ b/src/FairyBread.Tests/CustomizationTests.cs @@ -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 GetRequestExecutorAsync( -// Action preBuildProviderAction) -// { -// var services = new ServiceCollection(); -// services.AddValidatorsFromAssemblyContaining(); -// preBuildProviderAction?.Invoke(services); - -// return await services -// .AddGraphQL() -// .AddQueryType() -// .AddMutationType() -// .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(); -// }); - -// // 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(); -// }); - -// // 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 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 -// { -// 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 GetRequestExecutorAsync( + Action preBuildProviderAction) + { + var services = new ServiceCollection(); + services.AddValidatorsFromAssemblyContaining(); + preBuildProviderAction?.Invoke(services); + + return await services + .AddGraphQL() + .AddQueryType() + .AddMutationType() + .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(); + }); + + // 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(); + }); + + // 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 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 + { + public CustomValidator() + { + RuleFor(x => x.SomeInteger) + .GreaterThanOrEqualTo(999); + } + } + } +} diff --git a/src/FairyBread.Tests/InputValidationMiddlewareTests.Should_Respect_SetNullResultOnValidationError_Option_setNullResultOnValidationError=False.verified.txt b/src/FairyBread.Tests/InputValidationMiddlewareTests.Should_Respect_SetNullResultOnValidationError_Option_setNullResultOnValidationError=False.verified.txt new file mode 100644 index 0000000..2d57d1a --- /dev/null +++ b/src/FairyBread.Tests/InputValidationMiddlewareTests.Should_Respect_SetNullResultOnValidationError_Option_setNullResultOnValidationError=False.verified.txt @@ -0,0 +1,5 @@ +{ + Data: { + read: 'Custom set result on error' + } +} \ No newline at end of file diff --git a/src/FairyBread.Tests/InputValidationMiddlewareTests.Should_Respect_AssembliesToScanForValidators_Option.verified.txt b/src/FairyBread.Tests/InputValidationMiddlewareTests.Should_Respect_SetNullResultOnValidationError_Option_setNullResultOnValidationError=True.verified.txt similarity index 100% rename from src/FairyBread.Tests/InputValidationMiddlewareTests.Should_Respect_AssembliesToScanForValidators_Option.verified.txt rename to src/FairyBread.Tests/InputValidationMiddlewareTests.Should_Respect_SetNullResultOnValidationError_Option_setNullResultOnValidationError=True.verified.txt diff --git a/src/FairyBread.Tests/InputValidationMiddlewareTests.cs b/src/FairyBread.Tests/InputValidationMiddlewareTests.cs index 38f8ecd..d8cface 100644 --- a/src/FairyBread.Tests/InputValidationMiddlewareTests.cs +++ b/src/FairyBread.Tests/InputValidationMiddlewareTests.cs @@ -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; @@ -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(); + } + }); + + 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 @@ -325,5 +360,13 @@ public BarInputDtoAsyncValidator() .MustAsync((val, cancellationToken) => Task.FromResult(val == "ben@lol.com")); } } + + public class CustomValidationErrorsHandler : IValidationErrorsHandler + { + public void Handle(IMiddlewareContext context, IEnumerable invalidResults) + { + context.Result = "Custom set result on error"; + } + } } }