diff --git a/spring-graphql-test/build.gradle b/spring-graphql-test/build.gradle index 8423b255..cf22ea3a 100644 --- a/spring-graphql-test/build.gradle +++ b/spring-graphql-test/build.gradle @@ -2,6 +2,7 @@ plugins { id 'io.spring.dependency-management' version '1.0.10.RELEASE' id 'java-library' + id "org.springframework.graphql.conventions" } description = "Spring Support for Testing GraphQL Applications" 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 49cdf37e..d1aef807 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 @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.test.tester; import java.net.URI; @@ -61,6 +62,8 @@ import org.springframework.util.StringUtils; /** * Default implementation of {@link GraphQlTester}. + * + * @author Rossen Stoyanchev */ class DefaultGraphQlTester implements GraphQlTester { @@ -68,16 +71,14 @@ class DefaultGraphQlTester implements GraphQlTester { static { ClassLoader classLoader = DefaultGraphQlTester.class.getClassLoader(); - jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && - ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader); + jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) + && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader); } - private final RequestStrategy requestStrategy; private final Configuration jsonPathConfig; - DefaultGraphQlTester(WebTestClient client) { this.jsonPathConfig = initJsonPathConfig(); this.requestStrategy = new WebTestClientRequestStrategy(client, this.jsonPathConfig); @@ -92,13 +93,11 @@ class DefaultGraphQlTester implements GraphQlTester { return (jackson2Present ? Jackson2Configuration.create() : Configuration.builder().build()); } - @Override public RequestSpec query(String query) { return new DefaultRequestSpec(query); } - /** * Encapsulate how a GraphQL request is performed. */ @@ -106,21 +105,24 @@ class DefaultGraphQlTester implements GraphQlTester { /** * Perform a request with the given {@link RequestInput} container. + * @param input the request input + * @return the response spec */ GraphQlTester.ResponseSpec execute(RequestInput input); /** * Perform a subscription with the given {@link RequestInput} container. + * @param input the request input + * @return the subscription spec */ GraphQlTester.SubscriptionSpec executeSubscription(RequestInput input); } - /** - * {@link RequestStrategy} that works as an HTTP client with requests - * executed through {@link WebTestClient} that in turn may work connect with - * or without a live server for Spring MVC and WebFlux. + * {@link RequestStrategy} that works as an HTTP client with requests executed through + * {@link WebTestClient} that in turn may work connect with or without a live server + * for Spring MVC and WebFlux. */ private static class WebTestClientRequestStrategy implements RequestStrategy { @@ -135,14 +137,9 @@ class DefaultGraphQlTester implements GraphQlTester { @Override public ResponseSpec execute(RequestInput requestInput) { - EntityExchangeResult result = this.client.post() - .contentType(MediaType.APPLICATION_JSON) - .bodyValue(requestInput) - .exchange() - .expectStatus().isOk() - .expectHeader().contentType(MediaType.APPLICATION_JSON) - .expectBody() - .returnResult(); + EntityExchangeResult result = this.client.post().contentType(MediaType.APPLICATION_JSON) + .bodyValue(requestInput).exchange().expectStatus().isOk().expectHeader() + .contentType(MediaType.APPLICATION_JSON).expectBody().returnResult(); byte[] bytes = result.getResponseBodyContent(); Assert.notNull(bytes, "Expected GraphQL response content"); @@ -155,20 +152,15 @@ class DefaultGraphQlTester implements GraphQlTester { @Override public SubscriptionSpec executeSubscription(RequestInput requestInput) { FluxExchangeResult exchangeResult = this.client.post() - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.TEXT_EVENT_STREAM) - .bodyValue(requestInput) - .exchange() - .expectStatus().isOk() - .expectHeader().contentType(MediaType.TEXT_EVENT_STREAM) + .contentType(MediaType.APPLICATION_JSON).accept(MediaType.TEXT_EVENT_STREAM).bodyValue(requestInput) + .exchange().expectStatus().isOk().expectHeader().contentType(MediaType.TEXT_EVENT_STREAM) .returnResult(TestExecutionResult.class); - return new DefaultSubscriptionSpec( - exchangeResult.getResponseBody().cast(ExecutionResult.class), + return new DefaultSubscriptionSpec(exchangeResult.getResponseBody().cast(ExecutionResult.class), this.jsonPathConfig, exchangeResult::assertWithDiagnostics); } - } + } /** * {@link RequestStrategy} that performs requests directly on {@link GraphQL}. @@ -181,12 +173,11 @@ class DefaultGraphQlTester implements GraphQlTester { private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(5); - private final WebGraphQlHandler graphQlHandler; private final Configuration jsonPathConfig; - public DirectRequestStrategy(WebGraphQlHandler handler, Configuration jsonPathConfig) { + DirectRequestStrategy(WebGraphQlHandler handler, Configuration jsonPathConfig) { this.graphQlHandler = handler; this.jsonPathConfig = jsonPathConfig; } @@ -205,8 +196,9 @@ class DefaultGraphQlTester implements GraphQlTester { List errors = result.getErrors(); Consumer assertDecorator = assertDecorator(input); - assertDecorator.accept(() -> AssertionErrors.assertTrue( - "Response has " + errors.size() + " unexpected error(s).", CollectionUtils.isEmpty(errors))); + assertDecorator + .accept(() -> AssertionErrors.assertTrue("Response has " + errors.size() + " unexpected error(s).", + CollectionUtils.isEmpty(errors))); return new DefaultSubscriptionSpec(result.getData(), this.jsonPathConfig, assertDecorator); } @@ -219,7 +211,7 @@ class DefaultGraphQlTester implements GraphQlTester { } private Consumer assertDecorator(RequestInput input) { - return assertion -> { + return (assertion) -> { try { assertion.run(); } @@ -228,13 +220,13 @@ class DefaultGraphQlTester implements GraphQlTester { } }; } - } + } /** * {@link RequestSpec} that collects the query, operationName, and variables. */ - private class DefaultRequestSpec implements RequestSpec { + private final class DefaultRequestSpec implements RequestSpec { private final String query; @@ -284,12 +276,12 @@ class DefaultGraphQlTester implements GraphQlTester { RequestInput input = new RequestInput(this.query, this.operationName, this.variables); return DefaultGraphQlTester.this.requestStrategy.executeSubscription(input); } - } + } private static class ErrorsContainer { - private static final Predicate MATCH_ALL_PREDICATE = error -> true; + private static final Predicate MATCH_ALL_PREDICATE = (error) -> true; private final List errors; @@ -302,32 +294,35 @@ class DefaultGraphQlTester implements GraphQlTester { this.assertDecorator = assertDecorator; } - public void doAssert(Runnable task) { + void doAssert(Runnable task) { this.assertDecorator.accept(task); } - public void filterErrors(Predicate errorPredicate) { - this.errors.forEach(error -> error.filter(errorPredicate)); + void filterErrors(Predicate errorPredicate) { + this.errors.forEach((error) -> error.filter(errorPredicate)); } - public void consumeErrors(Consumer> consumer) { + void consumeErrors(Consumer> consumer) { filterErrors(MATCH_ALL_PREDICATE); consumer.accept(new ArrayList<>(this.errors)); } - public void verifyErrors() { + void verifyErrors() { - List unexpected = - this.errors.stream().filter(error -> !error.isExpected()).collect(Collectors.toList()); + List unexpected = this.errors.stream().filter((error) -> !error.isExpected()) + .collect(Collectors.toList()); - this.assertDecorator.accept(() -> AssertionErrors.assertTrue( - "Response has " + unexpected.size() + " unexpected error(s)" + - (unexpected.size() != this.errors.size() ? " of " + this.errors.size() + " total" : "") + ". " + - "If expected, please use ResponseSpec#errors to filter them out: " + unexpected, - CollectionUtils.isEmpty(unexpected))); + this.assertDecorator + .accept(() -> AssertionErrors.assertTrue( + "Response has " + unexpected.size() + " unexpected error(s)" + + ((unexpected.size() != this.errors.size()) + ? " of " + this.errors.size() + " total" : "") + + ". " + "If expected, please use ResponseSpec#errors to filter them out: " + + unexpected, + CollectionUtils.isEmpty(unexpected))); } - } + } /** * Container for a GraphQL response with access to data and errors. @@ -349,18 +344,19 @@ class DefaultGraphQlTester implements GraphQlTester { private static List readErrors(DocumentContext documentContext) { Assert.notNull(documentContext, "DocumentContext is required"); try { - return documentContext.read(ERRORS_PATH, new TypeRef>() {}); + return documentContext.read(ERRORS_PATH, new TypeRef>() { + }); } catch (PathNotFoundException ex) { return Collections.emptyList(); } } - public String jsonContent() { + String jsonContent() { return this.jsonContent; } - public String jsonContent(JsonPath jsonPath) { + String jsonContent(JsonPath jsonPath) { try { Object content = this.documentContext.read(jsonPath); return this.documentContext.configuration().jsonProvider().toJson(content); @@ -370,25 +366,24 @@ class DefaultGraphQlTester implements GraphQlTester { } } - public T read(JsonPath jsonPath, TypeRef typeRef) { + T read(JsonPath jsonPath, TypeRef typeRef) { return this.documentContext.read(jsonPath, typeRef); } - } + } /** * {@link ResponseSpec} that operates on the response from a GraphQL HTTP request. */ - private static class DefaultResponseSpec implements ResponseSpec, ErrorSpec { + private static final class DefaultResponseSpec implements ResponseSpec, ErrorSpec { private final ResponseContainer responseContainer; /** * Class constructor. * @param documentContext the parsed response content - * @param assertDecorator decorator to apply around assertions, e.g. to - * add extra contextual information such as HTTP request and response - * body details + * @param assertDecorator decorator to apply around assertions, e.g. to add extra + * contextual information such as HTTP request and response body details */ private DefaultResponseSpec(DocumentContext documentContext, Consumer assertDecorator) { this.responseContainer = new ResponseContainer(documentContext, assertDecorator); @@ -422,8 +417,8 @@ class DefaultGraphQlTester implements GraphQlTester { this.responseContainer.consumeErrors(consumer); return this; } - } + } /** * {@link PathSpec} implementation. @@ -438,7 +433,6 @@ class DefaultGraphQlTester implements GraphQlTester { private final JsonPathExpectationsHelper pathHelper; - DefaultPathSpec(String path, ResponseContainer responseContainer) { Assert.notNull(path, "`path` is required"); Assert.notNull(responseContainer, "ResponseContainer is required"); @@ -458,7 +452,6 @@ class DefaultGraphQlTester implements GraphQlTester { return JsonPath.compile(path); } - @Override public PathSpec path(String path) { return new DefaultPathSpec(path, this.responseContainer); @@ -466,29 +459,26 @@ class DefaultGraphQlTester implements GraphQlTester { @Override public PathSpec pathExists() { - this.responseContainer.doAssert( - () -> this.pathHelper.hasJsonPath(this.responseContainer.jsonContent())); + this.responseContainer.doAssert(() -> this.pathHelper.hasJsonPath(this.responseContainer.jsonContent())); return this; } @Override public PathSpec pathDoesNotExist() { - this.responseContainer.doAssert( - () -> this.pathHelper.doesNotHaveJsonPath(this.responseContainer.jsonContent())); + this.responseContainer + .doAssert(() -> this.pathHelper.doesNotHaveJsonPath(this.responseContainer.jsonContent())); return this; } @Override public PathSpec valueExists() { - this.responseContainer.doAssert( - () -> this.pathHelper.exists(this.responseContainer.jsonContent())); + this.responseContainer.doAssert(() -> this.pathHelper.exists(this.responseContainer.jsonContent())); return this; } @Override public PathSpec valueDoesNotExist() { - this.responseContainer.doAssert( - () -> this.pathHelper.doesNotExist(this.responseContainer.jsonContent())); + this.responseContainer.doAssert(() -> this.pathHelper.doesNotExist(this.responseContainer.jsonContent())); return this; } @@ -507,8 +497,8 @@ class DefaultGraphQlTester implements GraphQlTester { @Override public PathSpec valueIsNotEmpty() { - this.responseContainer.doAssert( - () -> this.pathHelper.assertValueIsNotEmpty(this.responseContainer.jsonContent())); + this.responseContainer + .doAssert(() -> this.pathHelper.assertValueIsNotEmpty(this.responseContainer.jsonContent())); return this; } @@ -555,18 +545,17 @@ class DefaultGraphQlTester implements GraphQlTester { new JsonExpectationsHelper().assertJsonEqual(expected, actual, strict); } catch (AssertionError ex) { - throw new AssertionError(ex.getMessage() + "\n\n" + - "Expected JSON content:\n'" + expected + "'\n\n" + - "Actual JSON content:\n'" + actual + "'\n\n" + - "Input path: '" + this.inputPath + "'\n", ex); + throw new AssertionError(ex.getMessage() + "\n\n" + "Expected JSON content:\n'" + expected + "'\n\n" + + "Actual JSON content:\n'" + actual + "'\n\n" + "Input path: '" + this.inputPath + "'\n", + ex); } catch (Exception ex) { throw new AssertionError("JSON parsing error", ex); } }); } - } + } /** * {@link EntitySpec} implementation. @@ -604,22 +593,19 @@ class DefaultGraphQlTester implements GraphQlTester { @Override public T isEqualTo(Object expected) { - this.responseContainer.doAssert( - () -> AssertionErrors.assertEquals(this.inputPath, expected, this.entity)); + this.responseContainer.doAssert(() -> AssertionErrors.assertEquals(this.inputPath, expected, this.entity)); return self(); } @Override public T isNotEqualTo(Object other) { - this.responseContainer.doAssert( - () -> AssertionErrors.assertNotEquals(this.inputPath, other, this.entity)); + this.responseContainer.doAssert(() -> AssertionErrors.assertNotEquals(this.inputPath, other, this.entity)); return self(); } @Override public T isSameAs(Object expected) { - this.responseContainer.doAssert( - () -> AssertionErrors.assertTrue(this.inputPath, expected == this.entity)); + this.responseContainer.doAssert(() -> AssertionErrors.assertTrue(this.inputPath, expected == this.entity)); return self(); } @@ -631,8 +617,8 @@ class DefaultGraphQlTester implements GraphQlTester { @Override public T matches(Predicate predicate) { - this.responseContainer.doAssert( - () -> AssertionErrors.assertTrue(this.inputPath, predicate.test(this.entity))); + this.responseContainer + .doAssert(() -> AssertionErrors.assertTrue(this.inputPath, predicate.test(this.entity))); return self(); } @@ -651,8 +637,8 @@ class DefaultGraphQlTester implements GraphQlTester { private T self() { return (T) this; } - } + } /** * {@link ListEntitySpec} implementation. @@ -669,8 +655,7 @@ class DefaultGraphQlTester implements GraphQlTester { public ListEntitySpec contains(E... elements) { doAssert(() -> { List expected = Arrays.asList(elements); - AssertionErrors.assertTrue( - "List at path '" + getInputPath() + "' does not contain " + expected, + AssertionErrors.assertTrue("List at path '" + getInputPath() + "' does not contain " + expected, (getEntity() != null && getEntity().containsAll(expected))); }); return this; @@ -702,36 +687,32 @@ class DefaultGraphQlTester implements GraphQlTester { @Override public ListEntitySpec hasSize(int size) { - doAssert(() -> - AssertionErrors.assertTrue( - "List at path '" + getInputPath() + "' should have size " + size, - (getEntity() != null && getEntity().size() == size))); + doAssert(() -> AssertionErrors.assertTrue("List at path '" + getInputPath() + "' should have size " + size, + (getEntity() != null && getEntity().size() == size))); return this; } @Override public ListEntitySpec hasSizeLessThan(int boundary) { - doAssert(() -> - AssertionErrors.assertTrue( - "List at path '" + getInputPath() + "' should have size less than " + boundary, - (getEntity() != null && getEntity().size() < boundary))); + doAssert(() -> AssertionErrors.assertTrue( + "List at path '" + getInputPath() + "' should have size less than " + boundary, + (getEntity() != null && getEntity().size() < boundary))); return this; } @Override public ListEntitySpec hasSizeGreaterThan(int boundary) { - doAssert(() -> - AssertionErrors.assertTrue( - "List at path '" + getInputPath() + "' should have size greater than " + boundary, - (getEntity() != null && getEntity().size() > boundary))); + doAssert(() -> AssertionErrors.assertTrue( + "List at path '" + getInputPath() + "' should have size greater than " + boundary, + (getEntity() != null && getEntity().size() > boundary))); return this; } + } - /** - * {@link SubscriptionSpec} implementation that operates on a - * {@link Publisher} of {@link ExecutionResult}. + * {@link SubscriptionSpec} implementation that operates on a {@link Publisher} of + * {@link ExecutionResult}. */ private static class DefaultSubscriptionSpec implements SubscriptionSpec { @@ -741,8 +722,8 @@ class DefaultGraphQlTester implements GraphQlTester { private final Consumer assertDecorator; - DefaultSubscriptionSpec( - Publisher publisher, Configuration jsonPathConfig, Consumer decorator) { + DefaultSubscriptionSpec(Publisher publisher, Configuration jsonPathConfig, + Consumer decorator) { this.publisher = publisher; this.jsonPathConfig = jsonPathConfig; @@ -751,22 +732,21 @@ class DefaultGraphQlTester implements GraphQlTester { @Override public Flux toFlux() { - return Flux.from(this.publisher).map(result -> { + return Flux.from(this.publisher).map((result) -> { DocumentContext context = JsonPath.parse(result.toSpecification(), this.jsonPathConfig); return new DefaultResponseSpec(context, this.assertDecorator); }); } - } + } private static class Jackson2Configuration { static Configuration create() { - return Configuration.builder() - .jsonProvider(new JacksonJsonProvider()) - .mappingProvider(new JacksonMappingProvider()) - .build(); + return Configuration.builder().jsonProvider(new JacksonJsonProvider()) + .mappingProvider(new JacksonMappingProvider()).build(); } + } } 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 e8abd8fc..d80a0402 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 @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.test.tester; import java.util.List; @@ -29,13 +30,12 @@ import org.springframework.lang.Nullable; import org.springframework.test.web.reactive.server.WebTestClient; /** - * Main entry point for testing GraphQL with requests performed either as an - * HTTP client via {@link WebTestClient} or directly via a - * {@link WebGraphQlHandler}. + * Main entry point for testing GraphQL with requests performed either as an HTTP client + * via {@link WebTestClient} or directly via a {@link WebGraphQlHandler}. * * - *

GraphQL requests to Spring MVC without an HTTP server: - *

+ * 

+ * GraphQL requests to Spring MVC without an HTTP server:

  * @SpringBootTest
  * @AutoConfigureMockMvc
  * public class MyTests {
@@ -49,8 +49,8 @@ import org.springframework.test.web.reactive.server.WebTestClient;
  *  }
  * 
* - *

GraphQL requests to Spring WebFlux without an HTTP server: - *

+ * 

+ * GraphQL requests to Spring WebFlux without an HTTP server:

  * @SpringBootTest
  * @AutoConfigureWebTestClient
  * public class MyTests {
@@ -63,8 +63,8 @@ import org.springframework.test.web.reactive.server.WebTestClient;
  *  }
  * 
* - *

GraphQL requests to a running server: - *

+ * 

+ * GraphQL requests to a running server:

  * @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
  * public class MyTests {
  *
@@ -76,8 +76,8 @@ import org.springframework.test.web.reactive.server.WebTestClient;
  *  }
  * 
* - *

GraphQL requests to any {@link WebGraphQlHandler}: - *

+ * 

+ * GraphQL requests to any {@link WebGraphQlHandler}:

  * @SpringBootTest
  * public class MyTests {
  *
@@ -88,24 +88,26 @@ import org.springframework.test.web.reactive.server.WebTestClient;
  *      this.graphQlTester = GraphQlTester.create(handler);
  *  }
  * 
+ * + * @author Rossen Stoyanchev + * @since 1.0.0 */ public interface GraphQlTester { /** - * Prepare to perform a GraphQL request with the given operation which may - * be a query, mutation, or a subscription. + * Prepare to perform a GraphQL request with the given operation which may be a query, + * mutation, or a subscription. * @param query the operation to be performed * @return spec for response assertions * @throws AssertionError if the response status is not 200 (OK) */ RequestSpec query(String query); - /** - * Create a {@code GraphQlTester} that performs GraphQL requests as an HTTP - * client through the given {@link WebTestClient}. Depending on how the - * {@code WebTestClient} is set up, tests may be with or without a server. - * See setup examples in class-level Javadoc. + * Create a {@code GraphQlTester} that performs GraphQL requests as an HTTP client + * through the given {@link WebTestClient}. Depending on how the {@code WebTestClient} + * is set up, tests may be with or without a server. See setup examples in class-level + * Javadoc. * @param client the web client to perform requests with * @return the created {@code GraphQlTester} instance */ @@ -114,8 +116,8 @@ public interface GraphQlTester { } /** - * Create a {@code GraphQlTester} that performs GraphQL requests through - * the given {@link WebGraphQlHandler}. + * Create a {@code GraphQlTester} that performs GraphQL requests through the given + * {@link WebGraphQlHandler}. * @param handler the handler to execute requests with * @return the created {@code GraphQlTester} instance */ @@ -123,19 +125,17 @@ public interface GraphQlTester { return new DefaultGraphQlTester(handler); } - /** * Declare options to perform a GraphQL request. */ interface ExecuteSpec { /** - * Execute the GraphQL request and return a spec for further inspection - * of response data and errors. - * + * Execute the GraphQL request and return a spec for further inspection of + * response data and errors. * @return options for asserting the response - * @throws AssertionError if the request is performed over HTTP and the - * response status is not 200 (OK). + * @throws AssertionError if the request is performed over HTTP and the response + * status is not 200 (OK). */ ResponseSpec execute(); @@ -145,18 +145,16 @@ public interface GraphQlTester { void executeAndVerify(); /** - * Execute the GraphQL request as a subscription and return a spec with - * options to transform the result stream. - * + * Execute the GraphQL request as a subscription and return a spec with options to + * transform the result stream. * @return spec with options to transform the subscription result stream - * @throws AssertionError if the request is performed over HTTP and the - * response status is not 200 (OK). + * @throws AssertionError if the request is performed over HTTP and the response + * status is not 200 (OK). */ SubscriptionSpec executeSubscription(); } - /** * Declare options to gather input for a GraphQL request and execute it. */ @@ -164,20 +162,27 @@ public interface GraphQlTester { /** * Set the operation name. + * @param name the operation name + * @return this request spec */ RequestSpec operationName(@Nullable String name); /** * Add a variable. + * @param name the variable name + * @param value the variable value + * @return this request spec */ RequestSpec variable(String name, Object value); /** * Modify variables by accessing the underlying map. + * @param variablesConsumer a callback for the map of variables + * @return this request spec */ RequestSpec variables(Consumer> variablesConsumer); - } + } /** * Declare options to switch to different part of the GraphQL response. @@ -185,20 +190,19 @@ public interface GraphQlTester { interface TraverseSpec { /** - * Switch to a path under the "data" section of the GraphQL response. - * The path can be an operation root type name, e.g. "project", or a - * nested path such as "project.name", or any + * Switch to a path under the "data" section of the GraphQL response. The path can + * be an operation root type name, e.g. "project", or a nested path such as + * "project.name", or any * JsonPath. - * * @param path the path to switch to * @return spec for asserting the content under the given path * @throws AssertionError if the GraphQL response contains - * errors - * that have not be checked via {@link ResponseSpec#errors()} + * errors that have + * not be checked via {@link ResponseSpec#errors()} */ PathSpec path(String path); - } + } /** * Declare options to check the data and errors of a GraphQL response. @@ -206,15 +210,15 @@ public interface GraphQlTester { interface ResponseSpec extends TraverseSpec { /** - * Return a spec to filter out or inspect errors. This must be used - * before traversing to a {@link #path(String)} if some errors are - * expected and need to be filtered out. + * Return a spec to filter out or inspect errors. This must be used before + * traversing to a {@link #path(String)} if some errors are expected and need to + * be filtered out. + * @return the error spec */ ErrorSpec errors(); } - /** * Declare options available to assert data at a given path. */ @@ -233,8 +237,8 @@ public interface GraphQlTester { PathSpec pathDoesNotExist(); /** - * Assert a value exists at the given path where the value is any - * {@code non-null} value, possibly an empty array or map. + * Assert a value exists at the given path where the value is any {@code non-null} + * value, possibly an empty array or map. * @return spec to assert the converted entity with */ PathSpec valueExists(); @@ -246,22 +250,22 @@ public interface GraphQlTester { PathSpec valueDoesNotExist(); /** - * Assert the value at the given path does not exist or is empty as defined - * in {@link org.springframework.util.ObjectUtils#isEmpty(Object)}. + * Assert the value at the given path does not exist or is empty as defined in + * {@link org.springframework.util.ObjectUtils#isEmpty(Object)}. * @return spec to assert the converted entity with * @see org.springframework.util.ObjectUtils#isEmpty(Object) */ PathSpec valueIsEmpty(); /** - * Assert the value at the given path is not {@link #valueIsEmpty()} + * Assert the value at the given path is not {@link #valueIsEmpty()}. * @return spec to assert the converted entity with */ PathSpec valueIsNotEmpty(); /** * Convert the data at the given path to the target type. - * @param entityType the type to convert to + * @param entityType the type to convert to * @param the target entity type * @return spec to assert the converted entity with */ @@ -292,33 +296,36 @@ public interface GraphQlTester { ListEntitySpec entityList(ParameterizedTypeReference elementType); /** - * Parse the JSON at the given path and the given expected JSON and assert - * that the two are "similar". - *

Use of this option requires the - * JSONassert library - * on to be on the classpath. + * Parse the JSON at the given path and the given expected JSON and assert that + * the two are "similar". + *

+ * Use of this option requires the + * JSONassert library on to be + * on the classpath. * @param expectedJson the expected JSON * @return spec to specify a different path - * @see org.springframework.test.util.JsonExpectationsHelper#assertJsonEqual(String, String) + * @see org.springframework.test.util.JsonExpectationsHelper#assertJsonEqual(String, + * String) */ TraverseSpec matchesJson(String expectedJson); /** - * Parse the JSON at the given path and the given expected JSON and assert - * that the two are "similar" so they contain the same attribute-value - * pairs regardless of formatting, along with lenient checking, e.g. - * extensible and non-strict array ordering. + * Parse the JSON at the given path and the given expected JSON and assert that + * the two are "similar" so they contain the same attribute-value pairs regardless + * of formatting, along with lenient checking, e.g. extensible and non-strict + * array ordering. * @param expectedJson the expected JSON * @return spec to specify a different path - * @see org.springframework.test.util.JsonExpectationsHelper#assertJsonEqual(String, String, boolean) + * @see org.springframework.test.util.JsonExpectationsHelper#assertJsonEqual(String, + * String, boolean) */ TraverseSpec matchesJsonStrictly(String expectedJson); } - /** * Declare options available to assert data converted to an entity. + * * @param the entity type * @param the spec type, including subtypes */ @@ -367,21 +374,23 @@ public interface GraphQlTester { /** * Perform any assertions on the converted entity, e.g. via AssertJ. * @param consumer the consumer to inspect the entity with + * @param the spec type * @return the same spec for more assertions */ T satisfies(Consumer consumer); /** * Return the converted entity. + * @return the converter entity */ D get(); } - /** - * Extension of {@link EntitySpec} with options available to assert data - * converted to a List of entities. + * Extension of {@link EntitySpec} with options available to assert data converted to + * a List of entities. + * * @param the type of elements in the list */ interface ListEntitySpec extends EntitySpec, ListEntitySpec> { @@ -433,16 +442,15 @@ public interface GraphQlTester { } - /** - * Declare options to filter out expected errors or inspect all errors and - * verify there are no unexpected errors. + * Declare options to filter out expected errors or inspect all errors and verify + * there are no unexpected errors. */ 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 + * Add a filter for expected errors. All errors that match the predicate are + * treated as expected and ignored on {@link #verify()} or when * {@link TraverseSpec#path(String) traversing} to a data path. * @param errorPredicate the predicate to add * @return the same spec to add more filters before {@link #verify()} @@ -450,17 +458,16 @@ public interface GraphQlTester { ErrorSpec filter(Predicate errorPredicate); /** - * Verify there are either no errors or that there no unexpected errors - * that have not been {@link #filter(Predicate) filtered out}. + * Verify there are either no errors or that there no unexpected errors that have + * not been {@link #filter(Predicate) filtered out}. * @return a spec to switch to a data path */ TraverseSpec verify(); /** - * Inspect errors - * in the response, if any. Use of this method effectively suppresses - * all errors and allows {@link TraverseSpec#path(String) traversing} to a - * data path. + * Inspect errors in + * the response, if any. Use of this method effectively suppresses all errors and + * allows {@link TraverseSpec#path(String) traversing} to a data path. * @param errorsConsumer to inspect errors with * @return a spec to switch to a data path */ @@ -468,30 +475,29 @@ public interface GraphQlTester { } - /** * Declare options available to assert a GraphQL Subscription response. */ interface SubscriptionSpec { /** - * Return a {@link Flux} of entities converted from some part of the data - * in each subscription event. + * Return a {@link Flux} of entities converted from some part of the data in each + * subscription event. * @param path a path into the data of each subscription event * @param entityType the type to convert data to * @param the entity type - * @return a {@code Flux} of entities that can be further inspected, - * e.g. with {@code reactor.test.StepVerifier} + * @return a {@code Flux} of entities that can be further inspected, e.g. with + * {@code reactor.test.StepVerifier} */ default Flux toFlux(String path, Class entityType) { - return toFlux().map(spec -> spec.path(path).entity(entityType).get()); + return toFlux().map((spec) -> spec.path(path).entity(entityType).get()); } /** - * Return a {@link Flux} of {@link ResponseSpec} instances, each - * representing an individual subscription event. - * @return a {@code Flux} of {@code ResponseSpec} instances that can be - * further inspected, e.g. with {@code reactor.test.StepVerifier} + * Return a {@link Flux} of {@link ResponseSpec} instances, each representing an + * individual subscription event. + * @return a {@code Flux} of {@code ResponseSpec} instances that can be further + * inspected, e.g. with {@code reactor.test.StepVerifier} */ Flux toFlux(); diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TestExecutionResult.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TestExecutionResult.java index 7a6572fc..df1f7c3c 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TestExecutionResult.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TestExecutionResult.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.test.tester; import java.util.ArrayList; @@ -27,6 +28,9 @@ import graphql.GraphQLError; /** * {@link GraphQLError} with setters for deserialization. + * + * @author Rossen Stoyanchev + * @since 1.0.0 */ public class TestExecutionResult implements ExecutionResult { @@ -36,7 +40,6 @@ public class TestExecutionResult implements ExecutionResult { private Map extensions = Collections.emptyMap(); - public void setData(Object data) { this.data = data; } @@ -72,8 +75,7 @@ public class TestExecutionResult implements ExecutionResult { @Override public Map toSpecification() { - ExecutionResultImpl.Builder builder = ExecutionResultImpl.newExecutionResult() - .addErrors(this.errors) + ExecutionResultImpl.Builder builder = ExecutionResultImpl.newExecutionResult().addErrors(this.errors) .extensions(this.extensions); if (isDataPresent()) { @@ -82,4 +84,5 @@ public class TestExecutionResult implements ExecutionResult { return builder.build().toSpecification(); } + } 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 9afb0e91..a0acf243 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 @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.test.tester; import java.util.List; @@ -28,6 +29,8 @@ import graphql.language.SourceLocation; /** * {@link GraphQLError} with setters to use for deserialization. + * + * @author Rossen Stoyanchev */ class TestGraphQlError implements GraphQLError { @@ -43,9 +46,7 @@ class TestGraphQlError implements GraphQLError { private boolean expected; - - - public void setMessage(String message) { + void setMessage(String message) { this.message = message; } @@ -54,7 +55,7 @@ class TestGraphQlError implements GraphQLError { return this.message; } - public void setLocations(List locations) { + void setLocations(List locations) { this.locations = TestSourceLocation.toSourceLocations(locations); } @@ -63,7 +64,7 @@ class TestGraphQlError implements GraphQLError { return this.locations; } - public void setErrorType(ErrorClassification errorType) { + void setErrorType(ErrorClassification errorType) { this.errorType = errorType; } @@ -72,7 +73,7 @@ class TestGraphQlError implements GraphQLError { return this.errorType; } - public void setPath(List path) { + void setPath(List path) { this.path = path; } @@ -81,7 +82,7 @@ class TestGraphQlError implements GraphQLError { return this.path; } - public void setExtensions(Map extensions) { + void setExtensions(Map extensions) { this.extensions = extensions; } @@ -92,8 +93,9 @@ class TestGraphQlError implements GraphQLError { /** * Whether the error is marked as filtered out as expected. + * @return whether the error is marked as expected */ - public boolean isExpected() { + boolean isExpected() { return this.expected; } @@ -117,6 +119,7 @@ class TestGraphQlError implements GraphQLError { /** * Mark this error as expected if it matches the predicate. + * @param predicate the error predicate */ void filter(Predicate predicate) { this.expected |= predicate.test(this); @@ -127,8 +130,7 @@ class TestGraphQlError implements GraphQLError { return toSpecification().toString(); } - - private static class TestSourceLocation { + private static final class TestSourceLocation { private int line; @@ -136,35 +138,36 @@ class TestGraphQlError implements GraphQLError { private String sourceName; - - public void setLine(int line) { + void setLine(int line) { this.line = line; } - public int getLine() { + int getLine() { return this.line; } - public void setColumn(int column) { + void setColumn(int column) { this.column = column; } - public int getColumn() { + int getColumn() { return this.column; } - public void setSourceName(String sourceName) { + void setSourceName(String sourceName) { this.sourceName = sourceName; } - public String getSourceName() { + String getSourceName() { return this.sourceName; } - public static List toSourceLocations(List locations) { + static List toSourceLocations(List locations) { return locations.stream() - .map(location -> new SourceLocation(location.line, location.column, location.sourceName)) + .map((location) -> new SourceLocation(location.line, location.column, location.sourceName)) .collect(Collectors.toList()); } + } + } diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TypeRefAdapter.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TypeRefAdapter.java index c5ae70db..17f67a2d 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TypeRefAdapter.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/TypeRefAdapter.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.test.tester; import java.lang.reflect.Type; @@ -23,14 +24,16 @@ import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ResolvableType; /** - * {@link TypeRef} with a {@link #getType() type} that is given rather than - * obtained from the declared generic type information. + * {@link TypeRef} with a {@link #getType() type} that is given rather than obtained from + * the declared generic type information. + * + * @param the referenced type + * @author Rossen Stoyanchev */ class TypeRefAdapter extends TypeRef { private final Type type; - TypeRefAdapter(Class clazz) { this.type = clazz; } @@ -47,7 +50,6 @@ class TypeRefAdapter extends TypeRef { this.type = ResolvableType.forClassWithGenerics(clazz, ResolvableType.forType(generic)).getType(); } - @Override public Type getType() { return this.type; diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/package-info.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/package-info.java index 4e60f5d1..67cbae3b 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/package-info.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/package-info.java @@ -13,6 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +/** + * GraphQL client testing support. + */ @NonNullApi @NonNullFields package org.springframework.graphql.test.tester; 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 94bfb660..a8f2829e 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 @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.test.tester; import java.util.Arrays; @@ -51,8 +52,8 @@ import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; /** * Tests for {@link GraphQlTester} parameterized to: @@ -61,20 +62,18 @@ import static org.mockito.Mockito.when; *
  • Use mock {@link WebGraphQlHandler} to return a preset {@link ExecutionResult}. * * - *

    There is no actual handling via {@link graphql.GraphQL} in either scenario. - * The main focus is to verify {@link GraphQlTester} request preparation and - * response handling. + *

    + * There is no actual handling via {@link graphql.GraphQL} in either scenario. The main + * focus is to verify {@link GraphQlTester} request preparation and response handling. */ public class GraphQlTesterTests { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - public static Stream argumentSource() { return Stream.of(new MockWebServerSetup(), new MockWebGraphQlHandlerSetup()); } - @ParameterizedTest @MethodSource("argumentSource") void pathAndValueExistsAndEmptyChecks(GraphQlTesterSetup setup) throws Exception { @@ -88,7 +87,7 @@ public class GraphQlTesterTests { spec.path("me.friends").valueIsEmpty(); spec.path("hero").pathDoesNotExist().valueDoesNotExist().valueIsEmpty(); - setup.verifyRequest(input -> assertThat(input.getQuery()).contains(query)); + setup.verifyRequest((input) -> assertThat(input.getQuery()).contains(query)); setup.shutdown(); } @@ -103,13 +102,13 @@ public class GraphQlTesterTests { spec.path("").matchesJson("{\"me\": {\"name\":\"Luke Skywalker\",\"friends\":[]}}"); spec.path("me").matchesJson("{\"name\":\"Luke Skywalker\"}"); - spec.path("me").matchesJson("{\"friends\":[]}"); // lenient match with subset of fields + spec.path("me").matchesJson("{\"friends\":[]}"); // lenient match with subset of + // fields assertThatThrownBy(() -> spec.path("me").matchesJsonStrictly("{\"friends\":[]}")) - .as("Extended fields should fail in strict mode") - .hasMessageContaining("Unexpected: name"); + .as("Extended fields should fail in strict mode").hasMessageContaining("Unexpected: name"); - setup.verifyRequest(input -> assertThat(input.getQuery()).contains(query)); + setup.verifyRequest((input) -> assertThat(input.getQuery()).contains(query)); setup.shutdown(); } @@ -126,22 +125,16 @@ public class GraphQlTesterTests { MovieCharacter han = MovieCharacter.create("Han Solo"); AtomicReference personRef = new AtomicReference<>(); - MovieCharacter actual = spec.path("me").entity(MovieCharacter.class) - .isEqualTo(luke) - .isNotEqualTo(han) - .satisfies(personRef::set) - .matches(movieCharacter -> personRef.get().equals(movieCharacter)) - .isSameAs(personRef.get()) - .isNotSameAs(luke) - .get(); + MovieCharacter actual = spec.path("me").entity(MovieCharacter.class).isEqualTo(luke).isNotEqualTo(han) + .satisfies(personRef::set).matches((movieCharacter) -> personRef.get().equals(movieCharacter)) + .isSameAs(personRef.get()).isNotSameAs(luke).get(); assertThat(actual.getName()).isEqualTo("Luke Skywalker"); - spec.path("") - .entity(new ParameterizedTypeReference>() {}) - .isEqualTo(Collections.singletonMap("me", luke)); + spec.path("").entity(new ParameterizedTypeReference>() { + }).isEqualTo(Collections.singletonMap("me", luke)); - setup.verifyRequest(input -> assertThat(input.getQuery()).contains(query)); + setup.verifyRequest((input) -> assertThat(input.getQuery()).contains(query)); setup.shutdown(); } @@ -150,13 +143,8 @@ public class GraphQlTesterTests { void entityList(GraphQlTesterSetup setup) throws Exception { String query = "{me {name, friends}}"; - setup.response("{" + - " \"me\":{" + - " \"name\":\"Luke Skywalker\"," + - " \"friends\":[{\"name\":\"Han Solo\"}, {\"name\":\"Leia Organa\"}]" + - " }" + - "}" - ); + setup.response("{" + " \"me\":{" + " \"name\":\"Luke Skywalker\"," + + " \"friends\":[{\"name\":\"Han Solo\"}, {\"name\":\"Leia Organa\"}]" + " }" + "}"); GraphQlTester.ResponseSpec spec = setup.graphQlTester().query(query).execute(); @@ -164,22 +152,16 @@ public class GraphQlTesterTests { MovieCharacter leia = MovieCharacter.create("Leia Organa"); MovieCharacter jabba = MovieCharacter.create("Jabba the Hutt"); - List actual = spec.path("me.friends").entityList(MovieCharacter.class) - .contains(han) - .containsExactly(han, leia) - .doesNotContain(jabba) - .hasSize(2) - .hasSizeGreaterThan(1) - .hasSizeLessThan(3) + List actual = spec.path("me.friends").entityList(MovieCharacter.class).contains(han) + .containsExactly(han, leia).doesNotContain(jabba).hasSize(2).hasSizeGreaterThan(1).hasSizeLessThan(3) .get(); assertThat(actual).containsExactly(han, leia); - spec.path("me.friends") - .entityList(new ParameterizedTypeReference() {}) - .containsExactly(han, leia); + spec.path("me.friends").entityList(new ParameterizedTypeReference() { + }).containsExactly(han, leia); - setup.verifyRequest(input -> assertThat(input.getQuery()).contains(query)); + setup.verifyRequest((input) -> assertThat(input.getQuery()).contains(query)); setup.shutdown(); } @@ -187,23 +169,17 @@ public class GraphQlTesterTests { @MethodSource("argumentSource") void operationNameAndVariables(GraphQlTesterSetup setup) throws Exception { - String query = "query HeroNameAndFriends($episode: Episode) {" + - " hero(episode: $episode) {" + - " name" + - " }" + - "}"; + String query = "query HeroNameAndFriends($episode: Episode) {" + " hero(episode: $episode) {" + " name" + + " }" + "}"; setup.response("{\"hero\": {\"name\":\"R2-D2\"}}"); - GraphQlTester.ResponseSpec spec = setup.graphQlTester().query(query) - .operationName("HeroNameAndFriends") - .variable("episode", "JEDI") - .variables(map -> map.put("foo", "bar")) - .execute(); + GraphQlTester.ResponseSpec spec = setup.graphQlTester().query(query).operationName("HeroNameAndFriends") + .variable("episode", "JEDI").variables((map) -> map.put("foo", "bar")).execute(); spec.path("hero").entity(MovieCharacter.class).isEqualTo(MovieCharacter.create("R2-D2")); - setup.verifyRequest(input -> { + setup.verifyRequest((input) -> { assertThat(input.getQuery()).contains(query); assertThat(input.getOperationName()).isEqualTo("HeroNameAndFriends"); assertThat(input.getVariables()).hasSize(2); @@ -223,7 +199,7 @@ public class GraphQlTesterTests { assertThatThrownBy(() -> setup.graphQlTester().query(query).executeAndVerify()) .hasMessageContaining("Response has 1 unexpected error(s)."); - setup.verifyRequest(input -> assertThat(input.getQuery()).contains(query)); + setup.verifyRequest((input) -> assertThat(input.getQuery()).contains(query)); setup.shutdown(); } @@ -237,7 +213,7 @@ public class GraphQlTesterTests { assertThatThrownBy(() -> setup.graphQlTester().query(query).execute().path("me")) .hasMessageContaining("Response has 1 unexpected error(s)."); - setup.verifyRequest(input -> assertThat(input.getQuery()).contains(query)); + setup.verifyRequest((input) -> assertThat(input.getQuery()).contains(query)); setup.shutdown(); } @@ -246,18 +222,14 @@ public class GraphQlTesterTests { void errorsPartiallyFiltered(GraphQlTesterSetup setup) throws Exception { String query = "{me {name, friends}}"; - setup.response( - GraphqlErrorBuilder.newError().message("some error").build(), + setup.response(GraphqlErrorBuilder.newError().message("some error").build(), GraphqlErrorBuilder.newError().message("some other error").build()); - assertThatThrownBy(() -> - setup.graphQlTester().query(query).execute() - .errors() - .filter(error -> error.getMessage().equals("some error")) - .verify()) - .hasMessageContaining("Response has 1 unexpected error(s) of 2 total."); + assertThatThrownBy(() -> setup.graphQlTester().query(query).execute().errors() + .filter((error) -> error.getMessage().equals("some error")).verify()) + .hasMessageContaining("Response has 1 unexpected error(s) of 2 total."); - setup.verifyRequest(input -> assertThat(input.getQuery()).contains(query)); + setup.verifyRequest((input) -> assertThat(input.getQuery()).contains(query)); setup.shutdown(); } @@ -266,17 +238,13 @@ public class GraphQlTesterTests { void errorsFiltered(GraphQlTesterSetup setup) throws Exception { String query = "{me {name, friends}}"; - setup.response( - GraphqlErrorBuilder.newError().message("some error").build(), + setup.response(GraphqlErrorBuilder.newError().message("some error").build(), GraphqlErrorBuilder.newError().message("some other error").build()); - setup.graphQlTester().query(query).execute() - .errors() - .filter(error -> error.getMessage().startsWith("some ")) - .verify() - .path("me").pathDoesNotExist(); + setup.graphQlTester().query(query).execute().errors().filter((error) -> error.getMessage().startsWith("some ")) + .verify().path("me").pathDoesNotExist(); - setup.verifyRequest(input -> assertThat(input.getQuery()).contains(query)); + setup.verifyRequest((input) -> assertThat(input.getQuery()).contains(query)); setup.shutdown(); } @@ -285,26 +253,21 @@ public class GraphQlTesterTests { void errorsConsumed(GraphQlTesterSetup setup) throws Exception { String query = "{me {name, friends}}"; - setup.response(GraphqlErrorBuilder.newError() - .message("Invalid query") - .location(new SourceLocation(1, 2)) - .build()); + setup.response( + GraphqlErrorBuilder.newError().message("Invalid query").location(new SourceLocation(1, 2)).build()); - setup.graphQlTester().query(query).execute() - .errors().satisfy(errors -> { - assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMessage()).isEqualTo("Invalid query"); - assertThat(errors.get(0).getLocations()).hasSize(1); - assertThat(errors.get(0).getLocations().get(0).getLine()).isEqualTo(1); - assertThat(errors.get(0).getLocations().get(0).getColumn()).isEqualTo(2); - }) - .path("me").pathDoesNotExist(); + setup.graphQlTester().query(query).execute().errors().satisfy((errors) -> { + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMessage()).isEqualTo("Invalid query"); + assertThat(errors.get(0).getLocations()).hasSize(1); + assertThat(errors.get(0).getLocations().get(0).getLine()).isEqualTo(1); + assertThat(errors.get(0).getLocations().get(0).getColumn()).isEqualTo(2); + }).path("me").pathDoesNotExist(); - setup.verifyRequest(input -> assertThat(input.getQuery()).contains(query)); + setup.verifyRequest((input) -> assertThat(input.getQuery()).contains(query)); setup.shutdown(); } - private interface GraphQlTesterSetup { GraphQlTester graphQlTester(); @@ -327,7 +290,6 @@ public class GraphQlTesterTests { } - private static class MockWebServerSetup implements GraphQlTesterSetup { private final MockWebServer server; @@ -356,12 +318,10 @@ public class GraphQlTesterTests { sb.append("\"data\":").append(data); } if (!CollectionUtils.isEmpty(errors)) { - List> errorSpecs = errors.stream() - .map(GraphQLError::toSpecification) + List> errorSpecs = errors.stream().map(GraphQLError::toSpecification) .collect(Collectors.toList()); - sb.append(StringUtils.hasText(data) ? ", " : "") - .append("\"errors\":") + sb.append(StringUtils.hasText(data) ? ", " : "").append("\"errors\":") .append(OBJECT_MAPPER.writeValueAsString(errorSpecs)); } sb.append("}"); @@ -380,7 +340,8 @@ public class GraphQlTesterTests { assertThat(request.getHeader(HttpHeaders.CONTENT_TYPE)).isEqualTo("application/json"); String content = request.getBody().readUtf8(); - Map map = new ObjectMapper().readValue(content, new TypeReference>() {}); + Map map = new ObjectMapper().readValue(content, new TypeReference>() { + }); WebInput webInput = new WebInput(request.getRequestUrl().uri(), new HttpHeaders(), map, null); consumer.accept(webInput); @@ -390,8 +351,8 @@ public class GraphQlTesterTests { public void shutdown() throws Exception { this.server.shutdown(); } - } + } private static class MockWebGraphQlHandlerSetup implements GraphQlTesterSetup { @@ -401,7 +362,7 @@ public class GraphQlTesterTests { private final GraphQlTester graphQlTester; - public MockWebGraphQlHandlerSetup() { + MockWebGraphQlHandlerSetup() { this.graphQlTester = GraphQlTester.create(this.handler); } @@ -414,14 +375,15 @@ public class GraphQlTesterTests { public void response(@Nullable String data, List errors) throws Exception { ExecutionResultImpl.Builder builder = new ExecutionResultImpl.Builder(); if (data != null) { - builder.data(OBJECT_MAPPER.readValue(data, new TypeReference>() {})); + builder.data(OBJECT_MAPPER.readValue(data, new TypeReference>() { + })); } if (!CollectionUtils.isEmpty(errors)) { builder.addErrors(errors); } ExecutionResult result = builder.build(); WebOutput output = new WebOutput(mock(WebInput.class), result); - when(this.handler.handle(this.bodyCaptor.capture())).thenReturn(Mono.just(output)); + given(this.handler.handle(this.bodyCaptor.capture())).willReturn(Mono.just(output)); } @Override @@ -429,6 +391,7 @@ public class GraphQlTesterTests { WebInput webInput = this.bodyCaptor.getValue(); consumer.accept(webInput); } + } } diff --git a/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/MovieCharacter.java b/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/MovieCharacter.java index 17114709..bad8b1ec 100644 --- a/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/MovieCharacter.java +++ b/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/MovieCharacter.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.test.tester; import org.springframework.lang.Nullable; @@ -46,11 +47,12 @@ public class MovieCharacter { return false; } MovieCharacter movieCharacter = (MovieCharacter) other; - return (this.name != null ? this.name.equals(movieCharacter.name) : movieCharacter.name == null); + return (this.name != null) ? this.name.equals(movieCharacter.name) : movieCharacter.name == null; } @Override public int hashCode() { - return (this.name != null ? this.name.hashCode() : 0); + return (this.name != null) ? this.name.hashCode() : 0; } + }