GraphQlTester and WebGraphQlTester builders
Closes gh-66
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
|
||||
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Assist with collecting the input for {@link GraphQlTester.Builder},
|
||||
* essentially to avoid challenges with generics in the builder hierarchy.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
final class BuilderDelegate {
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = DefaultGraphQlTester.class.getClassLoader();
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
|
||||
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private Configuration jsonPathConfig;
|
||||
|
||||
private Duration responseTimeout = Duration.ofSeconds(5);
|
||||
|
||||
public void jsonPathConfig(@Nullable Configuration config) {
|
||||
this.jsonPathConfig = config;
|
||||
}
|
||||
|
||||
public void responseTimeout(Duration timeout) {
|
||||
Assert.notNull(timeout, "'timeout' is required");
|
||||
this.responseTimeout = timeout;
|
||||
}
|
||||
|
||||
public Configuration initJsonPathConfig() {
|
||||
if (this.jsonPathConfig != null) {
|
||||
return this.jsonPathConfig;
|
||||
}
|
||||
else if (jackson2Present) {
|
||||
return Jackson2Configuration.create();
|
||||
}
|
||||
else {
|
||||
return Configuration.builder().build();
|
||||
}
|
||||
}
|
||||
|
||||
public Duration getResponseTimeout() {
|
||||
return this.responseTimeout;
|
||||
}
|
||||
|
||||
|
||||
private static class Jackson2Configuration {
|
||||
|
||||
static Configuration create() {
|
||||
return Configuration.builder()
|
||||
.jsonProvider(new JacksonJsonProvider())
|
||||
.mappingProvider(new JacksonMappingProvider())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,8 +32,7 @@ import com.jayway.jsonpath.DocumentContext;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import com.jayway.jsonpath.PathNotFoundException;
|
||||
import com.jayway.jsonpath.TypeRef;
|
||||
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
|
||||
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
|
||||
import graphql.ExecutionInput;
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.GraphQLError;
|
||||
import org.reactivestreams.Publisher;
|
||||
@@ -47,7 +46,6 @@ import org.springframework.test.util.AssertionErrors;
|
||||
import org.springframework.test.util.JsonExpectationsHelper;
|
||||
import org.springframework.test.util.JsonPathExpectationsHelper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -58,20 +56,11 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
class DefaultGraphQlTester implements GraphQlTester {
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = DefaultGraphQlTester.class.getClassLoader();
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
|
||||
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||
}
|
||||
|
||||
|
||||
private final RequestStrategy requestStrategy;
|
||||
|
||||
|
||||
DefaultGraphQlTester(GraphQlService service) {
|
||||
this(new GraphQlServiceRequestStrategy(service, initJsonPathConfig()));
|
||||
DefaultGraphQlTester(GraphQlService service, Configuration config, Duration responseTimeout) {
|
||||
this(new GraphQlServiceRequestStrategy(service, config, responseTimeout));
|
||||
}
|
||||
|
||||
DefaultGraphQlTester(RequestStrategy requestStrategy) {
|
||||
@@ -84,17 +73,48 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
}
|
||||
|
||||
|
||||
protected static Configuration initJsonPathConfig() {
|
||||
return (jackson2Present ? Jackson2Configuration.create() : Configuration.builder().build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestSpec query(String query) {
|
||||
return new DefaultRequestSpec(this.requestStrategy, query);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulate how a GraphQL request is performed.
|
||||
* Default implementation to build {@link GraphQlTester}.
|
||||
*/
|
||||
final static class DefaultBuilder implements Builder<DefaultBuilder> {
|
||||
|
||||
private final GraphQlService service;
|
||||
|
||||
private final BuilderDelegate delegate = new BuilderDelegate();
|
||||
|
||||
DefaultBuilder(GraphQlService service) {
|
||||
Assert.notNull(service, "GraphQlService is required.");
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder jsonPathConfig(Configuration config) {
|
||||
this.delegate.jsonPathConfig(config);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder responseTimeout(Duration timeout) {
|
||||
this.delegate.responseTimeout(timeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphQlTester build() {
|
||||
return new DefaultGraphQlTester(
|
||||
this.service, this.delegate.initJsonPathConfig(), this.delegate.getResponseTimeout());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal strategy abstracting how a GraphQL request is performed.
|
||||
*/
|
||||
interface RequestStrategy {
|
||||
|
||||
@@ -121,12 +141,17 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
*/
|
||||
protected abstract static class AbstractDirectRequestStrategy implements RequestStrategy {
|
||||
|
||||
protected static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(5);
|
||||
|
||||
private final Configuration jsonPathConfig;
|
||||
|
||||
protected AbstractDirectRequestStrategy(Configuration jsonPathConfig) {
|
||||
private final Duration responseTimeout;
|
||||
|
||||
protected AbstractDirectRequestStrategy(Configuration jsonPathConfig, Duration responseTimeout) {
|
||||
this.jsonPathConfig = jsonPathConfig;
|
||||
this.responseTimeout = responseTimeout;
|
||||
}
|
||||
|
||||
protected Duration getResponseTimeout() {
|
||||
return this.responseTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -174,13 +199,17 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
|
||||
private final GraphQlService graphQlService;
|
||||
|
||||
protected GraphQlServiceRequestStrategy(GraphQlService service, Configuration jsonPathConfig) {
|
||||
super(jsonPathConfig);
|
||||
protected GraphQlServiceRequestStrategy(
|
||||
GraphQlService service, Configuration jsonPathConfig, Duration responseTimeout) {
|
||||
|
||||
super(jsonPathConfig, responseTimeout);
|
||||
Assert.notNull(service, "GraphQlService is required.");
|
||||
this.graphQlService = service;
|
||||
}
|
||||
|
||||
protected ExecutionResult executeInternal(RequestInput input) {
|
||||
ExecutionResult result = this.graphQlService.execute(input.toExecutionInput()).block(DEFAULT_TIMEOUT);
|
||||
ExecutionInput executionInput = input.toExecutionInput();
|
||||
ExecutionResult result = this.graphQlService.execute(executionInput).block(getResponseTimeout());
|
||||
Assert.notNull(result, "Expected ExecutionResult");
|
||||
return result;
|
||||
}
|
||||
@@ -711,13 +740,4 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
|
||||
}
|
||||
|
||||
private static class Jackson2Configuration {
|
||||
|
||||
static Configuration create() {
|
||||
return Configuration.builder().jsonProvider(new JacksonJsonProvider())
|
||||
.mappingProvider(new JacksonMappingProvider()).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.DocumentContext;
|
||||
@@ -30,10 +32,12 @@ import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
import org.springframework.graphql.web.WebInput;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.FluxExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link WebGraphQlTester}.
|
||||
@@ -42,22 +46,82 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQlTester {
|
||||
|
||||
@Nullable
|
||||
private final HttpHeaders defaultHeaders;
|
||||
|
||||
DefaultWebGraphQlTester(WebTestClient client) {
|
||||
super(new WebTestClientRequestStrategy(client, initJsonPathConfig()));
|
||||
}
|
||||
|
||||
DefaultWebGraphQlTester(WebGraphQlHandler handler) {
|
||||
super(new WebGraphQlHandlerRequestStrategy(handler, initJsonPathConfig()));
|
||||
DefaultWebGraphQlTester(RequestStrategy requestStrategy, @Nullable HttpHeaders defaultHeaders) {
|
||||
super(requestStrategy);
|
||||
this.defaultHeaders = defaultHeaders;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public WebRequestSpec query(String query) {
|
||||
return new DefaultWebRequestSpec(getRequestStrategy(), query);
|
||||
return new DefaultWebRequestSpec(getRequestStrategy(), query, this.defaultHeaders);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation to build {@link WebGraphQlTester}.
|
||||
*/
|
||||
final static class DefaultBuilder implements WebGraphQlTester.Builder {
|
||||
|
||||
private final Supplier<RequestStrategy> requestStrategySupplier;
|
||||
|
||||
private final BuilderDelegate delegate = new BuilderDelegate();
|
||||
|
||||
@Nullable
|
||||
private HttpHeaders headers;
|
||||
|
||||
DefaultBuilder(WebTestClient client) {
|
||||
this.requestStrategySupplier = () ->
|
||||
new WebTestClientRequestStrategy(
|
||||
client.mutate().responseTimeout(this.delegate.getResponseTimeout()).build(),
|
||||
this.delegate.initJsonPathConfig());
|
||||
}
|
||||
|
||||
DefaultBuilder(WebGraphQlHandler handler) {
|
||||
this.requestStrategySupplier = () ->
|
||||
new WebGraphQlHandlerRequestStrategy(handler,
|
||||
this.delegate.initJsonPathConfig(),
|
||||
this.delegate.getResponseTimeout());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder jsonPathConfig(Configuration config) {
|
||||
this.delegate.jsonPathConfig(config);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder responseTimeout(Duration timeout) {
|
||||
this.delegate.responseTimeout(timeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder defaultHeader(String headerName, String... headerValues) {
|
||||
this.headers = (this.headers != null ? this.headers : new HttpHeaders());
|
||||
for (String headerValue : headerValues) {
|
||||
this.headers.add(headerName, headerValue);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester.Builder defaultHeaders(Consumer<HttpHeaders> headersConsumer) {
|
||||
this.headers = (this.headers != null ? this.headers : new HttpHeaders());
|
||||
headersConsumer.accept(this.headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester build() {
|
||||
return new DefaultWebGraphQlTester(this.requestStrategySupplier.get(), this.headers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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
|
||||
@@ -76,12 +140,9 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
|
||||
|
||||
@Override
|
||||
public ResponseSpec execute(RequestInput requestInput) {
|
||||
Assert.isInstanceOf(WebInput.class, requestInput);
|
||||
WebInput webInput = (WebInput) requestInput;
|
||||
|
||||
EntityExchangeResult<byte[]> result = this.client.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.headers(headers -> headers.putAll(webInput.getHeaders()))
|
||||
.headers(headers -> headers.putAll(getHeaders(requestInput)))
|
||||
.bodyValue(requestInput)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
@@ -101,13 +162,10 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
|
||||
|
||||
@Override
|
||||
public SubscriptionSpec executeSubscription(RequestInput requestInput) {
|
||||
Assert.isInstanceOf(WebInput.class, requestInput);
|
||||
WebInput webInput = (WebInput) requestInput;
|
||||
|
||||
FluxExchangeResult<TestExecutionResult> exchangeResult = this.client.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.TEXT_EVENT_STREAM)
|
||||
.headers(headers -> headers.putAll(webInput.getHeaders()))
|
||||
.headers(headers -> headers.putAll(getHeaders(requestInput)))
|
||||
.bodyValue(requestInput)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
@@ -120,6 +178,11 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
|
||||
this.jsonPathConfig, exchangeResult::assertWithDiagnostics);
|
||||
}
|
||||
|
||||
private HttpHeaders getHeaders(RequestInput requestInput) {
|
||||
Assert.isInstanceOf(WebInput.class, requestInput);
|
||||
return ((WebInput) requestInput).getHeaders();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,27 +193,32 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
|
||||
|
||||
private final WebGraphQlHandler graphQlHandler;
|
||||
|
||||
WebGraphQlHandlerRequestStrategy(WebGraphQlHandler handler, Configuration jsonPathConfig) {
|
||||
super(jsonPathConfig);
|
||||
WebGraphQlHandlerRequestStrategy(WebGraphQlHandler handler, Configuration config, Duration responseTimeout) {
|
||||
super(config, responseTimeout);
|
||||
this.graphQlHandler = handler;
|
||||
}
|
||||
|
||||
protected ExecutionResult executeInternal(RequestInput requestInput) {
|
||||
Assert.isInstanceOf(WebInput.class, requestInput);
|
||||
ExecutionResult result = this.graphQlHandler.handle((WebInput) requestInput).block(DEFAULT_TIMEOUT);
|
||||
protected ExecutionResult executeInternal(RequestInput input) {
|
||||
Assert.isInstanceOf(WebInput.class, input);
|
||||
WebInput webInput = (WebInput) input;
|
||||
ExecutionResult result = this.graphQlHandler.handle(webInput).block(getResponseTimeout());
|
||||
Assert.notNull(result, "Expected ExecutionResult");
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static final class DefaultWebRequestSpec extends DefaultRequestSpec implements WebRequestSpec {
|
||||
private static final class DefaultWebRequestSpec extends DefaultRequestSpec implements WebRequestSpec {
|
||||
|
||||
private static final URI DEFAULT_URL = URI.create("");
|
||||
|
||||
private final HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
public DefaultWebRequestSpec(RequestStrategy requestStrategy, String query) {
|
||||
DefaultWebRequestSpec(RequestStrategy requestStrategy, String query, @Nullable HttpHeaders headers) {
|
||||
super(requestStrategy, query);
|
||||
if (!CollectionUtils.isEmpty(headers)) {
|
||||
this.headers.putAll(headers);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,7 +238,7 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
|
||||
@Override
|
||||
protected RequestInput createRequestInput() {
|
||||
RequestInput requestInput = super.createRequestInput();
|
||||
return new WebInput(DEFAULT_URL, headers, requestInput.toMap(), null);
|
||||
return new WebInput(DEFAULT_URL, this.headers, requestInput.toMap(), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import graphql.GraphQLError;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@@ -43,25 +44,65 @@ import org.springframework.lang.Nullable;
|
||||
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);
|
||||
RequestSpec<?> query(String query);
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@code GraphQlTester} that performs GraphQL requests through the given
|
||||
* {@link GraphQlService}.
|
||||
* Create a {@code GraphQlTester} that performs GraphQL requests through the
|
||||
* given {@link GraphQlService}.
|
||||
* @param service the service to execute requests with
|
||||
* @return the created {@code GraphQlTester}
|
||||
*/
|
||||
static GraphQlTester create(GraphQlService service) {
|
||||
return new DefaultGraphQlTester(service);
|
||||
return builder(service).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a builder with options to initialize a {@code GraphQlTester}.
|
||||
* @param service the service to execute requests with
|
||||
* @return the builder to use
|
||||
*/
|
||||
static Builder<?> builder(GraphQlService service) {
|
||||
return new DefaultGraphQlTester.DefaultBuilder(service);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A builder to create a {@link GraphQlTester} instance.
|
||||
*/
|
||||
interface Builder<T extends Builder<T>> {
|
||||
|
||||
/**
|
||||
* Provide JSONPath configuration settings, including a
|
||||
* {@link com.jayway.jsonpath.spi.json.JsonProvider} as well as a
|
||||
* {@link com.jayway.jsonpath.spi.mapper.MappingProvider} that are used
|
||||
* to serialize and deserialize GraphQL JSON content.
|
||||
* <p>By default the configuration is to use Jackson JSON if it is
|
||||
* present on the classpath.
|
||||
* @param config the JSONPath configuration to use
|
||||
* @return the same builder instance
|
||||
*/
|
||||
T jsonPathConfig(Configuration config);
|
||||
|
||||
/**
|
||||
* Max amount of time to wait for a GraphQL response.
|
||||
* <p>By default this is set to 5 seconds.
|
||||
* @param timeout the response timeout value
|
||||
*/
|
||||
T responseTimeout(Duration timeout);
|
||||
|
||||
/**
|
||||
* Build the {@code GraphQlTester}.
|
||||
* @return the created instance
|
||||
*/
|
||||
GraphQlTester build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare options to perform a GraphQL request.
|
||||
|
||||
@@ -88,6 +88,7 @@ public interface WebGraphQlTester extends GraphQlTester {
|
||||
*/
|
||||
WebRequestSpec query(String query);
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@code WebGraphQlTester} that performs GraphQL requests as an
|
||||
* HTTP client through the given {@link WebTestClient}. Depending on how the
|
||||
@@ -97,7 +98,7 @@ public interface WebGraphQlTester extends GraphQlTester {
|
||||
* @return the created {@code WebGraphQlTester}
|
||||
*/
|
||||
static WebGraphQlTester create(WebTestClient client) {
|
||||
return new DefaultWebGraphQlTester(client);
|
||||
return builder(client).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +108,54 @@ public interface WebGraphQlTester extends GraphQlTester {
|
||||
* @return the created {@code WebGraphQlTester}
|
||||
*/
|
||||
static WebGraphQlTester create(WebGraphQlHandler handler) {
|
||||
return new DefaultWebGraphQlTester(handler);
|
||||
return builder(handler).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a builder with options to initialize a {@code WebGraphQlTester}.
|
||||
* @param client the client to execute requests with
|
||||
* @return the builder to use
|
||||
*/
|
||||
static Builder builder(WebTestClient client) {
|
||||
return new DefaultWebGraphQlTester.DefaultBuilder(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a builder with options to initialize a {@code WebGraphQlHandler}.
|
||||
* @param handler the handler to execute requests with
|
||||
* @return the builder to use
|
||||
*/
|
||||
static Builder builder(WebGraphQlHandler handler) {
|
||||
return new DefaultWebGraphQlTester.DefaultBuilder(handler);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A builder to create a {@link WebGraphQlTester} instance.
|
||||
*/
|
||||
interface Builder extends GraphQlTester.Builder<Builder> {
|
||||
|
||||
/**
|
||||
* Add the given header to all requests that haven't added it.
|
||||
* @param headerName the header name
|
||||
* @param headerValues the header values
|
||||
*/
|
||||
Builder defaultHeader(String headerName, String... headerValues);
|
||||
|
||||
/**
|
||||
* Variant of {@link #defaultHeader(String, String...)} that provides
|
||||
* access to the underlying headers to inspect or modify directly.
|
||||
* @param headersConsumer a function that consumes the {@code HttpHeaders}
|
||||
*/
|
||||
Builder defaultHeaders(Consumer<HttpHeaders> headersConsumer);
|
||||
|
||||
/**
|
||||
* Build the {@code WebGraphQlTester}.
|
||||
* @return the created instance
|
||||
*/
|
||||
@Override
|
||||
WebGraphQlTester build();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,27 +71,62 @@ public class WebGraphQlTesterTests {
|
||||
return Stream.of(new MockWebServerSetup(), new MockWebGraphQlHandlerSetup());
|
||||
}
|
||||
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("argumentSource")
|
||||
void pathAndValueExistsAndEmptyChecks(GraphQlTesterSetup setup) throws Exception {
|
||||
void headers(GraphQlTesterSetup setup) throws Exception {
|
||||
|
||||
String query = "{me {name, friends}}";
|
||||
setup.response("{\"me\": {\"name\":\"Luke Skywalker\", \"friends\":[]}}");
|
||||
|
||||
GraphQlTester.ResponseSpec spec = setup.graphQlTester().query(query).execute();
|
||||
GraphQlTester.ResponseSpec spec = setup.graphQlTester().query(query)
|
||||
.header("myHeader1", "myValue1a")
|
||||
.header("myHeader1", "myValue1b")
|
||||
.headers(headers -> headers.add("myHeader2", "myValue2"))
|
||||
.execute();
|
||||
|
||||
spec.path("me.name").pathExists().valueExists().valueIsNotEmpty();
|
||||
spec.path("me.friends").valueIsEmpty();
|
||||
spec.path("hero").pathDoesNotExist().valueDoesNotExist().valueIsEmpty();
|
||||
spec.path("me.name").entity(String.class).isEqualTo("Luke Skywalker");
|
||||
|
||||
setup.verifyRequest((input) -> {
|
||||
assertThat(input.getQuery()).contains(query);
|
||||
assertThat(input.getHeaders().get("myHeader1")).containsExactly("myValue1a", "myValue1b");
|
||||
assertThat(input.getHeaders().getFirst("myHeader2")).isEqualTo("myValue2");
|
||||
});
|
||||
setup.shutdown();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("argumentSource")
|
||||
void defaultHeaders(GraphQlTesterSetup setup) throws Exception {
|
||||
|
||||
String query = "{me {name, friends}}";
|
||||
setup.response("{\"me\": {\"name\":\"Luke Skywalker\", \"friends\":[]}}");
|
||||
|
||||
GraphQlTester.ResponseSpec spec = setup.graphQlTesterBuilder()
|
||||
.defaultHeader("myHeader1", "myValue1a")
|
||||
.defaultHeader("myHeader1", "myValue1b")
|
||||
.defaultHeaders(headers -> headers.add("myHeader2", "myValue2"))
|
||||
.build()
|
||||
.query(query)
|
||||
.execute();
|
||||
|
||||
spec.path("me.name").entity(String.class).isEqualTo("Luke Skywalker");
|
||||
|
||||
setup.verifyRequest((input) -> {
|
||||
assertThat(input.getQuery()).contains(query);
|
||||
assertThat(input.getHeaders().get("myHeader1")).containsExactly("myValue1a", "myValue1b");
|
||||
assertThat(input.getHeaders().getFirst("myHeader2")).isEqualTo("myValue2");
|
||||
});
|
||||
|
||||
setup.verifyRequest((input) -> assertThat(input.getQuery()).contains(query));
|
||||
setup.shutdown();
|
||||
}
|
||||
|
||||
|
||||
private interface GraphQlTesterSetup {
|
||||
|
||||
GraphQlTester graphQlTester();
|
||||
WebGraphQlTester graphQlTester();
|
||||
|
||||
WebGraphQlTester.Builder graphQlTesterBuilder();
|
||||
|
||||
default void response(String data) throws Exception {
|
||||
response(data, Collections.emptyList());
|
||||
@@ -115,11 +150,11 @@ public class WebGraphQlTesterTests {
|
||||
|
||||
private final MockWebServer server;
|
||||
|
||||
private final GraphQlTester graphQlTester;
|
||||
private final WebGraphQlTester.Builder graphQlTesterBuilder;
|
||||
|
||||
MockWebServerSetup() {
|
||||
this.server = new MockWebServer();
|
||||
this.graphQlTester = WebGraphQlTester.create(initWebTestClient(this.server));
|
||||
this.graphQlTesterBuilder = WebGraphQlTester.builder(initWebTestClient(this.server));
|
||||
}
|
||||
|
||||
private static WebTestClient initWebTestClient(MockWebServer server) {
|
||||
@@ -128,8 +163,13 @@ public class WebGraphQlTesterTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphQlTester graphQlTester() {
|
||||
return this.graphQlTester;
|
||||
public WebGraphQlTester graphQlTester() {
|
||||
return this.graphQlTesterBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester.Builder graphQlTesterBuilder() {
|
||||
return this.graphQlTesterBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,10 +200,12 @@ public class WebGraphQlTesterTests {
|
||||
RecordedRequest request = this.server.takeRequest();
|
||||
assertThat(request.getHeader(HttpHeaders.CONTENT_TYPE)).isEqualTo("application/json");
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
request.getHeaders().names().forEach(name -> headers.put(name, request.getHeaders().values(name)));
|
||||
|
||||
String content = request.getBody().readUtf8();
|
||||
Map<String, Object> map = new ObjectMapper().readValue(content, new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
WebInput webInput = new WebInput(request.getRequestUrl().uri(), new HttpHeaders(), map, null);
|
||||
Map<String, Object> map = new ObjectMapper().readValue(content, new TypeReference<Map<String, Object>>() {});
|
||||
WebInput webInput = new WebInput(request.getRequestUrl().uri(), headers, map, null);
|
||||
|
||||
consumer.accept(webInput);
|
||||
}
|
||||
@@ -181,15 +223,20 @@ public class WebGraphQlTesterTests {
|
||||
|
||||
private final ArgumentCaptor<WebInput> bodyCaptor = ArgumentCaptor.forClass(WebInput.class);
|
||||
|
||||
private final GraphQlTester graphQlTester;
|
||||
private final WebGraphQlTester.Builder graphQlTesterBuilder;
|
||||
|
||||
MockWebGraphQlHandlerSetup() {
|
||||
this.graphQlTester = WebGraphQlTester.create(this.handler);
|
||||
this.graphQlTesterBuilder = WebGraphQlTester.builder(this.handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphQlTester graphQlTester() {
|
||||
return this.graphQlTester;
|
||||
public WebGraphQlTester graphQlTester() {
|
||||
return this.graphQlTesterBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester.Builder graphQlTesterBuilder() {
|
||||
return this.graphQlTesterBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user