Can not test GraphQL with MockMvc, as the response is always empty.
jaggerwang opened this issue · 2 comments
jaggerwang commented
I'm using MockMvc
to test GraphQL API, but tests always failure because the response is empty. The full code can be found at Spring Boot in Practice.
package net.jaggerwang.sbip.api;
...
@SpringBootTest()
@AutoConfigureMockMvc
@ActiveProfiles("test")
@Sql({"/db/init-db-test.sql"})
@Sql(scripts = {"/db/clean-db-test.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
@EnabledIfSystemProperty(named = "test.api.enabled", matches = "true")
public class UserGraphQLApiTests {
@Autowired
private MockMvc mvc;
@Value("${graphql.url}")
private String graphqlUrl;
@Autowired
private ObjectMapper objectMapper;
@Test
void login() throws Exception {
var userEntity = UserEntity.builder().username("jaggerwang").password("123456").build();
var content = new ObjectMapper().createObjectNode();
content.put("query", "mutation($user: UserInput!) { authLogin(user: $user) { id username } }");
content.putObject("variables").putObject("user").put("username", userEntity.getUsername())
.put("password", userEntity.getPassword());
mvc.perform(post(graphqlUrl).contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(content))).andExpect(status().isOk())
.andExpect(jsonPath("$.errors").doesNotExist())
.andExpect(jsonPath("$.data.authLogin.username").value(userEntity.getUsername()));
}
...
}
Test output:
...
MockHttpServletRequest:
HTTP Method = POST
Request URI = /graphql
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"149"]
Body = {"query":"mutation($user: UserInput!) { authLogin(user: $user) { id username } }","variables":{"user":{"username":"jaggerwang","password":"123456"}}}
Session Attrs = {}
Handler:
Type = graphql.spring.web.servlet.components.GraphQLController
Method = graphql.spring.web.servlet.components.GraphQLController#graphqlPOST(String, String, String, String, String, WebRequest)
Async:
Async started = true
Async result = {data={authLogin={id=1, username=jaggerwang}}}
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY", Set-Cookie:"SESSION=OTFiNzRmNDgtYTIzNy00N2ZlLTk4MWQtNmMxNzMwYzU1ZDVk; Path=/; HttpOnly; SameSite=Lax"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = [[MockCookie@7d9c448f name = 'SESSION', value = 'OTFiNzRmNDgtYTIzNy00N2ZlLTk4MWQtNmMxNzMwYzU1ZDVk', comment = [null], domain = [null], maxAge = -1, path = '/', secure = false, version = 0, httpOnly = true]]
...
[ERROR] login Time elapsed: 0.187 s <<< FAILURE!
java.lang.AssertionError: No value at JSON path "$.data.authLogin.username"
at net.jaggerwang.sbip.api.UserGraphQLApiTests.login(UserGraphQLApiTests.java:45)
Caused by: java.lang.IllegalArgumentException: json can not be null or empty
at net.jaggerwang.sbip.api.UserGraphQLApiTests.login(UserGraphQLApiTests.java:45)
...
tomasz-galuszka commented
Try the following code - it works for me:
@Test
void exampleTest() throws Exception {
String query = new StringBuilder()
.append("query get($id: ID!) {")
.append(" getById (id: $id) {")
.append(" id")
.append(" name")
.append(" }")
.append("}")
.toString();
JSONObject variables = new JSONObject();
variables.put("id", 1);
MvcResult mvcResult = mockMvc.perform(post("/graphql")
.content(generateRequest(query, variables))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(request().asyncStarted())
.andExpect(request().asyncResult(notNullValue()))
.andReturn();
mockMvc.perform(asyncDispatch(mvcResult))
.andDo(print())
.andExpect(status().isOk())
}
private String generateRequest(String query, JSONObject variables) throws JSONException {
JSONObject jsonObject = new JSONObject();
jsonObject.put("query", query);
if (variables != null) {
jsonObject.put("variables", variables);
}
return jsonObject.toString();
}
}
andimarek commented
This project is now archived in favor of the official Spring GraphQL integration.