Trouble using #regex marker - karate

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)' }

Related

Can anyone explain how to get all the mismatch between two Array of JSON Object responses in karate? [duplicate]

Like if I have two JSON as below and I want to check the mismatch between those
JSON 1:
{
name:'john',
contact:'123',
country:'america'
}
JSON 2:
{
name:'vishal',
contact:'123',
country:'India'
}
Now it will return me with the mismatch between name and country not only the name?
No this is not supported. We feel this is not needed, because in your regular CI runs you only care if the test passed or failed, and you see the details in the log.
Also note that you can simulate this if you really want using a Scenario Outline: https://stackoverflow.com/a/54108755/143475
Finally, if you care so much about this, kindly contribute code, this is open-source after all.
EDIT: you can easily do this by iterating over keys. Here is the code:
EDIT2: Setting up data via a Background is no longer supported in version 1.3.0 onwards, please look at the #setup tag: https://github.com/karatelabs/karate#setup
Feature:
Background:
* def json1 = { name: 'john', contact: '123', country: 'america' }
* def json2 = { name: 'vishal', contact: '123', country: 'India' }
* def keys = karate.keysOf(json1)
* def data = karate.mapWithKey(keys, 'key')
Scenario Outline: <key>
* match (json1[key]) == json2[key]
Examples:
| data |
And here is the report:

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)' }

Is there a way to test response is contained in schema?

In Karate, I'd like to have a schema variable which is a superset of the response data so that I can test multiple requests with the same schema.
This should be specially useful for GraphQL, where the request itself defines the returned fields.
Expected schema:
{
id: '#notnull',
name: '#notnull',
description: '##string',
nonNullStringField: '#string'
...
}
Given url ...
When request ...
Then match response.data <contained in> '#(mySchema)'
Response.data:
{
id: 'someId',
name: 'some name'
}
In this case, all keys returned by the response.data should be in the schema, but any key in the schema not in the response.data should be ignored.
Is there a way to do that in Karate or some plan to add this feature going forward?
Edit: updated the example, since the only attribute being missed was a nullable one.
I'm not convinced an enhancement is needed, because the optional marker ##foo was designed for this purpose, and this already works:
* def schema = { id: '#notnull', name: '#notnull', description: '##string' }
* def response = { id: 'someId', name: 'some name' }
* match response == schema
EDIT: but since you want to limit your schema to the keys in the response in a "generic" way, you can do this:
* def expected = {}
* def fun = function(k, v){ expected.put(k, schema[k]) }
* eval karate.forEach(response, fun)
* match response == expected
You should be able to easily create a re-usable JS or Java utility that achieves the above. A few reasons I'm not in favor of adding another syntax / match keyword is that nested JSON may have some interesting edge cases that will make this complex. And I don't want to complicate match any further. As I said in the comments, IMO schema validation is the last thing you need to test for in GraphQL, it is pretty much guaranteed. This is the first time anyone has requested this in 2 years, so there's that. You could consider submitting a PR of course :)

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)' }

Karate contains and all key-values did not match error

I try to learn Karate but have some issue and I can't resolve it by myself.
So my Feature is looking rather simple:
Feature: Alerting get the list of all alerts
Background:
* url 'url'
Scenario: Retrieve all alerts
Given path '5c348c553a892c000bb1f2dd'
When method get
Then status 200
And match response contains {id: 5c348c553a892c000bb1f2dd}
The case here is to fetch a response and make sure that given ID is on the list. As far I understand this documentation keyword contains should lookup only for the given phrase but I get an error: reason: all key-values did not match
This is my console output:
allAlertsGet.feature:10 - path: $, actual: {data={name=Baelish of Harrenhal, user=griffin, id=5c348c553a892c000bb1f2dd, tags=["Gared"], triggers={prometheus=[{"js_id":"Qarth","labels":["Harry Potter and the Sorcerer's Stone"],"operator":"==","query":"up","value":"1"}]}, trigger_interval=398s, receivers={slack=[{"holdoffTime":"0s","id":"Stalls","message":"Dark and difficult times lie ahead. Soon we must all face the choice between what is right and what is easy.","revokeMessage":"Every flight begins with a fall.","token":"Buckbeak"}]}, hold_cap=4, max_cap=16, factor=2, createDate=1546947669, triggered_date=1546948867, mute_until=0, muted=false, status=3}}, expected: {id=5c348c553a892c000bb1f2dd}, reason: all key-values did not match
What I have missed? I use karate 0.9.0.
Pay attention to the nested structure of your JSON. You can paste this snippet into a Scenario and try it, this is a tip - you can experiment quickly without making HTTP requests like this:
* def response = { data: { name: 'Baelish of Harrenhal', user: 'griffin', id: '5c348c553a892c000bb1f2dd' } }
* match response.data contains { id: '5c348c553a892c000bb1f2dd' }
EDIT: just to show off a few other ways to do assertions:
* match response.data.id == '5c348c553a892c000bb1f2dd'
* match response..id contains '5c348c553a892c000bb1f2dd'
* def id = { id: '5c348c553a892c000bb1f2dd' }
* match response == { data: '#(^id)' }
* match response contains { data: '#(^id)' }