Skip to content
This repository was archived by the owner on Mar 28, 2025. It is now read-only.

Commit d8e2ae1

Browse files
committed
# 42 - Add ExtractJson method - string from json path
- Introduced method 'string-from-json-path' in group: 'extractJson'. - Improved error message in method 'body-contains-text' in group: 'assert'
1 parent 2ec99bb commit d8e2ae1

File tree

8 files changed

+154
-9
lines changed

8 files changed

+154
-9
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,13 @@ line break:\\nAnd a tab:\\tEnd .... Matches the string "line break
313313
- jsonKey: The key in the JSON object from which to extract the string.
314314
- runtimeCacheLevel: The expiration level to use when storing the extracted string in the runtime cache. [Global, Suite, Test]
315315

316+
- `extractJson.string-from-json-path`
317+
- description: Extracts a string from a JSON response at a given json path and stores it in a runtime cache with a given key and expiration level.
318+
- arguments:
319+
- cacheKey: The key to use when storing the extracted string in the runtime cache.
320+
- jsonPath: The json path in the JSON from which to extract the string.
321+
- runtimeCacheLevel: The expiration level to use when storing the extracted string in the runtime cache. [Global, Suite, Test]
322+
316323

317324
## Known issue
318325
- Error in Response.perform.

testApi/src/main/resources/schema/after.schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121
"properties": {
122122
"method": {
123123
"type": "string",
124-
"enum": ["assert.response-time-is-below", "assert.response-time-is-above", "assert.status-code-equals", "assert.status-code-is-success", "assert.status-code-is-client-error", "assert.status-code-is-server-error", "assert.header-exists", "assert.header-value-equals", "assert.content-type-is-json", "assert.content-type-is-xml", "assert.content-type-is-html", "assert.cookie-exists", "assert.cookie-value-equals", "assert.cookie-is-secured", "assert.cookie-is-not-secured", "assert.body-equals", "assert.body-contains-text", "assert.body-is-empty", "assert.body-is-not-empty", "assert.body-length-equals", "assert.body-starts-with", "assert.body-ends-with", "assert.body-matches-regex", "assert.body-json-is-json-array", "assert.body-json-is-json-object", "assert.body-json-path-exists", "log.error", "log.warn", "log.info", "log.debug", "log.log-info-response", "extractJson.string-from-list"],
124+
"enum": ["assert.response-time-is-below", "assert.response-time-is-above", "assert.status-code-equals", "assert.status-code-is-success", "assert.status-code-is-client-error", "assert.status-code-is-server-error", "assert.header-exists", "assert.header-value-equals", "assert.content-type-is-json", "assert.content-type-is-xml", "assert.content-type-is-html", "assert.cookie-exists", "assert.cookie-value-equals", "assert.cookie-is-secured", "assert.cookie-is-not-secured", "assert.body-equals", "assert.body-contains-text", "assert.body-is-empty", "assert.body-is-not-empty", "assert.body-length-equals", "assert.body-starts-with", "assert.body-ends-with", "assert.body-matches-regex", "assert.body-json-is-json-array", "assert.body-json-is-json-object", "assert.body-json-path-exists", "log.error", "log.warn", "log.info", "log.debug", "log.log-info-response", "extractJson.string-from-list", "extractJson.string-from-json-path"],
125125
"description": "The method to be used for the response action. Restricted to specific values."
126126
}
127127
},

testApi/src/main/resources/schema/before.schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
"properties": {
120120
"method": {
121121
"type": "string",
122-
"enum": ["assert.response-time-is-below", "assert.response-time-is-above", "assert.status-code-equals", "assert.status-code-is-success", "assert.status-code-is-client-error", "assert.status-code-is-server-error", "assert.header-exists", "assert.header-value-equals", "assert.content-type-is-json", "assert.content-type-is-xml", "assert.content-type-is-html", "assert.cookie-exists", "assert.cookie-value-equals", "assert.cookie-is-secured", "assert.cookie-is-not-secured", "assert.body-equals", "assert.body-contains-text", "assert.body-is-empty", "assert.body-is-not-empty", "assert.body-length-equals", "assert.body-starts-with", "assert.body-ends-with", "assert.body-matches-regex", "assert.body-json-is-json-array", "assert.body-json-is-json-object", "assert.body-json-path-exists", "log.error", "log.warn", "log.info", "log.debug", "log.log-info-response", "extractJson.string-from-list"],
122+
"enum": ["assert.response-time-is-below", "assert.response-time-is-above", "assert.status-code-equals", "assert.status-code-is-success", "assert.status-code-is-client-error", "assert.status-code-is-server-error", "assert.header-exists", "assert.header-value-equals", "assert.content-type-is-json", "assert.content-type-is-xml", "assert.content-type-is-html", "assert.cookie-exists", "assert.cookie-value-equals", "assert.cookie-is-secured", "assert.cookie-is-not-secured", "assert.body-equals", "assert.body-contains-text", "assert.body-is-empty", "assert.body-is-not-empty", "assert.body-length-equals", "assert.body-starts-with", "assert.body-ends-with", "assert.body-matches-regex", "assert.body-json-is-json-array", "assert.body-json-is-json-object", "assert.body-json-path-exists", "log.error", "log.warn", "log.info", "log.debug", "log.log-info-response", "extractJson.string-from-list", "extractJson.string-from-json-path"],
123123
"description": "The method to be used for the response action."
124124
}
125125
},

