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 d3c3ab41..7c1fce01 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 @@ -655,6 +655,16 @@ public EntityList hasSizeGreaterThan(int size) { getEntity().size() > size)); return this; } + + @Override + public Entity singleElement() { + this.hasSize(1); + E element = this.get().get(0); + @SuppressWarnings("unchecked") + Class elementClass = (Class) element.getClass(); + return new DefaultPath(DefaultPath.this.basePath, DefaultPath.this.path + "[0]", DefaultPath.this.delegate) + .entity(elementClass); + } } 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 a98f2b1b..66dec174 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 @@ -470,6 +470,13 @@ interface EntityList extends Entity, EntityL */ EntityList hasSizeGreaterThan(int size); + /** + * Verify the list has a single element and return an {@code Entity} spec for it. + *

This is a convenience method that combines {@link #hasSize(int) hasSize(1)} + * with navigating to the first element in the list. + * @return an {@code Entity} spec for the single element that allows further assertions + */ + Entity singleElement(); } /** 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 62e291c3..5eae00fd 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 @@ -173,12 +173,14 @@ void entityList() { String document = "{me {name, friends}}"; getGraphQlService().setDataAsJson(document, - "{" + - " \"me\":{" + - " \"name\":\"Luke Skywalker\"," - + " \"friends\":[{\"name\":\"Han Solo\"}, {\"name\":\"Leia Organa\"}]" + - " }" + - "}"); + """ + { + "me":{ + "name":"Luke Skywalker", + "friends":[{"name":"Han Solo"}, {"name":"Leia Organa"}] + } + } + """); GraphQlTester.Response response = graphQlTester().document(document).execute(); @@ -215,6 +217,54 @@ void entityList() { assertThat(getActualRequestDocument()).contains(document); } + @Test + void singleElementShouldThrowWhenMultiple() { + + String document = "{me {name, friends}}"; + getGraphQlService().setDataAsJson(document, + """ + { + "me":{ + "name":"Luke Skywalker", + "friends":[{"name":"Han Solo"}, {"name":"Leia Organa"}] + } + } + """); + + GraphQlTester.Response response = graphQlTester().document(document).execute(); + GraphQlTester.EntityList entityList = response.path("me.friends").entityList(MovieCharacter.class); + assertThatThrownBy(entityList::singleElement) + .as("Should have exactly one element") + .hasMessage("Expecting list " + + "[MovieCharacter[name='Han Solo'], MovieCharacter[name='Leia Organa']] " + + "at path 'me.friends' to have size == 1\n" + + "Request: document='{me {name, friends}}'"); + } + + @Test + void entityListWithSingleElement() { + + String document = "{me {name, friends}}"; + getGraphQlService().setDataAsJson(document, + """ + { + "me":{ + "name":"Luke Skywalker", + "friends":[{"name":"Han Solo"}] + } + } + """); + + GraphQlTester.Response response = graphQlTester().document(document).execute(); + + MovieCharacter han = MovieCharacter.create("Han Solo"); + + response.path("me.friends") + .entityList(MovieCharacter.class) + .singleElement() + .isEqualTo(han); + } + @Test void nestedPath() {