Skip to content
This repository was archived by the owner on Dec 19, 2023. It is now read-only.

Commit 5b7ca34

Browse files
authored
Merge pull request #807 from bsara/add-ability-to-pass-strings-to-graphqltesttemplate
feat: added ability to use strings for GraphQl queries when using GraphQLTestTemplate
2 parents c6578cb + 7ab48d2 commit 5b7ca34

File tree

2 files changed

+306
-1
lines changed

2 files changed

+306
-1
lines changed

graphql-spring-boot-test/src/main/java/com/graphql/spring/boot/test/GraphQLTestTemplate.java

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.graphql.spring.boot.test;
22

3+
import static java.util.Objects.isNull;
34
import static java.util.Objects.nonNull;
5+
import static java.util.Objects.requireNonNull;
46

57
import com.fasterxml.jackson.core.JsonProcessingException;
68
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -12,7 +14,10 @@
1214
import java.util.Arrays;
1315
import java.util.Collections;
1416
import java.util.List;
17+
import java.util.Map;
1518
import java.util.function.IntFunction;
19+
import java.util.regex.Matcher;
20+
import java.util.regex.Pattern;
1621
import lombok.Getter;
1722
import lombok.NonNull;
1823
import org.springframework.beans.factory.annotation.Value;
@@ -32,6 +37,11 @@
3237
/** Helper class to test GraphQL queries and mutations. */
3338
public class GraphQLTestTemplate {
3439

40+
private static final Pattern GRAPHQL_OP_NAME_PATTERN = Pattern.compile(
41+
"(query|mutation|subscription)\\s+([a-z0-9]+)\\s*[({]",
42+
(Pattern.CASE_INSENSITIVE | Pattern.MULTILINE)
43+
);
44+
3545
private final ResourceLoader resourceLoader;
3646
private final TestRestTemplate restTemplate;
3747
private final String graphqlMapping;
@@ -57,7 +67,9 @@ private String createJsonQuery(String graphql, String operation, ObjectNode vari
5767
if (nonNull(operation)) {
5868
wrapper.put("operationName", operation);
5969
}
60-
wrapper.set("variables", variables);
70+
if (nonNull(variables)) {
71+
wrapper.set("variables", variables);
72+
}
6173
return objectMapper.writeValueAsString(wrapper);
6274
}
6375

@@ -72,6 +84,16 @@ private String loadResource(Resource resource) throws IOException {
7284
}
7385
}
7486

87+
private String getOperationName(String graphql) {
88+
if (isNull(graphql)) {
89+
return null;
90+
}
91+
92+
Matcher matcher = GRAPHQL_OP_NAME_PATTERN.matcher(graphql);
93+
94+
return (matcher.find() ? matcher.group(2) : null);
95+
}
96+
7597
/**
7698
* Add an HTTP header that will be sent with each request this sends.
7799
*
@@ -411,6 +433,95 @@ public GraphQLResponse postFiles(
411433
return postRequest(RequestFactory.forMultipart(values, headers));
412434
}
413435

436+
/**
437+
* Performs a GraphQL request using the provided GraphQL query string.
438+
*
439+
* Operation name will be derived from the provided GraphQL query string.
440+
*
441+
* @param graphql the GraphQL query
442+
* @return {@link GraphQLResponse} containing the result of the query execution
443+
* @throws IOException if the request json cannot be created because of issues with one of the
444+
* provided arguments
445+
*/
446+
public GraphQLResponse postForString(String graphql) throws IOException {
447+
return postForString(graphql, getOperationName(graphql), ((ObjectNode) null));
448+
}
449+
450+
/**
451+
* Performs a GraphQL request using the provided GraphQL query string and operation name.
452+
*
453+
* @param graphql the GraphQL query
454+
* @param operation the name of the GraphQL operation to be executed
455+
* @return {@link GraphQLResponse} containing the result of the query execution
456+
* @throws IOException if the request json cannot be created because of issues with one of the
457+
* provided arguments
458+
*/
459+
public GraphQLResponse postForString(String graphql, String operation) throws IOException {
460+
return postForString(graphql, operation, ((ObjectNode) null));
461+
}
462+
463+
/**
464+
* Performs a GraphQL request using the provided GraphQL query string and variables.
465+
*
466+
* Operation name will be derived from the provided GraphQL query string.
467+
*
468+
* @param graphql the GraphQL query
469+
* @param variables the input variables for the GraphQL query
470+
* @return {@link GraphQLResponse} containing the result of the query execution
471+
* @throws IOException if the request json cannot be created because of issues with one of the
472+
* provided arguments
473+
*/
474+
public GraphQLResponse postForString(String graphql, Map<String, ?> variables) throws IOException {
475+
return postForString(graphql, getOperationName(graphql), variables);
476+
}
477+
478+
/**
479+
* Performs a GraphQL request using the provided GraphQL query string, operation name, and
480+
* variables.
481+
*
482+
* @param graphql the GraphQL query
483+
* @param operation the name of the GraphQL operation to be executed
484+
* @param variables the input variables for the GraphQL query
485+
* @return {@link GraphQLResponse} containing the result of the query execution
486+
* @throws IOException if the request json cannot be created because of issues with one of the
487+
* provided arguments
488+
*/
489+
public GraphQLResponse postForString(String graphql, String operation, Map<String, ?> variables) throws IOException {
490+
return postForString(graphql, operation, ((ObjectNode) new ObjectMapper().valueToTree(variables)));
491+
}
492+
493+
/**
494+
* Performs a GraphQL request using the provided GraphQL query string and variables.
495+
*
496+
* Operation name will be derived from the provided GraphQL query string.
497+
*
498+
* @param graphql the GraphQL query
499+
* @param variables the input variables for the GraphQL query
500+
* @return {@link GraphQLResponse} containing the result of the query execution
501+
* @throws IOException if the request json cannot be created because of issues with one of the
502+
* provided arguments
503+
*/
504+
public GraphQLResponse postForString(String graphql, ObjectNode variables) throws IOException {
505+
return post(createJsonQuery(graphql, getOperationName(graphql), variables));
506+
}
507+
508+
/**
509+
* Performs a GraphQL request using the provided GraphQL query string, operation name, and
510+
* variables.
511+
*
512+
* @param graphql the GraphQL query
513+
* @param operation the name of the GraphQL operation to be executed
514+
* @param variables the input variables for the GraphQL query
515+
* @return {@link GraphQLResponse} containing the result of the query execution
516+
* @throws IOException if the request json cannot be created because of issues with one of the
517+
* provided arguments
518+
*/
519+
public GraphQLResponse postForString(String graphql, String operation, ObjectNode variables) throws IOException {
520+
requireNonNull(graphql, "GraphQL query string cannot be null");
521+
522+
return post(createJsonQuery(graphql, operation, variables));
523+
}
524+
414525
/**
415526
* Performs a GraphQL request with the provided payload.
416527
*

graphql-spring-boot-test/src/test/java/com/graphql/spring/boot/test/GraphQLTestTemplateIntegrationTest.java

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.graphql.spring.boot.test;
22

3+
import static org.junit.jupiter.api.Assertions.assertThrows;
4+
35
import com.fasterxml.jackson.databind.ObjectMapper;
46
import com.fasterxml.jackson.databind.node.ArrayNode;
57
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -8,7 +10,9 @@
810
import java.io.IOException;
911
import java.util.Arrays;
1012
import java.util.Collections;
13+
import java.util.LinkedHashMap;
1114
import java.util.List;
15+
import java.util.Map;
1216
import java.util.UUID;
1317
import java.util.stream.Collectors;
1418
import org.junit.jupiter.api.BeforeEach;
@@ -274,4 +278,194 @@ void testPerformWithIndividualFileUpload() throws IOException {
274278
.asString()
275279
.isEqualTo(fileNames.get(0));
276280
}
281+
282+
@Test
283+
@DisplayName("Test postForString without operation name and without variables.")
284+
void testPostString() throws IOException {
285+
// GIVEN
286+
final String graphql = "query {\n"
287+
+ " otherQuery\n"
288+
+ "}";
289+
// WHEN - THEN
290+
graphQLTestTemplate
291+
.postForString(graphql)
292+
.assertThatNoErrorsArePresent()
293+
.assertThatField(DATA_FIELD_OTHER_QUERY)
294+
.asString()
295+
.isEqualTo(TEST);
296+
}
297+
298+
@Test
299+
@DisplayName("Test postForString with embedded operation name and without variables.")
300+
void testPostStringWithEmbeddedOperationName() throws IOException {
301+
// GIVEN
302+
final String graphql = "query TestOperationYo {\n"
303+
+ " otherQuery\n"
304+
+ "}";
305+
// WHEN - THEN
306+
graphQLTestTemplate
307+
.postForString(graphql)
308+
.assertThatNoErrorsArePresent()
309+
.assertThatField(DATA_FIELD_OTHER_QUERY)
310+
.asString()
311+
.isEqualTo(TEST);
312+
}
313+
314+
@Test
315+
@DisplayName("Test postForString with explicit operation name and without variables.")
316+
void testPostStringWithExplicitOperationName() throws IOException {
317+
// GIVEN
318+
final String graphql = "query TestOperationYo {\n"
319+
+ " otherQuery\n"
320+
+ "}";
321+
// WHEN - THEN
322+
graphQLTestTemplate
323+
.postForString(graphql, "TestOperationYo")
324+
.assertThatNoErrorsArePresent()
325+
.assertThatField(DATA_FIELD_OTHER_QUERY)
326+
.asString()
327+
.isEqualTo(TEST);
328+
}
329+
330+
@Test
331+
@DisplayName("Test postForString with fragments.")
332+
void testPostForStringWithFragments() throws IOException {
333+
graphQLTestTemplate
334+
.postForString(
335+
"query($foo: String, $bar: String) {\n"
336+
+ " fooBar(foo: $foo, bar: $bar) {\n"
337+
+ " ...FooBarFragment\n"
338+
+ " }\n"
339+
+ "}"
340+
+ "fragment FooBarFragment on FooBar {\n"
341+
+ " foo\n"
342+
+ " bar\n"
343+
+ "}"
344+
)
345+
.assertThatNoErrorsArePresent()
346+
.assertThatField(DATA_FIELD_FOO_BAR)
347+
.as(FooBar.class)
348+
.usingRecursiveComparison()
349+
.ignoringAllOverriddenEquals()
350+
.isEqualTo(FooBar.builder().foo(FOO).bar(BAR).build());
351+
}
352+
353+
@Test
354+
@DisplayName("Test postForString with ObjectNode variables.")
355+
void testPostForStringWithObjectNodeVariables() throws IOException {
356+
// GIVEN
357+
final ObjectNode variables = objectMapper.createObjectNode();
358+
variables.put(INPUT_STRING_NAME, INPUT_STRING_VALUE);
359+
360+
// WHEN - THEN
361+
graphQLTestTemplate
362+
.postForString(
363+
"query ($input: String!) {"
364+
+ " queryWithVariables(input: $input)"
365+
+ "}",
366+
variables
367+
)
368+
.assertThatNoErrorsArePresent()
369+
.assertThatField(DATA_FIELD_QUERY_WITH_VARIABLES)
370+
.asString()
371+
.isEqualTo(INPUT_STRING_VALUE);
372+
}
373+
374+
@Test
375+
@DisplayName("Test postForString with Map variables.")
376+
void testPostForStringWithMapVariables() throws IOException {
377+
// GIVEN
378+
final Map<String, Object> variables = new LinkedHashMap<>();
379+
variables.put(INPUT_STRING_NAME, INPUT_STRING_VALUE);
380+
381+
// WHEN - THEN
382+
graphQLTestTemplate
383+
.postForString(
384+
"query ($input: String!) {"
385+
+ " queryWithVariables(input: $input)"
386+
+ "}",
387+
variables
388+
)
389+
.assertThatNoErrorsArePresent()
390+
.assertThatField(DATA_FIELD_QUERY_WITH_VARIABLES)
391+
.asString()
392+
.isEqualTo(INPUT_STRING_VALUE);
393+
}
394+
395+
@Test
396+
@DisplayName("Test postForString with embedded operation name and variables.")
397+
void testPostForStringWithEmbeddedOperationNameAndVariables() throws IOException {
398+
// GIVEN
399+
final ObjectNode variables = objectMapper.createObjectNode();
400+
variables.put(INPUT_STRING_NAME, INPUT_STRING_VALUE);
401+
402+
// WHEN - THEN
403+
graphQLTestTemplate
404+
.postForString(
405+
"query TestOperationYo ($input: String!) {"
406+
+ " queryWithVariables(input: $input)"
407+
+ "}",
408+
variables
409+
)
410+
.assertThatNoErrorsArePresent()
411+
.assertThatField(DATA_FIELD_QUERY_WITH_VARIABLES)
412+
.asString()
413+
.isEqualTo(INPUT_STRING_VALUE);
414+
}
415+
416+
@Test
417+
@DisplayName("Test postForString with explicit operation name and ObjectNode variables.")
418+
void testPostForStringWithExplicitOperationNameAndObjectNodeVariables() throws IOException {
419+
// GIVEN
420+
final ObjectNode variables = objectMapper.createObjectNode();
421+
variables.put(INPUT_STRING_NAME, INPUT_STRING_VALUE);
422+
423+
// WHEN - THEN
424+
graphQLTestTemplate
425+
.postForString(
426+
"query TestOperationYo ($input: String!) {"
427+
+ " queryWithVariables(input: $input)"
428+
+ "}",
429+
"TestOperationYo",
430+
variables
431+
)
432+
.assertThatNoErrorsArePresent()
433+
.assertThatField(DATA_FIELD_QUERY_WITH_VARIABLES)
434+
.asString()
435+
.isEqualTo(INPUT_STRING_VALUE);
436+
}
437+
438+
@Test
439+
@DisplayName("Test postForString with explicit operation name and Map variables.")
440+
void testPostForStringWithExplicitOperationNameAndMapVariables() throws IOException {
441+
// GIVEN
442+
final Map<String, Object> variables = new LinkedHashMap<>();
443+
variables.put(INPUT_STRING_NAME, INPUT_STRING_VALUE);
444+
445+
// WHEN - THEN
446+
graphQLTestTemplate
447+
.postForString(
448+
"query TestOperationYo ($input: String!) {"
449+
+ " queryWithVariables(input: $input)"
450+
+ "}",
451+
"TestOperationYo",
452+
variables
453+
)
454+
.assertThatNoErrorsArePresent()
455+
.assertThatField(DATA_FIELD_QUERY_WITH_VARIABLES)
456+
.asString()
457+
.isEqualTo(INPUT_STRING_VALUE);
458+
}
459+
460+
@Test
461+
@DisplayName("Test postForString with null string.")
462+
void testPostStringWithNullString() {
463+
// GIVEN
464+
final String graphql = null;
465+
466+
// WHEN - THEN
467+
assertThrows(NullPointerException.class, () -> {
468+
graphQLTestTemplate.postForString(graphql);
469+
});
470+
}
277471
}

0 commit comments

Comments
 (0)