testApi/src/main/resources/schema/suite.schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@
130130
"properties": {
131131
"method": {
132132
"type": "string",
133-
"enum": ["assert.response-time-is-below", "assert.response-time-is-above", "assert.status-code-equals", "assert.status-code-is-success", "assert.status-code-is-client-error", "assert.status-code-is-server-error", "assert.header-exists", "assert.header-value-equals", "assert.content-type-is-json", "assert.content-type-is-xml", "assert.content-type-is-html", "assert.cookie-exists", "assert.cookie-value-equals", "assert.cookie-is-secured", "assert.cookie-is-not-secured", "assert.body-equals", "assert.body-contains-text", "assert.body-is-empty", "assert.body-is-not-empty", "assert.body-length-equals", "assert.body-starts-with", "assert.body-ends-with", "assert.body-matches-regex", "assert.body-json-is-json-array", "assert.body-json-is-json-object", "assert.body-json-path-exists", "log.error", "log.warn", "log.info", "log.debug", "log.log-info-response", "extractJson.string-from-list"],
133+
"enum": ["assert.response-time-is-below", "assert.response-time-is-above", "assert.status-code-equals", "assert.status-code-is-success", "assert.status-code-is-client-error", "assert.status-code-is-server-error", "assert.header-exists", "assert.header-value-equals", "assert.content-type-is-json", "assert.content-type-is-xml", "assert.content-type-is-html", "assert.cookie-exists", "assert.cookie-value-equals", "assert.cookie-is-secured", "assert.cookie-is-not-secured", "assert.body-equals", "assert.body-contains-text", "assert.body-is-empty", "assert.body-is-not-empty", "assert.body-length-equals", "assert.body-starts-with", "assert.body-ends-with", "assert.body-matches-regex", "assert.body-json-is-json-array", "assert.body-json-is-json-object", "assert.body-json-path-exists", "log.error", "log.warn", "log.info", "log.debug", "log.log-info-response", "extractJson.string-from-list", "extractJson.string-from-json-path"],
134134
"description": "The method to be used for the response action."
135135
}
136136
},

