How can I use eval for conditional feature call with parameters? - karate

I wanted to call another feature file in a feature file with parameters but if a data value of previous api's response is true. And after running this eval function I wanted to it continue to run other parts of my main feature. I wrote this code;
eval if (response.data.eula == true) karate.call('classpath:eula/eula-sign.feature') { no: '#(no)' , password: '#(password)'}
But I can't use eval like this. How can I achieve my aim that I explained above?
I've tried conditional logic methods which explained in Karate intuit page. But I couldn't solve my problem.
eval if (response.data.eula == true) karate.call('classpath:eula/eula-sign.feature') { no: '#(no)' , password: '#(password)'}
As I expect error, Karate gave me these logs;
com.intuit.karate.exception.KarateException: content-filter.feature:26 - javascript evaluation failed: if (response.data.eula == true) ; karate.call('classpath:eulasign/eula-sign.feature') { no: '#(no)' , password: '#(password)'}, :1:135 Expected ; but found {
if (response.data.eula == true) ; karate.call('classpath:eulasign/eula-sign.feature') { no: '#(no)' , password: '#(password)'}
^ in at line number 1 at column number 135

You are mixing karate.call and call read.
It's either karate.call(fileName, [arg]) or call read(filename) { arg }
So in your case with karate.call, the variables no and password have to be passed in JSON format as the second argument of your function.

Related

How to handle multiple conditions for responseStatus [duplicate]

I'm using Karate framework with JUnit.
Using this feature:
Given path 'save_token'
And request
"""
{
"token": "test_token"
}
"""
And retry until response.tokens ==
"""
[
"test_token"
]
"""
When method POST
I'm having this exception:
java.lang.ArrayIndexOutOfBoundsException: 1
at com.intuit.karate.core.MethodMatch.convertArgs(MethodMatch.java:60)
at com.intuit.karate.core.Engine.executeStep(Engine.java:141)
at com.intuit.karate.core.ScenarioExecutionUnit.execute(ScenarioExecutionUnit.java:171)
When response.tokens list is empty:
{
"tokens": []
}
I don't understand why == does not work in this case (it should return false, and keep retrying).
Thanks in advance!
The retry until expression has to be pure JavaScript and the special Karate match keywords such as contains are not supported, and you can't do a "deep equals" like how you are trying, as that also is not possible in JS.
EDIT: in 0.9.6. onwards you can do a complex match in JS: https://stackoverflow.com/a/50350442/143475
Also note that JsonPath is not supported, which means * or .. cannot appear in the expression.
So if your response is { "tokens": [ "value1" ] }, you can do this:
And retry until response.tokens.includes('value1')
Or:
And retry until response.tokens[0] == 'value1'
To experiment, you can try expressions like this:
* def response = { "tokens": [ "value1" ] }
* assert response.tokens.includes('value1')
At run time, you can use JS to take care of conditions when the response is not yet ready while polling:
And retry until response.tokens && response.tokens.length
EDIT: actually a more elegant way to do the above is shown below, because karate.get() gracefully handles a JS or JsonPath evaluation failure and returns null:
And retry until karate.get('response.tokens.length')
Or if you are dealing with XML, you can use the karate.xmlPath() API:
And retry until karate.xmlPath(response, '//result') == 5
And if you really want to use the power of Karate's match syntax, you can use the JS API:
And retry until karate.match(response, { tokens: '##[_ > 0]' }).pass
Note that if you have more complex logic, you can always wrap it into a re-usable function:
* def isValid = function(x){ return karate.match(x, { tokens: '##[_ > 0]' }).pass }
# ...
And retry until isValid(response)
Finally if none of the above works, you can always switch to a custom polling routine: polling.feature
EDIT: also see this answer for an example of how to use karate.filter() instead of JsonPath: https://stackoverflow.com/a/60537602/143475
EDIT: in version 0.9.6 onwards, Karate can do a match in JS, which can simplify some of the above: https://stackoverflow.com/a/50350442/143475

Karate: retry until with response expression [duplicate]

I'm using Karate framework with JUnit.
Using this feature:
Given path 'save_token'
And request
"""
{
"token": "test_token"
}
"""
And retry until response.tokens ==
"""
[
"test_token"
]
"""
When method POST
I'm having this exception:
java.lang.ArrayIndexOutOfBoundsException: 1
at com.intuit.karate.core.MethodMatch.convertArgs(MethodMatch.java:60)
at com.intuit.karate.core.Engine.executeStep(Engine.java:141)
at com.intuit.karate.core.ScenarioExecutionUnit.execute(ScenarioExecutionUnit.java:171)
When response.tokens list is empty:
{
"tokens": []
}
I don't understand why == does not work in this case (it should return false, and keep retrying).
Thanks in advance!
The retry until expression has to be pure JavaScript and the special Karate match keywords such as contains are not supported, and you can't do a "deep equals" like how you are trying, as that also is not possible in JS.
EDIT: in 0.9.6. onwards you can do a complex match in JS: https://stackoverflow.com/a/50350442/143475
Also note that JsonPath is not supported, which means * or .. cannot appear in the expression.
So if your response is { "tokens": [ "value1" ] }, you can do this:
And retry until response.tokens.includes('value1')
Or:
And retry until response.tokens[0] == 'value1'
To experiment, you can try expressions like this:
* def response = { "tokens": [ "value1" ] }
* assert response.tokens.includes('value1')
At run time, you can use JS to take care of conditions when the response is not yet ready while polling:
And retry until response.tokens && response.tokens.length
EDIT: actually a more elegant way to do the above is shown below, because karate.get() gracefully handles a JS or JsonPath evaluation failure and returns null:
And retry until karate.get('response.tokens.length')
Or if you are dealing with XML, you can use the karate.xmlPath() API:
And retry until karate.xmlPath(response, '//result') == 5
And if you really want to use the power of Karate's match syntax, you can use the JS API:
And retry until karate.match(response, { tokens: '##[_ > 0]' }).pass
Note that if you have more complex logic, you can always wrap it into a re-usable function:
* def isValid = function(x){ return karate.match(x, { tokens: '##[_ > 0]' }).pass }
# ...
And retry until isValid(response)
Finally if none of the above works, you can always switch to a custom polling routine: polling.feature
EDIT: also see this answer for an example of how to use karate.filter() instead of JsonPath: https://stackoverflow.com/a/60537602/143475
EDIT: in version 0.9.6 onwards, Karate can do a match in JS, which can simplify some of the above: https://stackoverflow.com/a/50350442/143475

Karate: I would like to use retry more efficiently [duplicate]

I'm using Karate framework with JUnit.
Using this feature:
Given path 'save_token'
And request
"""
{
"token": "test_token"
}
"""
And retry until response.tokens ==
"""
[
"test_token"
]
"""
When method POST
I'm having this exception:
java.lang.ArrayIndexOutOfBoundsException: 1
at com.intuit.karate.core.MethodMatch.convertArgs(MethodMatch.java:60)
at com.intuit.karate.core.Engine.executeStep(Engine.java:141)
at com.intuit.karate.core.ScenarioExecutionUnit.execute(ScenarioExecutionUnit.java:171)
When response.tokens list is empty:
{
"tokens": []
}
I don't understand why == does not work in this case (it should return false, and keep retrying).
Thanks in advance!
The retry until expression has to be pure JavaScript and the special Karate match keywords such as contains are not supported, and you can't do a "deep equals" like how you are trying, as that also is not possible in JS.
EDIT: in 0.9.6. onwards you can do a complex match in JS: https://stackoverflow.com/a/50350442/143475
Also note that JsonPath is not supported, which means * or .. cannot appear in the expression.
So if your response is { "tokens": [ "value1" ] }, you can do this:
And retry until response.tokens.includes('value1')
Or:
And retry until response.tokens[0] == 'value1'
To experiment, you can try expressions like this:
* def response = { "tokens": [ "value1" ] }
* assert response.tokens.includes('value1')
At run time, you can use JS to take care of conditions when the response is not yet ready while polling:
And retry until response.tokens && response.tokens.length
EDIT: actually a more elegant way to do the above is shown below, because karate.get() gracefully handles a JS or JsonPath evaluation failure and returns null:
And retry until karate.get('response.tokens.length')
Or if you are dealing with XML, you can use the karate.xmlPath() API:
And retry until karate.xmlPath(response, '//result') == 5
And if you really want to use the power of Karate's match syntax, you can use the JS API:
And retry until karate.match(response, { tokens: '##[_ > 0]' }).pass
Note that if you have more complex logic, you can always wrap it into a re-usable function:
* def isValid = function(x){ return karate.match(x, { tokens: '##[_ > 0]' }).pass }
# ...
And retry until isValid(response)
Finally if none of the above works, you can always switch to a custom polling routine: polling.feature
EDIT: also see this answer for an example of how to use karate.filter() instead of JsonPath: https://stackoverflow.com/a/60537602/143475
EDIT: in version 0.9.6 onwards, Karate can do a match in JS, which can simplify some of the above: https://stackoverflow.com/a/50350442/143475

How to override the NQPMatch.Str function

... Or how to change $<sigil>.Str value from token sigil { ... } idependently from the matched text. Yes I'm asking how to cheat grammars above (i.e. calling) me.
I am trying to write a Slang for Raku without sigil.
So I want the nogil token, matching anything <?> to return NqpMatch that stringifies: $<sigil>.Str to '$'.
Currently, my token sigil look like that
token sigil {
| <[$#%&]>
| <nogil> { say "Nogil returned: ", lk($/, 'nogil').Str; # Here It should print "$"
}
}
token nogil-proxy {
| '€'
| <?>
{log "No sigil:", get-stack; }
}
And the method with that should return a NQPMatch with method Str overwritten
method nogil {
my $cursor := self.nogil-proxy;
# .. This si where Nqp expertise would be nice
say "string is:", $cursor.Str; # here also it should print "$"
return $cursor;
}
Failed try:
$cursor.^cache_add('Str', sub { return '$'; } );
$cursor.^publish_method_cache;
for $cursor.^attributes { .name.say };
for $cursor.^methods { .name.say };
say $cursor.WHAT.Str;
nqp::setmethcacheauth($cursor, 0);
Currently, most of my tests work but I have problems in declarations without my (with no strict) like my-var = 42; because they are considered as method call.
#Arne-Sommer already made a post and an article. This is closely related. But this questions aims:
How can we customize the return value of a compile-time token and not how to declare it.
Intro: The answer, pointed by #JonathanWorthington:
Brief: Use the mixin meta function. (And NOT the but requiring compose method.)
Demo:
Create a NQPMatch object by retrieving another token: here the token sigil-my called by self.sigil-my.
Use ^mixin with a role
method sigil { return self.sigil-my.^mixin(Nogil::StrGil); }
Context: full reproducible code:
So you can see what type are sigil-my and Nogil::StrGil. But I told you: token (more than method) and role (uninstantiable classes).
role Nogil::StrGil {
method Str() {
return sigilize(callsame);
}
}
sub EXPORT(|) {
# Save: main raku grammar
my $main-grammar = $*LANG.slang_grammar('MAIN');
my $main-actions = $*LANG.slang_actions('MAIN');
role Nogil::NogilGrammar {
method sigil {
return self.sigil-my.^mixin(Nogil::StrGil);
}
}
token sigil-my { | <[$#%&]> | <?> }
# Mix
my $grammar = $main-grammar.^mixin(Nogil::NogilGrammar);
my $actions = $main-actions.^mixin(Nogil::NogilActions);
$*LANG.define_slang('MAIN', $grammar, $actions);
# Return empty hash -> specify that we’re not exporting anything extra
return {};
}
Note: This opens the door to mush more problems (also pointed by jnthn question comments) -> -0fun !

Karate framework retry until not working as expected

I'm using Karate framework with JUnit.
Using this feature:
Given path 'save_token'
And request
"""
{
"token": "test_token"
}
"""
And retry until response.tokens ==
"""
[
"test_token"
]
"""
When method POST
I'm having this exception:
java.lang.ArrayIndexOutOfBoundsException: 1
at com.intuit.karate.core.MethodMatch.convertArgs(MethodMatch.java:60)
at com.intuit.karate.core.Engine.executeStep(Engine.java:141)
at com.intuit.karate.core.ScenarioExecutionUnit.execute(ScenarioExecutionUnit.java:171)
When response.tokens list is empty:
{
"tokens": []
}
I don't understand why == does not work in this case (it should return false, and keep retrying).
Thanks in advance!
The retry until expression has to be pure JavaScript and the special Karate match keywords such as contains are not supported, and you can't do a "deep equals" like how you are trying, as that also is not possible in JS.
EDIT: in 0.9.6. onwards you can do a complex match in JS: https://stackoverflow.com/a/50350442/143475
Also note that JsonPath is not supported, which means * or .. cannot appear in the expression.
So if your response is { "tokens": [ "value1" ] }, you can do this:
And retry until response.tokens.includes('value1')
Or:
And retry until response.tokens[0] == 'value1'
To experiment, you can try expressions like this:
* def response = { "tokens": [ "value1" ] }
* assert response.tokens.includes('value1')
At run time, you can use JS to take care of conditions when the response is not yet ready while polling:
And retry until response.tokens && response.tokens.length
EDIT: actually a more elegant way to do the above is shown below, because karate.get() gracefully handles a JS or JsonPath evaluation failure and returns null:
And retry until karate.get('response.tokens.length')
Or if you are dealing with XML, you can use the karate.xmlPath() API:
And retry until karate.xmlPath(response, '//result') == 5
And if you really want to use the power of Karate's match syntax, you can use the JS API:
And retry until karate.match(response, { tokens: '##[_ > 0]' }).pass
Note that if you have more complex logic, you can always wrap it into a re-usable function:
* def isValid = function(x){ return karate.match(x, { tokens: '##[_ > 0]' }).pass }
# ...
And retry until isValid(response)
Finally if none of the above works, you can always switch to a custom polling routine: polling.feature
EDIT: also see this answer for an example of how to use karate.filter() instead of JsonPath: https://stackoverflow.com/a/60537602/143475
EDIT: in version 0.9.6 onwards, Karate can do a match in JS, which can simplify some of the above: https://stackoverflow.com/a/50350442/143475