Karate - Cannot cast java.util.LinkedHashMap to java.util.List - karate

I need to compare an XML file with that of Json response. Below is just a short version of original xml file, JSON and XML have different attribute names because of which i cannot compare them directly. I need to call function to format xml so that it can be compared with json. During this process, I am getting the error Cannot cast java.util.LinkedHashMap to java.util.List after running below code.
* xml list = $Test1/Body
* print list
* def xpath = function(x, p){ try { return karate.xmlPath(x, p) } catch (e) { return '#notpresent' } }
* def fun = function(x){ return { code: xpath(x, '/Body/code') } }
* def temp = karate.map(list, fun)
* print temp
Test1 is an xml file containing below sample data;
<ns9:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns5:plan">
<ns4:code>XPBSMWAT</ns4:code>
</ns9:Body>
This is a simpler version of XML data; my actual xml file is bigger.

karate.map takes 2 arguments list and a function,
From your question,
* xml list = $Test1/Body
variable name list is actually of a xml data type as you defined, not a list.
karate takes XML/JSON as java.util.LinkedHashMap since you passed the XML as input to the map function it tried to cast it into List and failed.
So it should be something like,
* def list = <something>
But make sure instead of xml it returns a list
Your xml path $Test1/Body returns xml
when you print the list you will see it surrounded with [ and
]
I am not quite sure what you are trying to do with this xml and JS functions but this could be root cause for the error you are getting.

Related

Karate: Unable to replace embedded expression value inside a XML chunk read from a JS function

Unable to replace embedded expression value inside a XML chunk read from a JS function, had a look at string to XML conversion. But unable to figure out what am I missing,
Scenario file has below, which calls a js function to get XML chunk containing a embedded expression,
* def customerNumber = functions.getRandomNumber()
* xml Security1 = functions.fetchSecExistMort()
* print Security1
Sharing JS function in my next comment.
Below is my javascript function,
function()
{
return {
fetchPrimaryResiAddress: function()
{
var PrimaryResidentialAddress =
`<Address>
<StreetNo>#(customerNumber)</StreetNo>
<Street Type="Street">RAWSON</Street>
<City>DEAKIN</City>
<State Name="ACT"/>
<Postcode>2600</Postcode>
<Country ISO3166="AU"/>
</Address>`;
return PrimaryResidentialAddress;
}
getRandomNumber: function()
{
var temp = '';
karate.repeat(14, function(){ temp += Math.floor(Math.random() * 9) + 1 });
return temp;
}
}
}
As part of print outcome, embedded expression #(customerNumber) isnt getting updated to customerNumber value
Embedded expressions will not work within JS. It is designed to work only within feature files, or when using the read() API.
If you are using JS, just do some string-concatenation and move-on.

Karate : Trying to convert array to string using js method toString() in karate [duplicate]