testApi/src/main/scala/africa/absa/testing/scapi/rest/response/action/AssertionResponseAction.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ object AssertionResponseAction extends ResponseActions {
508508
*/
509509
private def assertBodyContainsText(response: Response, text: String): Try[Unit] = Try {
510510
if (!response.body.contains(text)) {
511-
val errMsg = s"Expected body to contain $text"
511+
val errMsg = s"Expected body to contains: '$text'. Content of body: '${response.body}'"
512512
Logger.error(errMsg)
513513
throw AssertionException(errMsg)
514514
}

testApi/src/main/scala/africa/absa/testing/scapi/rest/response/action/ExtractJsonResponseAction.scala

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import africa.absa.testing.scapi.rest.response.action.types.ExtractJsonResponseA
2323
import africa.absa.testing.scapi.utils.cache.RuntimeCache
2424
import africa.absa.testing.scapi.utils.validation.ContentValidator
2525
import africa.absa.testing.scapi.{AssertionException, UndefinedResponseActionTypeException}
26+
import com.jayway.jsonpath.{Configuration, JsonPath}
2627
import spray.json._
2728

2829
import scala.util.Try
@@ -45,6 +46,7 @@ object ExtractJsonResponseAction extends ResponseActions {
4546
val action = fromString(responseAction.name.toLowerCase).getOrElse(None)
4647
action match {
4748
case StringFromList => validateStringFromList(responseAction)
49+
case StringFromJsonPath => validateStringFromJsonPath(responseAction)
4850
case _ => throw UndefinedResponseActionTypeException(responseAction.name)
4951
}
5052
}
@@ -61,13 +63,21 @@ object ExtractJsonResponseAction extends ResponseActions {
6163

6264
val action = fromString(responseAction.name.toLowerCase).getOrElse(None)
6365
action match {
64-
case StringFromList =>
66+
case StringFromList | StringFromJsonPath =>
6567
val cacheKey = responseAction.params("cacheKey")
66-
val listIndex = responseAction.params("listIndex").toInt
67-
val jsonKey = responseAction.params("jsonKey")
6868
val cacheLevel = responseAction.params("cacheLevel")
6969

70-
stringFromList(response, cacheKey, listIndex, jsonKey, cacheLevel)
70+
action match {
71+
case StringFromList =>
72+
val jsonKey = responseAction.params("jsonKey")
73+
val listIndex = responseAction.params("listIndex").toInt
74+
stringFromList(response, cacheKey, listIndex, jsonKey, cacheLevel)
75+
76+
case StringFromJsonPath =>
77+
val jsonPath = responseAction.params("jsonPath")
78+
stringFromJsonPath(response, jsonPath, cacheKey, cacheLevel)
79+
}
80+
7181
case _ => throw UndefinedResponseActionTypeException(s"Unsupported assertion[group: extract]: ${responseAction.name}")
7282
}
7383
}
@@ -137,4 +147,45 @@ object ExtractJsonResponseAction extends ResponseActions {
137147
ContentValidator.validateIntegerString(listIndex, s"ExtractJson.$StringFromList.listIndex")
138148
}
139149

150+
/**
151+
* This method validates the parameters of the StringFromJsonPath type of response action.
152+
*
153+
* @param assertion The ResponseAction instance containing the response action details.
154+
*/
155+
private def validateStringFromJsonPath(assertion: ResponseAction): Unit = {
156+
val cacheKey = assertion.params.getOrElse("cacheKey", throw new IllegalArgumentException(s"Missing required 'cacheKey' parameter for extract $StringFromJsonPath logic"))
157+
val jsonPath = assertion.params.getOrElse("jsonPath", throw new IllegalArgumentException(s"Missing required 'jsonPath' parameter for extract $StringFromJsonPath logic"))
158+
val cacheLevel = assertion.params.getOrElse("cacheLevel", throw new IllegalArgumentException(s"Missing required 'cacheLevel' parameter for extract $StringFromJsonPath logic"))
159+
160+
ContentValidator.validateNonEmptyString(jsonPath, s"ExtractJson.$StringFromJsonPath.jsonPath")
161+
ContentValidator.validateNonEmptyString(cacheKey, s"ExtractJson.$StringFromJsonPath.cacheKey")
162+
ContentValidator.validateNonEmptyString(cacheLevel, s"ExtractJson.$StringFromJsonPath.cacheLevel")
163+
}
164+
165+
/**
166+
* This method extracts a string from a JSON array response at a given json path
167+
* and stores it in a runtime cache with a given key and expiration level.
168+
*
169+
* @param response The Response instance containing the JSON body.
170+
* @param jsonPath The json path in the JSON from which to extract the string.
171+
* @param cacheKey The key to use when storing the extracted string in the runtime cache.
172+
* @param runtimeCacheLevel The expiration level to use when storing the extracted string in the runtime cache.
173+
* @return A Try[Unit] indicating whether the string extraction and caching operation was successful or not.
174+
*/
175+
private def stringFromJsonPath(response: Response, jsonPath: String, cacheKey: String, runtimeCacheLevel: String): Try[Unit] = Try {
176+
val configuration = Configuration.defaultConfiguration().addOptions(com.jayway.jsonpath.Option.SUPPRESS_EXCEPTIONS)
177+
val json = JsonPath.using(configuration).parse(response.body)
178+
val extractedValueOpt = Option(json.read[Any](jsonPath))
179+
180+
extractedValueOpt match {
181+
case Some(extractedValue) =>
182+
RuntimeCache.put(key = cacheKey, value = extractedValue.toString, RuntimeCache.determineLevel(runtimeCacheLevel))
183+
Logger.debug(s"Extracted string '${extractedValue.toString}' from json path '$jsonPath' and stored it in runtime cache with key '$cacheKey' and expiration level '$runtimeCacheLevel'.")
184+
185+
case None =>
186+
val errMsg = s"Expected JSON path '$jsonPath' does not exist in the response body"
187+
Logger.error(errMsg)
188+
throw AssertionException(errMsg)
189+
}
190+
}
140191
}

testApi/src/main/scala/africa/absa/testing/scapi/rest/response/action/types/ExtractJsonResponseActionType.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ object ExtractJsonResponseActionType extends Enumeration {
2323
type ExtractJsonResponseActionType = Value
2424

2525
val StringFromList: ExtractJsonResponseActionType.Value = Value("string-from-list")
26+
val StringFromJsonPath: ExtractJsonResponseActionType.Value = Value("string-from-json-path")
2627

2728
def fromString(s: String): Option[ExtractJsonResponseActionType] = Try(this.withName(s)).toOption
2829
}

0 commit comments

Comments
 (0)