spring-restdocs icon indicating copy to clipboard operation
spring-restdocs copied to clipboard

Consistency with the subsection path.

Open ddaaac opened this issue 1 year ago • 4 comments

Hi, I have two JSON string.

{
  "a": {
    "b": [
      {
        "c": "c1"
      }
    ]
  }
}
{
  "a": [
    {
      "b": [
        {
          "c": "c1"
        }
      ]
    }
  ]
}

First one, A(B(List<C>)) responseFields(fieldWithPath("a.b[].c")) <- Test passed. responseFields(beneathPath("a.b[]"), listOf(fieldWithPath("c"))) <- Test passed. responseFields(beneathPath("a.b[]"), listOf(fieldWithPath("[].c"))) <- Test failed.

Second one, A(List<B(List<C>)>) responseFields(fieldWithPath("a[].b[].c")) <- Test passed. responseFields(beneathPath("a[].b[]"), listOf(fieldWithPath("c"))) <- Test failed. responseFields(beneathPath("a[].b[]"), listOf(fieldWithPath("[].c"))) <- Test passed.

Is this intentional? Does the way to find the path change if there is an array in the root?


Additional information.

responseFields(fieldWithPath("a.b[].c[].d")) <- Test passed. responseFields(beneathPath("a.b[].c[]"), listOf(fieldWithPath("d"))) <- Test failed. responseFields(beneathPath("a.b[].c[]"), listOf(fieldWithPath("[].d"))) <- Test Passed.

responseFields(fieldWithPath("a.b[].c.d")) <- Test passed. responseFields(beneathPath("a.b[].c"), listOf(fieldWithPath("d"))) <- Test Passed. responseFields(beneathPath("a.b[].c"), listOf(fieldWithPath("[].d"))) <- Test failed.

I think an array of 1 depth behaves differently from an array of n depth(n >= 2).

ddaaac avatar Aug 06 '24 04:08 ddaaac

See also https://github.com/spring-projects/spring-restdocs/issues/627.

wilkinsona avatar Aug 12 '24 10:08 wilkinsona

@ddaaac could you please share your complete tests? I'd like to be able to run them to see exactly what's happening with the field paths.

wilkinsona avatar Aug 13 '24 11:08 wilkinsona

import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.restdocs.RestDocumentationExtension
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get
import org.springframework.restdocs.payload.JsonFieldType
import org.springframework.restdocs.payload.PayloadDocumentation.*
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController


@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs
@ExtendWith(RestDocumentationExtension::class)
class ArrayTest {

    @Autowired
    private lateinit var mockMvc: MockMvc

    @Test
    fun `test response1`() {
        mockMvc.perform(get("/response1"))
            .andDo(
                document(
                    "response1",
                    responseFields(
                        fieldWithPath("a.b[].c").type(JsonFieldType.STRING).description("root")
                    ),
                    responseFields(
                        beneathPath("a.b[]").withSubsectionId("array"),
                        fieldWithPath("c").type(JsonFieldType.STRING).description("c")
                    )
//                    responseFields(
//                        beneathPath("a.b[]").withSubsectionId("nestedArray"),
//                        fieldWithPath("[].c").type(JsonFieldType.STRING).description("c")
//                    )
                )
            )
    }

    @Test
    fun `test response2`() {
        mockMvc.perform(get("/response2"))
            .andExpect(status().isOk)
            .andDo(
                document(
                    "response2",
                    responseFields(
                        fieldWithPath("a[].b[].c").type(JsonFieldType.STRING).description("root")
                    ),
//                    responseFields(
//                        beneathPath("a[].b[]").withSubsectionId("array"),
//                        fieldWithPath("c").type(JsonFieldType.STRING).description("c")
//                    )
                    responseFields(
                        beneathPath("a[].b[]").withSubsectionId("nestedArray"),
                        fieldWithPath("[].c").type(JsonFieldType.STRING).description("c")
                    )
                )
            )
    }

}

@RestController
class MyController {

    @GetMapping("/response1")
    fun getResponse1(): Map<String, Any> {
        return mapOf(
            "a" to mapOf(
                "b" to listOf(
                    mapOf(
                        "c" to "c1"
                    )
                )
            )
        )
    }

    @GetMapping("/response2")
    fun getResponse2(): Map<String, Any> {
        return mapOf(
            "a" to listOf(
                mapOf(
                    "b" to listOf(
                        mapOf(
                            "c" to "c1"
                        )
                    )
                )
            )
        )
    }
}

I use kotlin. The commented part is the part that fails.

ddaaac avatar Aug 19 '24 05:08 ddaaac

Thanks.

wilkinsona avatar Aug 19 '24 06:08 wilkinsona