This question already has an answer here:
Change type from string to float/double for a key value of any json object in an array
(1 answer)
Closed 1 year ago.
I'm trying to convert an Array to string using a simple js function placed in the reusable feature file. I don't see any reason why the array is not getting converted to a string when I try to run the same function on the console it works without any issue.
Can anyone suggest a way to get this issue sorted?
"""
* def formatter = function(str){
var formatstring = str.toString();
return formatstring
}
"""
feature file
* def format = call read('../common/resuable.feature)
* def result = format.formatter(value)
* print result
Input = ["ID3:Jigglypuff(NORMAL)"]
Actual result = ["ID3:Jigglypuff(NORMAL)"]
Expected result = ID3:Jigglypuff(NORMAL)
[![When tried same on console][1]][1]
[1]: https://i.stack.imgur.com/tAcIz.png
Sorry, if you print an array, it will have square-brackets and all, that's just how it is.
Please unpack arrays if you want the plain string / content:
* def input = ["ID3:Jigglypuff(NORMAL)"]
* def expected = input[0]

Groovy : Class.forName().newInstance() error

I have this following method in which I return a List<ImField> object using the List<GPathResult> filteredList. I perform filteredList.each closure where I generate
class at runtime and assign it a static type of ImField.
static List<ImField> getFields(GPathResult root,String fieldClass, String fieldType){
List<GPathResult> filteredList = root.children().findAll{
XMLSlurperUtil.name(it as GPathResult) == fieldType
} as List<GPathResult>
List<ImField> fields = []
filteredList.each{GPathResult it, int index ->
fields.add(Class.forName(fieldClass).newInstance() as ImField)
fields[index].set(it)
}
fields
}
The function call would look like so :
ImStageUtil.getFields(root, ImFieldFactory.SOURCE_FIELD, ImParserConstants.SOURCE_FIELD)
where ImFieldFactory.SOURCE_FIELD = "com.dto.fields.SourceField"
and ImParserContants.SOURCE_FIELD = "SOURCEFIELD"
the error occurs at the .each closure line:
No signature of method: com.extractor.ImStageUtil$_getFields_closure11.doCall() is applicable for argument types: (groovy.util.slurpersupport.NodeChild) values: []
Possible solutions: doCall(groovy.util.slurpersupport.GPathResult, int), findAll(), findAll(), isCase(java.lang.Object), isCase(java.lang.Object)
groovy.lang.MissingMethodException: No signature of method: com.extractor.ImStageUtil$_getFields_closure11.doCall() is applicable for argument types: (groovy.util.slurpersupport.NodeChild) values: []
Possible solutions: doCall(groovy.util.slurpersupport.GPathResult, int), findAll(), findAll(), isCase(java.lang.Object), isCase(java.lang.Object)
I've tried to create a similar script to your example, there are two things I had to modify (if your filteredList is not empty, which you need to check first):
1- You need to use collect() after the findAll{} closure, this allows you to collect all entries and add them to your filteredList.
2- You're using .each{} and you're providing a List along with the index, this should be replaced by .eachWithIndex{} because the first one doesn't expect an index.
Here is a simplified version of your code:
import groovy.util.slurpersupport.GPathResult
def text = '''
<list>
<technology>
<name>Groovy</name>
</technology>
</list>
'''
def list = new XmlSlurper().parseText(text)
def List getFields(GPathResult root,String fieldClass, String fieldType){
List<GPathResult> filteredList = root.children().findAll{
//println(it)
it != null
}.collect() as List<GPathResult>
println('list: ' + filteredList.getClass() + ', ' + filteredList.size())
filteredList.eachWithIndex{GPathResult it, int index ->
println('it: ' + it)
}
}
getFields(list, '', '')
This last example doesn't raise any exception for me.
Hope this helps.

Expression with String placeholder in the filter part of JsonPath using karate

I am trying to filter my response using JSON Path where one of the condition using a value from a variable but I am not able to map variable properly, so my filter not working properly.
Sample response JSON:
{
"response":[
{
"id":"1234",
"confirmationCode":"abcd"
}
]
}
I am using the below script where I am using variable 'code':
* def Code = 'abcd'
* def value = karate.jsonPath($.response[?(#.confirmationCode == ' + Code +')])
Read the docs carefully please:
* def value = karate.jsonPath(response, "$.response[?(#.confirmationCode=='" + Code + "')]")

Groovy dynamic method invocation with nested function

I need to evaluate a string with nested function calls. Is there an easy way to do this with groovy?
Edit: Code made more realistic. The context is nonacademic; my function needs to combine and evaluate a bunch of arbitrary strings and values from json files.
JSON file 1 will have strings like:
"biggerThan(isList,0)"
"smallerThan(isList,3)"
"biggerThan(isList,1)"
JSON file 2 will have values like
[4,1]
[1,2,1]
[1,5,6,2,98]
[]
def biggerThan= {func, val->
{v->return func(v) && (v.size() > val)}
}
def isList ={n->
return n instanceof List
}
def a=biggerThan(isList,1)
a([4,1])
// -> returns true in groovy console because [4,1] is a list with size>1