diff --git a/core/src/main/kotlin/io/specmatic/stub/stateful/StatefulHttpStub.kt b/core/src/main/kotlin/io/specmatic/stub/stateful/StatefulHttpStub.kt index e605d84d9..83a474a75 100644 --- a/core/src/main/kotlin/io/specmatic/stub/stateful/StatefulHttpStub.kt +++ b/core/src/main/kotlin/io/specmatic/stub/stateful/StatefulHttpStub.kt @@ -36,6 +36,7 @@ import io.specmatic.core.value.JSONArrayValue import io.specmatic.core.value.JSONObjectValue import io.specmatic.core.value.StringValue import io.specmatic.core.value.Value +import io.specmatic.core.value.mergeWith import io.specmatic.mock.ScenarioStub import io.specmatic.stub.ContractAndRequestsMismatch import io.specmatic.stub.ContractStub @@ -595,12 +596,23 @@ class StatefulHttpStub( if (responseBody !is JSONObjectValue) return@forEach if(httpRequest.method == "POST" && httpRequest.body !is JSONObjectValue) return@forEach - stubCache.addResponse( - path = resourcePath, - responseBody = responseBody, - idKey = DEFAULT_CACHE_RESPONSE_ID_KEY, - idValue = idValueFor(DEFAULT_CACHE_RESPONSE_ID_KEY, responseBody) - ) + + val requestBody = httpRequest.body + if(requestBody is JSONObjectValue) { + stubCache.addResponse( + path = resourcePath, + responseBody = requestBody.mergeWith(responseBody) as JSONObjectValue, + idKey = DEFAULT_CACHE_RESPONSE_ID_KEY, + idValue = idValueFor(DEFAULT_CACHE_RESPONSE_ID_KEY, responseBody) + ) + } else { + stubCache.addResponse( + path = resourcePath, + responseBody = responseBody, + idKey = DEFAULT_CACHE_RESPONSE_ID_KEY, + idValue = idValueFor(DEFAULT_CACHE_RESPONSE_ID_KEY, responseBody) + ) + } } return stubCache diff --git a/core/src/test/kotlin/io/specmatic/stub/stateful/StatefulHttpStubTest.kt b/core/src/test/kotlin/io/specmatic/stub/stateful/StatefulHttpStubTest.kt index 04c194f72..5168dc0d3 100644 --- a/core/src/test/kotlin/io/specmatic/stub/stateful/StatefulHttpStubTest.kt +++ b/core/src/test/kotlin/io/specmatic/stub/stateful/StatefulHttpStubTest.kt @@ -518,7 +518,7 @@ class StatefulHttpStubSeedDataFromExamplesTest { assertThat(response.body).isInstanceOf(JSONArrayValue::class.java) val responseBody = (response.body as JSONArrayValue) - assertThat(responseBody.list.size).isEqualTo(4) + assertThat(responseBody.list.size).isEqualTo(5) val responseObjectFromResponseBody = (response.body as JSONArrayValue) .list.filterIsInstance().first { it.getStringValue("id") == "300" } @@ -530,7 +530,6 @@ class StatefulHttpStubSeedDataFromExamplesTest { assertThat(responseObjectFromResponseBody.getStringValue("inStock")).isEqualTo("true") } - @Test fun `should get the product from seed data loaded from examples`() { val response = httpStub.client.execute( @@ -550,6 +549,25 @@ class StatefulHttpStubSeedDataFromExamplesTest { assertThat(responseBody.getStringValue("inStock")).isEqualTo("true") } + @Test + fun `should get the Samsung Ultra product from seed data loaded from examples which is a merge of request and response bodies`() { + val response = httpStub.client.execute( + HttpRequest( + method = "GET", + path = "/products/700" + ) + ) + + assertThat(response.status).isEqualTo(200) + val responseBody = response.body as JSONObjectValue + + assertThat(responseBody.getStringValue("id")).isEqualTo("700") + assertThat(responseBody.getStringValue("name")).isEqualTo("Samsung Ultra") + assertThat(responseBody.getStringValue("description")).isEqualTo("Samsung Ultra Description") + assertThat(responseBody.getStringValue("price")).isEqualTo("1000") + assertThat(responseBody.getStringValue("inStock")).isEqualTo("false") + } + @Test fun `should not load the xiaomi product from the seed data as it has the same id (300) as that of iphone example`() { val response = httpStub.client.execute( @@ -563,7 +581,7 @@ class StatefulHttpStubSeedDataFromExamplesTest { assertThat(response.body).isInstanceOf(JSONArrayValue::class.java) val responseBody = (response.body as JSONArrayValue) - assertThat(responseBody.list.size).isEqualTo(4) + assertThat(responseBody.list.size).isEqualTo(5) val responseObjectsFromResponseBody = (response.body as JSONArrayValue) .list.filterIsInstance().filter { it.getStringValue("id") == "300" } @@ -588,7 +606,7 @@ class StatefulHttpStubSeedDataFromExamplesTest { assertThat(response.body).isInstanceOf(JSONArrayValue::class.java) val responseBody = (response.body as JSONArrayValue) - assertThat(responseBody.list.size).isEqualTo(4) + assertThat(responseBody.list.size).isEqualTo(5) val productsWithIds500And600 = (response.body as JSONArrayValue) .list.filterIsInstance().filter { diff --git a/core/src/test/resources/openapi/spec_with_strictly_restful_apis/spec_with_strictly_restful_apis_examples/post_with_missing_values_from_response.json b/core/src/test/resources/openapi/spec_with_strictly_restful_apis/spec_with_strictly_restful_apis_examples/post_with_missing_values_from_response.json new file mode 100644 index 000000000..f66e812f6 --- /dev/null +++ b/core/src/test/resources/openapi/spec_with_strictly_restful_apis/spec_with_strictly_restful_apis_examples/post_with_missing_values_from_response.json @@ -0,0 +1,25 @@ +{ + "http-request": { + "path": "/products", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "name": "Samsung Ultra", + "price": 1000 + } + }, + "http-response": { + "status": 201, + "body": { + "id": 700, + "description": "Samsung Ultra Description", + "inStock": false + }, + "status-text": "Created", + "headers": { + "Content-Type": "application/json" + } + } +}