Repository: authorjapps/zerocode
Pull request #285 (2019-08-01 07:44:57)

ISS-16 # [HelloWorld repo] When Json Path returns array
- Even for single matching element


Patch:
diff --git a/core/src/main/java/org/jsmart/zerocode/converter/Converter.java b/core/src/main/java/org/jsmart/zerocode/converter/Converter.java
index c8c41d2c..3d489fc4 100644
--- a/core/src/main/java/org/jsmart/zerocode/converter/Converter.java
+++ b/core/src/main/java/org/jsmart/zerocode/converter/Converter.java
@@ -7,6 +7,8 @@ import java.io.IOException;
 public interface Converter {
     Object xmlToJson(String xmlObject);
 
+    Object stringToJson(String jsonString) throws IOException;
+
     Object jsonToJson(String jsonString) throws IOException;
 
     Object jsonBlockToJson(JsonNode jsonNode) throws IOException;
diff --git a/core/src/main/java/org/jsmart/zerocode/converter/MimeTypeConverter.java b/core/src/main/java/org/jsmart/zerocode/converter/MimeTypeConverter.java
index b8bbe14a..26b82250 100644
--- a/core/src/main/java/org/jsmart/zerocode/converter/MimeTypeConverter.java
+++ b/core/src/main/java/org/jsmart/zerocode/converter/MimeTypeConverter.java
@@ -48,7 +48,9 @@ public class MimeTypeConverter implements Converter {
     }
 
     /**
-     * Converts input JSON string (usually escaped e.g. "{\"a\": \"b\", \"active\": true}" ) to JSON block
+     * Converts input JSON string (usually escaped e.g. "{\"a\": \"b\", \"active\": true}" ) to JSON block.
+     * This helps in picking a value from the JSON block via Jayway Path and assert.
+     *
      * See also-
      * - method jsonBlockToJson for unescaped json to json block.
      * - method jsonNodeToJson for unescaped json to json block.
@@ -58,10 +60,15 @@ public class MimeTypeConverter implements Converter {
      * @throws IOException - This method might throw IOException
      */
     @Override
-    public Object jsonToJson(String jsonString) throws IOException {
+    public Object stringToJson(String jsonString) throws IOException {
         return mapper.readValue(jsonString, JsonNode.class);
     }
 
+    @Override
+    public Object jsonToJson(String jsonString) throws IOException {
+        return stringToJson(jsonString);
+    }
+
     /**
      * Converts JSON Block({"a": "b", "active": true}) to JSON block
      * See also- jsonNodeToJson which is identical to jsonBlockToJson.


Test patch:
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
index 0d819bda..5d7356e5 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
@@ -6,20 +6,41 @@ import com.fasterxml.jackson.databind.node.JsonNodeType;
 import com.google.inject.Inject;
 import com.google.inject.name.Named;
 import com.jayway.jsonpath.JsonPath;
-
-import org.apache.commons.lang.text.StrSubstitutor;
-import org.jsmart.zerocode.core.domain.reports.LocalDateTimeDeserializer;
-import org.jsmart.zerocode.core.engine.assertion.*;
-
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import net.minidev.json.JSONArray;
+import org.apache.commons.lang.text.StrSubstitutor;
+import org.jsmart.zerocode.core.engine.assertion.ArrayIsEmptyAsserter;
+import org.jsmart.zerocode.core.engine.assertion.ArraySizeAsserter;
+import org.jsmart.zerocode.core.engine.assertion.AssertionReport;
+import org.jsmart.zerocode.core.engine.assertion.FieldHasDateAfterValueAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldHasDateBeforeValueAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldHasEqualNumberValueAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldHasExactValueAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldHasGreaterThanValueAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldHasInEqualNumberValueAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldHasLesserThanValueAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldHasSubStringIgnoreCaseValueAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldHasSubStringValueAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldIsNotNullAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldIsNullAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldIsOneOfValueAsserter;
+import org.jsmart.zerocode.core.engine.assertion.FieldMatchesRegexPatternAsserter;
+import org.jsmart.zerocode.core.engine.assertion.JsonAsserter;
 
 import static java.lang.String.format;
 import static org.apache.commons.lang.StringEscapeUtils.escapeJava;
-import static org.jsmart.zerocode.core.utils.TokenUtils.*;
+import static org.jsmart.zerocode.core.utils.TokenUtils.getTestCaseTokens;
+import static org.jsmart.zerocode.core.utils.TokenUtils.populateParamMap;
 import static org.slf4j.LoggerFactory.getLogger;
 
 public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
@@ -106,18 +127,17 @@ public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
                     paramMap.put(thisPath, escapedString);
 
                 } else {
-                    // if it is a json block/node or array, this return value is LinkedHashMap.
-                    if (JsonPath.read(scenarioState, thisPath) instanceof LinkedHashMap) {
-                        final String pathValue = mapper.writeValueAsString(JsonPath.read(scenarioState, thisPath));
-                        String escapedPathValue = escapeJava(pathValue);
-                        paramMap.put(thisPath, escapedPathValue);
+                    Object jsonPathValue = JsonPath.read(scenarioState, thisPath);
+                    if (isPathValueJson(jsonPathValue)) {
+                        final String jsonAsString = mapper.writeValueAsString(jsonPathValue);
+                        String escapedJsonString = escapeJava(jsonAsString);
+                        paramMap.put(thisPath, escapedJsonString);
 
                     } else {
-                        // Usual flow
+
                         paramMap.put(thisPath, JsonPath.read(scenarioState, thisPath));
 
                     }
-
                 }
 
             } catch (Exception e) {
@@ -342,4 +362,9 @@ public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
     private LocalDateTime parseLocalDateTime (String value){ 	
     	return LocalDateTime.parse(value, DateTimeFormatter.ISO_DATE_TIME);
     }
+
+    boolean isPathValueJson(Object jsonPathValue) {
+        return jsonPathValue instanceof LinkedHashMap || jsonPathValue instanceof JSONArray;
+    }
+
 }
diff --git a/core/src/test/java/org/jsmart/zerocode/converter/MimeTypeConverterTest.java b/core/src/test/java/org/jsmart/zerocode/converter/MimeTypeConverterTest.java
index 76cf1d99..57f7babb 100644
--- a/core/src/test/java/org/jsmart/zerocode/converter/MimeTypeConverterTest.java
+++ b/core/src/test/java/org/jsmart/zerocode/converter/MimeTypeConverterTest.java
@@ -4,12 +4,14 @@ import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.jayway.jsonpath.JsonPath;
 import org.jsmart.zerocode.core.di.provider.ObjectMapperProvider;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
 import static org.apache.commons.lang.StringEscapeUtils.escapeJava;
 import static org.apache.commons.lang.StringEscapeUtils.escapeJavaScript;
 import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 public class MimeTypeConverterTest {
@@ -191,4 +193,21 @@ public class MimeTypeConverterTest {
         assertThat(jsonNodeOutput.toString(), containsString("[{\"postCode\":4005"));
 
     }
+
+    @Test
+    public void testConvert_stringToJsonArray() throws Exception{
+        String jsonBlockString = "[{\"id\":\"id-001\",\"name\":\"Emma\"},{\"id\":\"id-002\",\"name\":\"Nikhi\"}]";
+        Object jsonNodeOutput = xmlToJsonConverter.stringToJson(jsonBlockString);
+        assertThat(((JsonNode)jsonNodeOutput).isArray(), is(true));
+        assertThat(((JsonNode)jsonNodeOutput).get(0).get("name").asText(), is("Emma"));
+    }
+
+    @Test
+    public void testConvert_stringToJsonObject() throws Exception{
+        String jsonBlockString = "{\"id\":\"id-001\",\"name\":\"Emma\"}";
+        Object jsonNodeOutput = xmlToJsonConverter.stringToJson(jsonBlockString);
+        assertThat(((JsonNode)jsonNodeOutput).isObject(), is(true));
+        assertThat(((JsonNode)jsonNodeOutput).get("name").asText(), is("Emma"));
+    }
+
 }
\ No newline at end of file
diff --git a/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java b/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
index f4963f1a..3aa308d7 100644
--- a/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
+++ b/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
@@ -1,10 +1,12 @@
 package org.jsmart.zerocode.core.engine.preprocessor;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.jayway.jsonpath.JsonPath;
 import org.jsmart.simulator.main.SimpleRestJsonSimulatorsMain;
 import org.jsmart.zerocode.core.di.main.ApplicationMainModule;
+import org.jsmart.zerocode.core.di.provider.ObjectMapperProvider;
 import org.jsmart.zerocode.core.domain.ScenarioSpec;
 import org.jsmart.zerocode.core.engine.assertion.AssertionReport;
 import org.jsmart.zerocode.core.engine.assertion.JsonAsserter;
@@ -26,14 +28,16 @@ public class ZeroCodeJsonTestProcesorImplTest {
     Injector injector;
     SmartUtils smartUtils;
     SimpleRestJsonSimulatorsMain simulator ;
+    ObjectMapper mapper;
 
-    ZeroCodeJsonTestProcesor jsonPreProcessor;
+    ZeroCodeJsonTestProcesorImpl jsonPreProcessor;
 
     @Before
     public void setUpStuff() throws Exception {
         String serverEnvFileName = "config_hosts_test.properties";
         injector = Guice.createInjector(new ApplicationMainModule(serverEnvFileName));
         smartUtils = injector.getInstance(SmartUtils.class);
+        mapper = new ObjectMapperProvider().get();
         jsonPreProcessor = new ZeroCodeJsonTestProcesorImpl(smartUtils.getMapper(), serverEnvFileName);
     }
 
@@ -1006,4 +1010,65 @@ public class ZeroCodeJsonTestProcesorImplTest {
 
         assertThat(failedReports.size(), is(1));
     }
+
+    @Test
+    public void testJsonPathValue_isArray() throws Exception{
+        String scenarioStateJson = "{\n" +
+                "    \"type\": \"fuzzy\",\n" +
+                "    \"results\": [\n" +
+                "        {\n" +
+                "            \"id\": \"id-001\",\n" +
+                "            \"name\": \"Emma\"\n" +
+                "        },\n" +
+                "        {\n" +
+                "            \"id\": \"id-002\",\n" +
+                "            \"name\": \"Nikhi\"\n" +
+                "        }\n" +
+                "    ]\n" +
+                "}";
+        Object jsonPathValue = JsonPath.read(scenarioStateJson, "$.results");
+        assertThat(mapper.writeValueAsString(jsonPathValue), is("[{\"id\":\"id-001\",\"name\":\"Emma\"},{\"id\":\"id-002\",\"name\":\"Nikhi\"}]"));
+        assertThat(jsonPreProcessor.isPathValueJson(jsonPathValue), is(true));
+    }
+
+    @Test
+    public void testJsonPathValue_isObject() throws Exception {
+        String scenarioStateJson = "{\n" +
+                "    \"type\": \"fuzzy\",\n" +
+                "    \"results\": [\n" +
+                "        {\n" +
+                "            \"id\": \"id-001\",\n" +
+                "            \"name\": \"Emma\"\n" +
+                "        },\n" +
+                "        {\n" +
+                "            \"id\": \"id-002\",\n" +
+                "            \"name\": \"Nikhi\"\n" +
+                "        }\n" +
+                "    ]\n" +
+                "}";
+        Object jsonPathValue = JsonPath.read(scenarioStateJson, "$.results[0]");
+        assertThat(mapper.writeValueAsString(jsonPathValue), is("{\"id\":\"id-001\",\"name\":\"Emma\"}"));
+        assertThat(jsonPreProcessor.isPathValueJson(jsonPathValue), is(true));
+    }
+
+    @Test
+    public void testJsonPathValue_isSingleField() {
+        String scenarioStateJson = "{\n" +
+                "    \"type\": \"fuzzy\",\n" +
+                "    \"results\": [\n" +
+                "        {\n" +
+                "            \"id\": \"id-001\",\n" +
+                "            \"name\": \"Emma\"\n" +
+                "        },\n" +
+                "        {\n" +
+                "            \"id\": \"id-002\",\n" +
+                "            \"name\": \"Nikhi\"\n" +
+                "        }\n" +
+                "    ]\n" +
+                "}";
+        Object jsonPathValue = JsonPath.read(scenarioStateJson, "$.type");
+        assertThat(jsonPathValue+"", is("fuzzy"));
+        assertThat(jsonPreProcessor.isPathValueJson(jsonPathValue), is(false));
+    }
+
 }
\ No newline at end of file
diff --git a/http-testing/src/main/java/org/jsmart/zerocode/zerocodejavaexec/DbSqlExecutor.java b/http-testing/src/main/java/org/jsmart/zerocode/zerocodejavaexec/DbSqlExecutor.java
index 4b485a34..fcd18d36 100644
--- a/http-testing/src/main/java/org/jsmart/zerocode/zerocodejavaexec/DbSqlExecutor.java
+++ b/http-testing/src/main/java/org/jsmart/zerocode/zerocodejavaexec/DbSqlExecutor.java
@@ -2,6 +2,7 @@ package org.jsmart.zerocode.zerocodejavaexec;
 
 import com.google.inject.Inject;
 import com.google.inject.name.Named;
+import java.util.Arrays;
 import org.jsmart.zerocode.zerocodejavaexec.pojo.DbResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,6 +33,20 @@ public class DbSqlExecutor {
         return results;
     }
 
+    public Map<String, List<DbResult>> fetchDbCustomersByName(String name){
+
+        Map<String, List<DbResult>> results = executeSelectSql("any sql");
+
+        DbResult foundResult = results.get(RESULTS_KEY).stream()
+                .filter(thisRecord -> thisRecord.getName().equals(name))
+                .findFirst()
+                .get();
+
+        results.put(RESULTS_KEY, Arrays.asList(foundResult));
+
+        return results;
+    }
+
     private Map<String, List<DbResult>> executeSelectSql(String sqlStatement) {
         LOGGER.info("\n\nDB Connection user:{}, password:{}\n\n", dbUserName, dbPassword);
 
diff --git a/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworldarrayelementmatching/HelloWorldArrayElementPickerTest.java b/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworldarrayelementmatching/HelloWorldArrayElementPickerTest.java
new file mode 100644
index 00000000..d789d102
--- /dev/null
+++ b/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworldarrayelementmatching/HelloWorldArrayElementPickerTest.java
@@ -0,0 +1,19 @@
+package org.jsmart.zerocode.testhelp.tests.helloworldarrayelementmatching;
+
+import org.jsmart.zerocode.core.domain.JsonTestCase;
+import org.jsmart.zerocode.core.domain.TargetEnv;
+import org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@TargetEnv("github_host.properties")
+@RunWith(ZeroCodeUnitRunner.class)
+public class HelloWorldArrayElementPickerTest {
+
+    @Test
+    @JsonTestCase("helloworld_array_dynamic_element/dynamic_array_element_picker_test.json")
+    public void testArrayDynamicElementPick() throws Exception {
+
+    }
+
+}
diff --git a/http-testing/src/test/resources/helloworld_array_dynamic_element/dynamic_array_element_picker_test.json b/http-testing/src/test/resources/helloworld_array_dynamic_element/dynamic_array_element_picker_test.json
new file mode 100644
index 00000000..d129b3d1
--- /dev/null
+++ b/http-testing/src/test/resources/helloworld_array_dynamic_element/dynamic_array_element_picker_test.json
@@ -0,0 +1,44 @@
+{
+    "scenarioName": "Pick a value from result array when JSON Path returns an array for a single matching field",
+    "steps": [
+        {
+            "name": "get_records",
+            "url": "org.jsmart.zerocode.zerocodejavaexec.DbSqlExecutor",
+            "operation": "fetchDbCustomers",
+            "request": "select id, name from customers",
+            "assertions": {
+                "results": [
+                    {
+                        "id": 1,
+                        "name": "Elon Musk"
+                    },
+                    {
+                        "id": 2,
+                        "name": "Jeff Bezos"
+                    }
+                ]
+            }
+        },
+        {
+            "name": "find_matching_value",
+            "url": "org.jsmart.zerocode.converter.MimeTypeConverter",
+            "operation": "stringToJson",
+            "request": "${$.get_records.response.results[?(@.id=='2')].name}",
+            "assertions": [ "Jeff Bezos" ]
+        },
+        {
+            "name": "get_by_name",
+            "url": "org.jsmart.zerocode.zerocodejavaexec.DbSqlExecutor",
+            "operation": "fetchDbCustomersByName",
+            "request": "${$.find_matching_value.response[0]}", //<--- Picked the field from the above array i.e. the step `find_matching_value`
+            "assertions": {
+                "results": [
+                    {
+                        "id": 2,
+                        "name": "Jeff Bezos"
+                    }
+                ]
+            }
+        }
+    ]
+}