Skip to content

GraphQlTester created via @GraphQlTest should use application JSON config #345

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
nenros opened this issue Mar 30, 2022 · 5 comments
Closed
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@nenros
Copy link

nenros commented Mar 30, 2022

hi!
I found another problem this time during testing.
Controller:

@QueryMapping
    suspend fun people(): Flow<PersonResponse> {
            return service.getAllPeople().map {
                PersonResponse(
                    it.id!!,
                    it.firstName,
                    it.lastName,
                    it.createdAt!!
                )
            }
    }

Test:

 @Test
    fun `get all persons`() {
        val person = Person(
            UUID.randomUUID(),
            firstName = "Test",
            lastName = "Test",
            createdAt = LocalDateTime.now()
        )
        
        val personResponse = PersonResponse(
            person.id!!,
            person.firstName,
            person.lastName,
            person.createdAt!!
        )
        
        coEvery { personService.getAllPeople() }.answers { flowOf(person) }
        
        graphQlTester.documentName("getAllPeople")
            .execute()
            .path("people")
            .entityList(PersonResponse::class.java)
            .hasSize(1)
            .contains(personResponse)
    }

query:

query {
    people {
        id, firstName, lastName, createdAt
    }
}

error:

java.lang.IllegalArgumentException: Cannot construct instance of `com.example.backendgraphql.person.response.PersonResponse` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: java.util.ArrayList[0])
com.jayway.jsonpath.spi.mapper.MappingException: java.lang.IllegalArgumentException: Cannot construct instance of `com.example.backendgraphql.person.response.PersonResponse` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: java.util.ArrayList[0])
	at app//com.jayway.jsonpath.spi.mapper.JacksonMappingProvider.map(JacksonMappingProvider.java:58)
	at app//com.jayway.jsonpath.internal.JsonContext.convert(JsonContext.java:121)
	at app//com.jayway.jsonpath.internal.JsonContext.read(JsonContext.java:98)
	at app//org.springframework.graphql.test.tester.DefaultGraphQlTester$ResponseDelegate.read(DefaultGraphQlTester.java:229)
	at app//org.springframework.graphql.test.tester.DefaultGraphQlTester$DefaultPath.entityList(DefaultGraphQlTester.java:395)
	at app//com.example.backendgraphql.person.PersonControllerTest.get all persons(PersonControllerTest.kt:44)

This happened when I use data class for response object, when I use record from java I get :

java.lang.IllegalArgumentException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling
 at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: java.util.ArrayList[0]->com.example.backendgraphql.person.PersonResponse["createdAt"])
com.jayway.jsonpath.spi.mapper.MappingException: java.lang.IllegalArgumentException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling
 at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: java.util.ArrayList[0]->com.example.backendgraphql.person.PersonResponse["createdAt"])
	at app//com.jayway.jsonpath.spi.mapper.JacksonMappingProvider.map(JacksonMappingProvider.java:58)
	at app//com.jayway.jsonpath.internal.JsonContext.convert(JsonContext.java:121)
	at app//com.jayway.jsonpath.internal.JsonContext.read(JsonContext.java:98)
	at app//org.springframework.graphql.test.tester.DefaultGraphQlTester$ResponseDelegate.read(DefaultGraphQlTester.java:229)
	at app//org.springframework.graphql.test.tester.DefaultGraphQlTester$DefaultPath.entityList(DefaultGraphQlTester.java:395)

and record looks like that:

public record PersonResponse(
        UUID id,
        String firstName,
        String lastName,
        LocalDateTime createdAt
) {
}

And as you can see I have com.fasterxml.jackson.datatype:jackson-datatype-jsr310
Zrzut ekranu 2022-03-30 o 16 13 09

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 30, 2022
@rstoyanchev
Copy link
Contributor

Can you show how the tester is created exactly? Or provide a sample.

@nenros
Copy link
Author

nenros commented Mar 30, 2022

@GraphQlTest(PersonController::class)
internal class PersonControllerTest {
    @Autowired
    private lateinit var graphQlTester: GraphQlTester

    @MockkBean
    lateinit var personService: PersonService
    
    @Test
    fun `get all persons`() {
        val person = Person(
            UUID.randomUUID(),
            firstName = "Test",
            lastName = "Test",
            createdAt = LocalDateTime.now()
        )
        
        val personResponse = PersonResponse(
            person.id!!,
            person.firstName,
            person.lastName,
            person.createdAt!!
        )
        
        coEvery { personService.getAllPeople() }.answers { flowOf(person) }
        
        graphQlTester.documentName("getAllPeople")
            .execute()
            .path("people")
            .entityList(PersonResponse::class.java)
            .hasSize(1)
            .contains(personResponse)
    }
}

And i found that changing to

@AutoConfigureHttpGraphQlTester
@SpringBootTest

make test pass, but as I guess it should also pass with previous solution.

@rstoyanchev
Copy link
Contributor

Currently, no JSON config options are exposed in the GraphQlTester.Builder, but when use a transport-specific extension, e.g. HTTP, WebSocket, RSocket, the JSON config for the underlying client/transport, e.g. from WebTestClient, is detected and used.

@GraphQlTest configures only a basic GraphQlTester for server side testing without any transport, so it doesn't benefit from this. We could expose some JSON config options on the builder for ExecutionGraphQlTester. @bclozel, what would be the most convenient config option there? Ultimately what's needed internally is an Encoder and Decoder pair.

@rstoyanchev rstoyanchev self-assigned this Apr 12, 2022
@rstoyanchev rstoyanchev added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Apr 12, 2022
@rstoyanchev rstoyanchev added this to the 1.0.0-RC1 milestone Apr 12, 2022
@rstoyanchev rstoyanchev changed the title GraphqlTester - Jsonpath - don't use proper object mapper GraphQlTester created via @GraphQlTest does not use application JSON config Apr 12, 2022
@rstoyanchev
Copy link
Contributor

I've exposed Encoder and Decoder on ExecutionGraphQlServiceTester but leaving this open for now, until we have corresponding changes on the Boot side for @GraphQlTest.

@bclozel
Copy link
Member

bclozel commented Apr 12, 2022

The enhancement is now pushed in Spring Boot 2.7.x, see spring-projects/spring-boot#30646. Changes are available in SNAPSHOTs now and will be released with 2.7.0-RC1 in a few days.

Nothing else is required from my side, I think we can close this issue now.

@rstoyanchev rstoyanchev changed the title GraphQlTester created via @GraphQlTest does not use application JSON config GraphQlTester created via @GraphQlTest should use application JSON config Apr 12, 2022
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants