diff --git a/samples/webflux-security/.graphqlconfig b/samples/webflux-security/.graphqlconfig new file mode 100644 index 00000000..607e05c0 --- /dev/null +++ b/samples/webflux-security/.graphqlconfig @@ -0,0 +1,5 @@ +{ + "name": "Spring WebFlux Security Sample Schema", + "schemaPath": "src/main/resources/graphql/schema.graphqls", + "extensions": {} +} \ No newline at end of file diff --git a/samples/webflux-security/src/main/resources/graphql/employeesNames.graphql b/samples/webflux-security/src/main/resources/graphql/employeesNames.graphql new file mode 100644 index 00000000..31b61667 --- /dev/null +++ b/samples/webflux-security/src/main/resources/graphql/employeesNames.graphql @@ -0,0 +1,5 @@ +query { + employees { + name + } +} \ No newline at end of file diff --git a/samples/webflux-security/src/main/resources/graphql/employeesNamesAndSalaries.graphql b/samples/webflux-security/src/main/resources/graphql/employeesNamesAndSalaries.graphql new file mode 100644 index 00000000..38cd30a5 --- /dev/null +++ b/samples/webflux-security/src/main/resources/graphql/employeesNamesAndSalaries.graphql @@ -0,0 +1,6 @@ +query { + employees { + name, + salary + } +} \ No newline at end of file diff --git a/samples/webflux-security/src/test/java/io/spring/sample/graphql/SampleApplicationTests.java b/samples/webflux-security/src/test/java/io/spring/sample/graphql/SampleApplicationTests.java index 5ee200b9..e945580b 100644 --- a/samples/webflux-security/src/test/java/io/spring/sample/graphql/SampleApplicationTests.java +++ b/samples/webflux-security/src/test/java/io/spring/sample/graphql/SampleApplicationTests.java @@ -37,14 +37,7 @@ class SampleApplicationTests { @Test void printError() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .execute() .errors() .satisfy(System.out::println); @@ -52,14 +45,7 @@ class SampleApplicationTests { @Test void anonymousThenUnauthorized() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .execute() .errors() .satisfy(errors -> { @@ -70,14 +56,7 @@ class SampleApplicationTests { @Test void userRoleThenForbidden() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .headers(headers -> headers.setBasicAuth("rob", "rob")) .execute() .errors() @@ -89,27 +68,14 @@ class SampleApplicationTests { @Test void canQueryName() { - String query = "{" + - " employees{ " + - " name" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNames") .execute() .path("employees[0].name").entity(String.class).isEqualTo("Andi"); } @Test void canNotQuerySalary() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .execute() .errors() .satisfy(errors -> { @@ -120,14 +86,7 @@ class SampleApplicationTests { @Test void canQuerySalaryAsAdmin() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .headers(headers -> headers.setBasicAuth("admin", "admin")) .execute() .path("employees[0].name").entity(String.class).isEqualTo("Andi") @@ -136,15 +95,8 @@ class SampleApplicationTests { @Test void invalidCredentials() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - assertThatThrownBy(() -> - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .headers(headers -> headers.setBasicAuth("admin", "INVALID")) .executeAndVerify()) .hasMessage("Status expected:<200 OK> but was:<401 UNAUTHORIZED>"); diff --git a/samples/webflux-websocket/.graphqlconfig b/samples/webflux-websocket/.graphqlconfig index 258ce389..54ea7cdf 100644 --- a/samples/webflux-websocket/.graphqlconfig +++ b/samples/webflux-websocket/.graphqlconfig @@ -1,15 +1,5 @@ { - "name": "Spring WebFlux+WebSocket GraphQL Sample Schema", + "name": "Spring WebFlux WebSocket Sample Schema", "schemaPath": "src/main/resources/graphql/schema.graphqls", - "extensions": { - "endpoints": { - "Local GraphQL Endpoint": { - "url": "http://localhost:8080/graphql", - "headers": { - "user-agent": "JS GraphQL" - }, - "introspect": false - } - } - } + "extensions": {} } \ No newline at end of file diff --git a/samples/webmvc-http-security/.graphqlconfig b/samples/webmvc-http-security/.graphqlconfig new file mode 100644 index 00000000..8a8ee379 --- /dev/null +++ b/samples/webmvc-http-security/.graphqlconfig @@ -0,0 +1,5 @@ +{ + "name": "Spring MVC HTTP Security Sample Schema", + "schemaPath": "src/main/resources/graphql/schema.graphqls", + "extensions": {} +} \ No newline at end of file diff --git a/samples/webmvc-http-security/src/main/resources/graphql/employeesNames.graphql b/samples/webmvc-http-security/src/main/resources/graphql/employeesNames.graphql new file mode 100644 index 00000000..31b61667 --- /dev/null +++ b/samples/webmvc-http-security/src/main/resources/graphql/employeesNames.graphql @@ -0,0 +1,5 @@ +query { + employees { + name + } +} \ No newline at end of file diff --git a/samples/webmvc-http-security/src/main/resources/graphql/employeesNamesAndSalaries.graphql b/samples/webmvc-http-security/src/main/resources/graphql/employeesNamesAndSalaries.graphql new file mode 100644 index 00000000..38cd30a5 --- /dev/null +++ b/samples/webmvc-http-security/src/main/resources/graphql/employeesNamesAndSalaries.graphql @@ -0,0 +1,6 @@ +query { + employees { + name, + salary + } +} \ No newline at end of file diff --git a/samples/webmvc-http-security/src/test/java/io/spring/sample/graphql/SampleApplicationTests.java b/samples/webmvc-http-security/src/test/java/io/spring/sample/graphql/SampleApplicationTests.java index 2201decd..eada64f3 100644 --- a/samples/webmvc-http-security/src/test/java/io/spring/sample/graphql/SampleApplicationTests.java +++ b/samples/webmvc-http-security/src/test/java/io/spring/sample/graphql/SampleApplicationTests.java @@ -22,14 +22,7 @@ class SampleApplicationTests { @Test void printError() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .execute() .errors() .satisfy(System.out::println); @@ -37,14 +30,7 @@ class SampleApplicationTests { @Test void anonymousThenUnauthorized() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .execute() .errors() .satisfy(errors -> { @@ -55,14 +41,7 @@ class SampleApplicationTests { @Test void userRoleThenForbidden() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .headers(headers -> headers.setBasicAuth("rob", "rob")) .execute() .errors() @@ -74,27 +53,14 @@ class SampleApplicationTests { @Test void canQueryName() { - String query = "{" + - " employees{ " + - " name" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNames") .execute() .path("employees[0].name").entity(String.class).isEqualTo("Andi"); } @Test void canNotQuerySalary() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .execute() .errors() .satisfy(errors -> { @@ -105,14 +71,7 @@ class SampleApplicationTests { @Test void canQuerySalaryAsAdmin() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .headers(headers -> headers.setBasicAuth("admin", "admin")) .execute() .path("employees[0].name").entity(String.class).isEqualTo("Andi") @@ -121,15 +80,8 @@ class SampleApplicationTests { @Test void invalidCredentials() { - String query = "{" + - " employees{ " + - " name" + - " salary" + - " }" + - "}"; - assertThatThrownBy(() -> - this.graphQlTester.query(query) + this.graphQlTester.queryName("employeesNamesAndSalaries") .headers(headers -> headers.setBasicAuth("admin", "INVALID")) .executeAndVerify()) .hasMessage("Status expected:<200 OK> but was:<401 UNAUTHORIZED>"); diff --git a/samples/webmvc-http/.graphqlconfig b/samples/webmvc-http/.graphqlconfig index e74b793d..7e0d5852 100644 --- a/samples/webmvc-http/.graphqlconfig +++ b/samples/webmvc-http/.graphqlconfig @@ -1,15 +1,5 @@ { - "name": "Spring MVC GraphQL Sample Schema", + "name": "Spring MVC HTTP Sample Schema", "schemaPath": "src/main/resources/graphql/schema.graphqls", - "extensions": { - "endpoints": { - "Local GraphQL Endpoint": { - "url": "http://localhost:8080/graphql", - "headers": { - "user-agent": "JS GraphQL" - }, - "introspect": false - } - } - } + "extensions": {} } \ No newline at end of file diff --git a/samples/webmvc-http/src/main/resources/graphql/artifactRepositories.graphql b/samples/webmvc-http/src/main/resources/graphql/artifactRepositories.graphql new file mode 100644 index 00000000..0da76c92 --- /dev/null +++ b/samples/webmvc-http/src/main/resources/graphql/artifactRepositories.graphql @@ -0,0 +1,5 @@ +query { + artifactRepositories { + id + } +} \ No newline at end of file diff --git a/samples/webmvc-http/src/main/resources/graphql/artifactRepository.graphql b/samples/webmvc-http/src/main/resources/graphql/artifactRepository.graphql new file mode 100644 index 00000000..1b64d983 --- /dev/null +++ b/samples/webmvc-http/src/main/resources/graphql/artifactRepository.graphql @@ -0,0 +1,5 @@ +query artifactRepository($id: ID!) { + artifactRepository(id: $id) { + name + } +} \ No newline at end of file diff --git a/samples/webmvc-http/src/main/resources/graphql/projectReleases.graphql b/samples/webmvc-http/src/main/resources/graphql/projectReleases.graphql new file mode 100644 index 00000000..9c8b96af --- /dev/null +++ b/samples/webmvc-http/src/main/resources/graphql/projectReleases.graphql @@ -0,0 +1,8 @@ +query project($slug: ID!) { + project(slug: $slug) { + repositoryUrl + releases { + version + } + } +} \ No newline at end of file diff --git a/samples/webmvc-http/src/main/resources/graphql/projectRepositoryUrl.graphql b/samples/webmvc-http/src/main/resources/graphql/projectRepositoryUrl.graphql new file mode 100644 index 00000000..09f479a0 --- /dev/null +++ b/samples/webmvc-http/src/main/resources/graphql/projectRepositoryUrl.graphql @@ -0,0 +1,5 @@ +query project($slug: ID!) { + project(slug: $slug) { + repositoryUrl + } +} \ No newline at end of file diff --git a/samples/webmvc-http/src/test/java/io/spring/sample/graphql/project/MockMvcGraphQlTests.java b/samples/webmvc-http/src/test/java/io/spring/sample/graphql/project/MockMvcGraphQlTests.java index 8d385ce7..8f90ed40 100644 --- a/samples/webmvc-http/src/test/java/io/spring/sample/graphql/project/MockMvcGraphQlTests.java +++ b/samples/webmvc-http/src/test/java/io/spring/sample/graphql/project/MockMvcGraphQlTests.java @@ -39,15 +39,8 @@ public class MockMvcGraphQlTests { @Test void jsonPath() { - String query = "{" + - " project(slug:\"spring-framework\") {" + - " releases {" + - " version" + - " }"+ - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("projectReleases") + .variable("slug", "spring-framework") .execute() .path("project.releases[*].version") .entityList(String.class) @@ -57,13 +50,8 @@ public class MockMvcGraphQlTests { @Test void jsonContent() { - String query = "{" + - " project(slug:\"spring-framework\") {" + - " repositoryUrl" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("projectRepositoryUrl") + .variable("slug", "spring-framework") .execute() .path("project") .matchesJson("{\"repositoryUrl\":\"http://github.com/spring-projects/spring-framework\"}"); @@ -71,15 +59,8 @@ public class MockMvcGraphQlTests { @Test void decodedResponse() { - String query = "{" + - " project(slug:\"spring-framework\") {" + - " releases {" + - " version" + - " }" + - " }" + - "}"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("projectReleases") + .variable("slug", "spring-framework") .execute() .path("project") .entity(Project.class) @@ -88,9 +69,8 @@ public class MockMvcGraphQlTests { @Test void querydslRepositorySingle() { - String query = "query { artifactRepository(id: \"spring-releases\") { name } }"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("artifactRepository") + .variable("id", "spring-releases") .execute() .path("artifactRepository.name") .entity(String.class).isEqualTo("Spring Releases"); @@ -98,9 +78,7 @@ public class MockMvcGraphQlTests { @Test void querydslRepositoryMany() { - String query = "query { artifactRepositories { id } }"; - - this.graphQlTester.query(query) + this.graphQlTester.queryName("artifactRepositories") .execute() .path("artifactRepositories[*].id") .entityList(String.class).containsExactly("spring-releases", "spring-milestones", "spring-snapshots"); diff --git a/spring-graphql-docs/src/docs/asciidoc/testing.adoc b/spring-graphql-docs/src/docs/asciidoc/testing.adoc index b2e5c90f..9a05f4c9 100644 --- a/spring-graphql-docs/src/docs/asciidoc/testing.adoc +++ b/spring-graphql-docs/src/docs/asciidoc/testing.adoc @@ -101,9 +101,9 @@ GraphQL response. ---- String query = "{" + " project(slug:\"spring-framework\") {" + - " releases {" + - " version" + - " }"+ + " releases {" + + " version" + + " }"+ " }" + "}"; @@ -116,6 +116,40 @@ GraphQL response. The JsonPath is relative to the "data" section of the response. +You can also create query files with extensions `.graphql` or `.gql` under `"graphql/"` on +the classpath and refer to them by file name. For example, given a file called +`projectReleases.graphql` in `src/main/resources/graphql`, with content: + +[source,graphql,indent=0,subs="verbatim,quotes"] +---- + query projectReleases($slug: ID!) { + project(slug: $slug) { + releases { + version + } + } + } +---- + +You can write the same test as follows: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + graphQlTester.queryName("projectReleases") <1> + .variable("slug", "spring-framework") <2> + .execute() + .path("project.releases[*].version") + .entityList(String.class) + .hasSizeGreaterThan(1); +---- +<1> Refer to the query in the file named "projectReleases". +<2> Set the `slug` variable. + +[TIP] +==== +The "JS GraphQL" plugin for IntelliJ supports GraphQL query files with code completion. +==== + [[testing-errors]] 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 d8b1f6c9..aa15b134 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 @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -48,10 +49,14 @@ class DefaultGraphQlTester implements GraphQlTester { private final RequestStrategy requestStrategy; + private final Function queryNameResolver; - DefaultGraphQlTester(RequestStrategy requestStrategy) { + + DefaultGraphQlTester(RequestStrategy requestStrategy, Function queryNameResolver) { Assert.notNull(requestStrategy, "RequestStrategy is required."); + Assert.notNull(queryNameResolver, "'queryNameResolver' is required."); this.requestStrategy = requestStrategy; + this.queryNameResolver = queryNameResolver; } @@ -60,6 +65,11 @@ class DefaultGraphQlTester implements GraphQlTester { return new DefaultRequestSpec(this.requestStrategy, query); } + @Override + public RequestSpec queryName(String queryName) { + return query(this.queryNameResolver.apply(queryName)); + } + /** * Factory for {@link GraphQlTester.ResponseSpec}, for use from diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTesterBuilder.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTesterBuilder.java index e9bf883d..89be89d2 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTesterBuilder.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTesterBuilder.java @@ -65,7 +65,7 @@ class DefaultGraphQlTesterBuilder RequestStrategy strategy = new GraphQlServiceRequestStrategy( this.service, getErrorFilter(), initJsonPathConfig(), initResponseTimeout()); - return new DefaultGraphQlTester(strategy); + return new DefaultGraphQlTester(strategy, getQueryNameResolver()); } } diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTester.java index 173c5222..96bbd7de 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTester.java @@ -18,6 +18,7 @@ package org.springframework.graphql.test.tester; import java.net.URI; import java.util.function.Consumer; +import java.util.function.Function; import reactor.core.publisher.Flux; @@ -39,11 +40,17 @@ class DefaultWebGraphQlTester implements WebGraphQlTester { @Nullable private final HttpHeaders defaultHeaders; + private final Function queryNameResolver; + + + DefaultWebGraphQlTester( + WebRequestStrategy requestStrategy, @Nullable HttpHeaders defaultHeaders, + Function queryNameResolver) { - DefaultWebGraphQlTester(WebRequestStrategy requestStrategy, @Nullable HttpHeaders defaultHeaders) { Assert.notNull(requestStrategy, "WebRequestStrategy is required."); this.requestStrategy = requestStrategy; this.defaultHeaders = defaultHeaders; + this.queryNameResolver = queryNameResolver; } @@ -52,6 +59,11 @@ class DefaultWebGraphQlTester implements WebGraphQlTester { return new DefaultWebRequestSpec(this.requestStrategy, this.defaultHeaders, query); } + @Override + public WebRequestSpec queryName(String queryName) { + return query(this.queryNameResolver.apply(queryName)); + } + /** * Factory for {@link WebGraphQlTester.ResponseSpec}, for use from diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTesterBuilder.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTesterBuilder.java index f6b2a8e5..0e37662c 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTesterBuilder.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTesterBuilder.java @@ -96,7 +96,7 @@ final class DefaultWebGraphQlTesterBuilder @Override public WebGraphQlTester build() { - return new DefaultWebGraphQlTester(initRequestStrategy(), this.headers); + return new DefaultWebGraphQlTester(initRequestStrategy(), this.headers, getQueryNameResolver()); } private WebRequestStrategy initRequestStrategy() { 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 28cb968f..035ec428 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 @@ -52,6 +52,16 @@ public interface GraphQlTester { */ RequestSpec query(String query); + /** + * Refer to a query by name where the given name is to look for a file with + * the same name and extension {@code ".graphql"} or {@code ".gql"} under + * classpath location {@code "graphql/"}. + * @return spec for response assertions + * @throws IllegalArgumentException if the queryName cannot be resolved + * @throws AssertionError if the response status is not 200 (OK) + */ + RequestSpec queryName(String queryName); + /** * Create a {@code GraphQlTester} that performs GraphQL requests through the diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTesterBuilderSupport.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTesterBuilderSupport.java index 07f8446d..8f1e2a0f 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTesterBuilderSupport.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTesterBuilderSupport.java @@ -15,7 +15,12 @@ */ package org.springframework.graphql.test.tester; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.util.Arrays; +import java.util.function.Function; import java.util.function.Predicate; import com.jayway.jsonpath.Configuration; @@ -23,9 +28,12 @@ import com.jayway.jsonpath.spi.json.JacksonJsonProvider; import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider; import graphql.GraphQLError; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.FileCopyUtils; /** * Base class support for implementations of @@ -56,6 +64,8 @@ class GraphQlTesterBuilderSupport { @Nullable private Duration responseTimeout; + private final Function queryNameResolver = new QueryNameResolver(); + protected void addErrorFilter(Predicate predicate) { this.errorFilter = (this.errorFilter != null ? errorFilter.and(predicate) : predicate); @@ -80,6 +90,10 @@ class GraphQlTesterBuilderSupport { return this.responseTimeout; } + protected Function getQueryNameResolver() { + return this.queryNameResolver; + } + protected Configuration initJsonPathConfig() { if (this.jsonPathConfig != null) { return this.jsonPathConfig; @@ -97,6 +111,39 @@ class GraphQlTesterBuilderSupport { } + private static class QueryNameResolver implements Function { + + private static final ClassPathResource LOCATION = new ClassPathResource("graphql/"); + + private static final String[] EXTENSIONS = new String[] {".graphql", ".gql"}; + + @Override + public String apply(String queryName) { + Resource queryResource = getQueryResource(queryName); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + FileCopyUtils.copy(queryResource.getInputStream(), outputStream); + } + catch (IOException ex) { + throw new IllegalArgumentException("Failed to read query from: " + LOCATION.getPath()); + } + return new String(outputStream.toByteArray(), StandardCharsets.UTF_8); + } + + private Resource getQueryResource(String queryName) { + for (String extension : EXTENSIONS) { + Resource resource = LOCATION.createRelative(queryName + extension); + if (resource.exists()) { + return resource; + } + } + throw new IllegalArgumentException( + "Could not find file '" + queryName + "' with extensions " + Arrays.toString(EXTENSIONS) + + " under " + LOCATION.getDescription()); + } + } + + private static class Jackson2Configuration { static Configuration create() { diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlTester.java index 2a86b0e3..eb6eb2eb 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlTester.java @@ -88,6 +88,13 @@ public interface WebGraphQlTester extends GraphQlTester { */ WebRequestSpec query(String query); + /** + * {@inheritDoc} + *

The returned spec for Web request input also allows adding HTTP headers. + */ + WebRequestSpec queryName(String queryName); + + /** * Create a {@code WebGraphQlTester} that performs GraphQL requests as an