Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

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

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants