diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java index 35f7147f..47e5f9df 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java @@ -203,13 +203,19 @@ class DefaultGraphQlTester implements GraphQlTester { this.assertDecorator.accept(task); } - void filterErrors(@Nullable Predicate predicate) { + boolean filterErrors(@Nullable Predicate predicate) { + boolean filtered = false; if (predicate != null) { - this.errors.forEach((error) -> { - // Error marked "filtered" if true - error.applyErrorFilterPredicate(predicate); - }); + for (TestGraphQlError error : this.errors) { + filtered |= error.apply(predicate); + } } + return filtered; + } + + void expectErrors(@Nullable Predicate predicate) { + boolean filtered = filterErrors(predicate); + this.assertDecorator.accept(() -> AssertionErrors.assertTrue("No matching errors.", filtered)); } void consumeErrors(Consumer> consumer) { @@ -265,6 +271,12 @@ class DefaultGraphQlTester implements GraphQlTester { return this; } + @Override + public ErrorSpec expect(Predicate predicate) { + this.responseContainer.expectErrors(predicate); + return this; + } + @Override public TraverseSpec verify() { this.responseContainer.verifyErrors(); diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java index ef123463..cd575a6b 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java @@ -90,10 +90,8 @@ public interface GraphQlTester { interface Builder> { /** - * Add a global filter for expected errors. All errors that match the - * given predicate are treated as expected and ignored on - * {@link GraphQlTester.ErrorSpec#verify()} or when - * {@link TraverseSpec#path(String) traversing} to a data path. + * Configure a global {@link ErrorSpec#filter(Predicate) filter} that + * applies to all requests. * @param predicate the error filter to add * @return the same builder instance */ @@ -450,14 +448,32 @@ public interface GraphQlTester { interface ErrorSpec { /** - * Add a filter for expected errors. All errors that match the predicate are - * treated as expected and ignored on {@link #verify()} or when + * Use this to filter out errors that are expected and can be ignored. + * This can be useful for warnings or other notifications returned along + * with the data. + *

The configured filters are applied to all errors. Those that match + * are treated as expected and are ignored on {@link #verify()} or when * {@link TraverseSpec#path(String) traversing} to a data path. + *

In contrast to {@link #expect(Predicate)}, filters do not have to + * match any errors, and don't imply that the errors must be present. * @param errorPredicate the error filter to add * @return the same spec to add more filters before {@link #verify()} */ ErrorSpec filter(Predicate errorPredicate); + /** + * Use this to declare errors that are expected. + *

Errors that match are treated as expected and are ignored on + * {@link #verify()} or when {@link TraverseSpec#path(String) traversing} + * to a data path. + *

In contrast to {@link #filter(Predicate)}, use of this option + * does imply that errors are present or else an {@link AssertionError} + * is raised. + * @param errorPredicate the predicate for the expected error + * @return the same spec to add more filters or expected errors + */ + ErrorSpec expect(Predicate errorPredicate); + /** * Verify there are either no errors or that there no unexpected errors that have * not been {@link #filter(Predicate) filtered out}. diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TestGraphQlError.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TestGraphQlError.java index eec9e3ec..ae758ceb 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TestGraphQlError.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TestGraphQlError.java @@ -148,9 +148,12 @@ final class TestGraphQlError implements GraphQLError { /** * Mark this error as expected if it matches the predicate. * @param predicate the error predicate + * @return whether the predicate matched */ - void applyErrorFilterPredicate(Predicate predicate) { - this.expected |= predicate.test(this); + boolean apply(Predicate predicate) { + boolean match = predicate.test(this); + this.expected |= match; + return match; } @Override diff --git a/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/GraphQlTesterTests.java b/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/GraphQlTesterTests.java index d287b414..78790c77 100644 --- a/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/GraphQlTesterTests.java +++ b/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/GraphQlTesterTests.java @@ -276,6 +276,40 @@ public class GraphQlTesterTests { assertThat(this.inputCaptor.getValue().getQuery()).contains(query); } + @Test + void errorsExpected() throws Exception { + + String query = "{me {name, friends}}"; + setResponse( + GraphqlErrorBuilder.newError().message("some error").build(), + GraphqlErrorBuilder.newError().message("some other error").build()); + + this.graphQlTester.query(query) + .execute() + .errors() + .expect((error) -> error.getMessage().startsWith("some ")) + .verify() + .path("me") + .pathDoesNotExist(); + + assertThat(this.inputCaptor.getValue().getQuery()).contains(query); + } + + @Test + void errorsExpectedButNotFound() throws Exception { + + String query = "{me {name, friends}}"; + setResponse( + GraphqlErrorBuilder.newError().message("some error").build(), + GraphqlErrorBuilder.newError().message("some other error").build()); + + assertThatThrownBy(() -> + this.graphQlTester.query(query) + .execute() + .errors().expect((error) -> error.getMessage().startsWith("another "))) + .hasMessageStartingWith("No matching errors."); + } + @Test void errorsConsumed() throws Exception {