Null values in CSV Scenario Outline [duplicate] - karate

I am able to read a csv file and convert it to json by
def expectedResponse = read('classpath:somefile.csv')
Suppose I have csv file as below
name,age
praveen,29
joseph,20
1.It is converting all elements as string and stores in the variable as json. How to keep the number as a number ? because it causes match failure which i do later with the actual response.
2.How to get the value 20. Like by specifying joseph, I want to get the age.
I got the jsonpath as
get expectedResponse $.[?(#.member == '<name>')].age
I get the name from examples. So I get it as joseph in runtime. But i get error as reason: not equal (Integer : JSONArray). It is not returning the age alone (Integer value)
Or is there any better way to get it ?

The CSV format does not contain any type information, so everything defaults to "string" and you have to convert it yourself. But this is easy using karate.map().
* text users =
"""
name,age
praveen,29
joseph,20
"""
* csv users = users
* match users == [{ name: 'praveen', age: '29' }, { name: 'joseph', age: '20' }]
* def fun = function(x){ x.age = ~~x.age; return x }
* def users = karate.map(users, fun)
* match users == [{ name: 'praveen', age: 29 }, { name: 'joseph', age: 20 }]

Related

Is there a way to set some values in the multiple dimensional json array

Scenario Outline: Explore Karate '<ID>'
* karate.set($attributesFirstRun[*].created_timestamp,'#present')
* karate.set($attributesSecondRun[*].created_timestamp,'#present')
* match attributesFirstRun == attributesSecondRun
Examples:
| read('Sample.csv') |
I tried this. But I'm getting this error
org.graalvm.polyglot.PolyglotException: SyntaxError: Unnamed:1:42 Expected an operand but found *
I think you are over-thinking this. Karate is actually just plain JS. And sounds like you are trying to do a "bulk update" via JsonPath - sorry, that's not supported, perhaps you would be interested in contributing code.
Here's the solution for updating all elements of an array:
* def before = [{ a: 1 }, { a: 2 }]
* def after = before.map(x => ({ a: x.a * 5 }))
* match after == [{ a: 5 }, { a: 10 }]
Keep in mind updating JSON is easy:
* def data = {}
* data.a = 1
* match data == { a: 1 }
Refer the docs: https://github.com/karatelabs/karate#json-transforms

Date regexp failing [duplicate]

I'm having trouble constructing a proper #regex marker.
I'm trying to match on a couple of date formats in my response JSON:
"created": "2017-03-23T14:16:25.854Z"
"modified": "2018-06-21T05:38:37.978Z"
I've attempted the following markers:
'#regex [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}Z'
'#regex [0-9]{4}-[0-9]{2}-[0-9]{2}.[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}.'
'#regex \d+-\d+-\d+.\d+:\d+:\d+.\d+.'
All 3 forms appear to be correct (according to rubular.com). I've also played around with escaping characters that might be problematic. The only one I been able to get tot work so far is:
[0-9-T:.Z]+
But this feels a little "loose" of a pattern match.
Basically I'm attempting this:
* def meta = { created: '#regex[[0-9]{4}-[0-9]{2}-[0-9]{2}.[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}.]', modified: '#regex[[0-9]{4}-[0-9]{2}-[0-9]{2}.[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}.]' }
And match each response ==
"""
{
id: '#regex [a-z0-9]+',
name: '#string',
type: '<Type>',
meta: #(meta),
integration_id: '#uuid'
}
"""
Get an error similar to this:
KarateException: objects-api.feature:40 - path: $[0].meta.created, actual: '2016-11-30T20:48:16.782Z', expected: '#regex [0-9]+-[0-9]+-[0-9]+[0-9]+:[0-9]+:[0-9]+[0-9]+', reason: regex match failed
Here is a suggestion, why don't you parse the dates into java Date objects and that will open up more possibilities such as being able to compare 2 dates.
Here are good examples:
https://stackoverflow.com/a/54133126/143475
https://stackoverflow.com/a/55938480/143475
That said, I think you missed having to escape the backslash-es, this is a Java thing and is mentioned in the docs. So this works:
* def date = '2017-03-23T14:16:25.854Z'
* match date == '#regex \\d+-\\d+-\\d+.\\d+:\\d+:\\d+.\\d+.'
* match date == '#regex [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}Z'
The Karate JS engine also supports the RegExp JS object, so see if this example gives you some solutions as well:
https://stackoverflow.com/a/54768838/143475
EDIT, this works for me as well:
* def meta = { created: '#regex \\d+-\\d+-\\d+.\\d+:\\d+:\\d+.\\d+.', modified: '#regex \\d+-\\d+-\\d+.\\d+:\\d+:\\d+.\\d+.' }
* def response = [{ meta: { created: '2017-03-23T14:16:25.854Z', modified: '2018-06-21T05:38:37.978Z' } }]
* match each response == { meta: '#(meta)' }

Trouble using #regex marker

I'm having trouble constructing a proper #regex marker.
I'm trying to match on a couple of date formats in my response JSON:
"created": "2017-03-23T14:16:25.854Z"
"modified": "2018-06-21T05:38:37.978Z"
I've attempted the following markers:
'#regex [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}Z'
'#regex [0-9]{4}-[0-9]{2}-[0-9]{2}.[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}.'
'#regex \d+-\d+-\d+.\d+:\d+:\d+.\d+.'
All 3 forms appear to be correct (according to rubular.com). I've also played around with escaping characters that might be problematic. The only one I been able to get tot work so far is:
[0-9-T:.Z]+
But this feels a little "loose" of a pattern match.
Basically I'm attempting this:
* def meta = { created: '#regex[[0-9]{4}-[0-9]{2}-[0-9]{2}.[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}.]', modified: '#regex[[0-9]{4}-[0-9]{2}-[0-9]{2}.[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}.]' }
And match each response ==
"""
{
id: '#regex [a-z0-9]+',
name: '#string',
type: '<Type>',
meta: #(meta),
integration_id: '#uuid'
}
"""
Get an error similar to this:
KarateException: objects-api.feature:40 - path: $[0].meta.created, actual: '2016-11-30T20:48:16.782Z', expected: '#regex [0-9]+-[0-9]+-[0-9]+[0-9]+:[0-9]+:[0-9]+[0-9]+', reason: regex match failed
Here is a suggestion, why don't you parse the dates into java Date objects and that will open up more possibilities such as being able to compare 2 dates.
Here are good examples:
https://stackoverflow.com/a/54133126/143475
https://stackoverflow.com/a/55938480/143475
That said, I think you missed having to escape the backslash-es, this is a Java thing and is mentioned in the docs. So this works:
* def date = '2017-03-23T14:16:25.854Z'
* match date == '#regex \\d+-\\d+-\\d+.\\d+:\\d+:\\d+.\\d+.'
* match date == '#regex [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}Z'
The Karate JS engine also supports the RegExp JS object, so see if this example gives you some solutions as well:
https://stackoverflow.com/a/54768838/143475
EDIT, this works for me as well:
* def meta = { created: '#regex \\d+-\\d+-\\d+.\\d+:\\d+:\\d+.\\d+.', modified: '#regex \\d+-\\d+-\\d+.\\d+:\\d+:\\d+.\\d+.' }
* def response = [{ meta: { created: '2017-03-23T14:16:25.854Z', modified: '2018-06-21T05:38:37.978Z' } }]
* match each response == { meta: '#(meta)' }

How to match a string value from the database with an integer value from the response

My feature calls Java to query the database and then compares the results with the response. The results from the Java call returns all values as string. But in the response some of values are integer. So the test fails with the reason: actual value is not a string. I have tried to convert the results to json but that didn't work. If I print out the results, it shows all keys and values are enclosed in double quotes, but there are no double quotes in the error message. I found a similar question in the forum and it was suggested to set the field in the response to '#ignore'. But I want to verify all the fields. How do I get this to work?
Scenario: Get an script by id
* def results = db.getRows("select * from ScriptVersion where id=4 order by version")
Given path '4'
When method get
Then status 200
And match response.version == results
[main] ERROR com.intuit.karate - assertion failed: path: $.version[0], actual: {id=4, version=1, created=2016-06-23T10:49:51.9630000-05:00, updated=2016-06-23T10:49:51.9630000-05:00, message=Initial Version, author=ocadm, hash=0023ad00455962eee4ef1db16a58ce41}, expected: {created=2016-06-23T10:49:51.9630000-05:00, author=ocadm, id=4, message=Initial Version, version=1, updated=2016-06-23T10:49:51.9630000-05:00, hash=0023ad00455962eee4ef1db16a58ce41}, reason: [path: $.version[0].id, actual: 4, expected: '4', reason: actual value is not a string]
Just convert the fields you need to the right data type before the match:
* def results = [{ id: '1', foo: 'bar' }, { id: '2', foo: 'baz' }]
* def fun = function(x){ x.id = ~~x.id; return x }
* def results = karate.map(results, fun)
* match results == [{ id: 1, foo: 'bar' }, { id: 2, foo: 'baz' }]

Karate Schema validation, does it work with nested arrays when using match contains assertion?

I'm trying to use a match on a json object by only checking for some elements. The Json object contains a nested array which seem to be the root cause for the test failing. It seems like using the 'match contains' assertion on key:values within the nested array does not work as expected and throws an error.
I've tried to use 'match contains' on first level keys and that works fine but when attempting to match keys within a nested array I get the following error message: reason: actual value has 1 more key(s) than expected
* def json = { id: 1, priority: 1, compRound: { id: 1, comp_id: 89 } }
* match json contains
"""
{
id: '#number',
priority: '#number',
compRound: {
id: '#number'
}
}
"""
As I'm using the match contains assertion, I would expect for the test to pass but instead it looks like Karate expects all key:values within the nested array to be present.
Please read this section of the docs carefully: https://github.com/intuit/karate#contains-short-cuts
* def json = { id: 1, priority: 1, compRound: { id: 1, comp_id: 89 } }
* def compRound = { id: '#number' }
* match json == { id: '#number', priority: '#number', compRound: '#(^compRound)' }