Schema validation of empty array for nested structure verification - karate

I am working on a POC with Karate framework (latest version 0.9.6) and I came across with the following:
* match each response.bar contains { id:"#uuid ? _ != ''", name: "#notnull", foo: "#[] #object"}
I noticed that, when foo is an empty array, it does not fail the step.
Is it possible to add a length verification on the above step to fail if the array is empty?
Thanks in advance.

Yes, read the docs: https://github.com/intuit/karate#schema-validation
* match each response.bar contains { id:"#uuid ? _ != ''", name: "#notnull", foo: "#[_ > 0] #object"}

Related

How to use mapFieldType with gdal.VectorTranslate

I'm trying to export a postgresql database into a .gpkg file, but some of my fields are lists, and ogr2ogr send me the message :
Warning 1: The output driver does not natively support StringList type for field my_field_name. Misconversion can happen. -mapFieldType can be used to control field type conversion.
But, as in the documentation, -mapFieldType is not a -lco, i don't find how to use it with the python version of gdal.VectorTranslate
here ma config :
gdal_conn = gdal.OpenEx(f"PG:service={my_pgsql_service}", gdal.OF_VECTOR)
gdal.VectorTranslate("path_to_my_file.gpkg"), gdal_conn,
SQLStatement=my_sql_query,
layerName=my_mayer_name,
format="GPKG",
accessMode='append',
)
so i've tried to add it in the -lco :
layerCreationOptions=["-mapFieldType StringList=String"]
but it didn't work
so i diged into the code of gdal, added a field mapFieldType=None into the VectorTranslateOptions function, and added into its code the following lines :
if mapFieldType is not None:
mapField_str = ''
i = 0
for k, v in mapFieldType.items():
i += 1
mapField_str += f"{k}={v}" if i == len(mapFieldType) else f"{k}={v},"
new_options += ['-mapFieldType', mapField_str]
And it worked, but is there an other way ?
And if not, where can i propose this feature ?
Thank you for your help

Karate: Unable to move schema definition out of feature file

I'm able to successfully run the Feature/scenario, When I define the schema inside my feature file .
Here is a simplified example of the schema.
Background:
...
...
* def accountSchema = { id: '#number? _ >= 0', prop1: '#number? _ >= 0', prop2: '#string', prop3: '#string', optionaProp: '##string' }
* def userAccountsSchema = ({ entitledAccounts: '#[] accountSchema', prop5: '#number' , prop6: '##string'})
And here is how I'm validating
Scenario:
...
...
When method GET
Then status 200
* print userAccountsSchema
And match response == userAccountsSchema
But the schema I posted here is simplified to ask this question, the real schema is far more complex.
So for clarity purpose, I decided to put schema in a separate js file response-schemas.js under the same folder as the feature file.
Here is the simplified content of response-schemas.js file.
function schema () {
let accountSchema = {
id: '#number? _ >= 0',
prop1: '#number? _ >= 0',
prop2: '#string',
prop3: '#string',
optionaProp: '##string',
}'
return {
accounts: `#[] ${accountSchema}` ,
prop5: '#string',
prop6: '#string',
};
}
now if I replace the 2 lines I mentioned at the beginning of the question under Background:, with below line
* def userAccountsSchema = call read('response-schemas.js')
I get this error
And match response == schemas
SyntaxError: Unnamed:1:8 Expected comma but found ident
[object Object]
^
I believe, I understand the problem, is this line
accounts: `#[] ${accountSchema}` ,
but unable to figure out the solution. If I tried to change the accountSchema variable in response-schemas.js to use multiline string then I get error in read step in Background
the whole idea to have a dedicated js file for schema is to keep it readable (by using multiple lines, preferably objects not a long string)
The main problem is this part:
accounts: `#[] ${accountSchema}`
Where you are trying to stuff a JSON into the Karate "fuzzy" expression. This is just not supported. Note that the Karate way of defining things like #(foo) and #[] bar has nothing to do with JavaScript, so I recommend not mixing these.
I know there is a desire to achieve the match in just one-line and somehow get one monstrous schema to do everything and I very strongly discourage this. Split your assertions into multiple lines. Split your response into smaller chunks of JSON if needed. There is nothing wrong with that. This also makes the life much easier of people who come along later who have to maintain your test.
For ideas see this answer: https://stackoverflow.com/a/61252709/143475
Other answers: https://stackoverflow.com/search?q=%5Bkarate%5D+array+schema
Tip: you can keep your schema "chunks" as JSON files if needed.

g1ant: jsonpath with method length() not implemented

I have problem to get size items of array. Function of jsonPath "length()" not implemented in g1ant, because throwing exception "Array index expected".
Below is sample in g1ant script for test.
addon core version 4.103.0.0
addon language version 4.104.0.0
♥jsonImage = ⟦json⟧‴{ "book" : [ { "name" : "Bambi"} , { "name" : "Cinderella" } ] }‴
♥aaa = ♥jsonImage⟦$.book.length()⟧
dialog ♥aaa
Are there other solutions related to the length of the array?
It's not possible to get the number of json array elements in the way that you are trying. G1ANT is using Newtonsoft.Json library for selecting json tokens where they don't allow expressions like .length() as you can read here.
Here's how you can workaround this issue.
♥jsonImage = ⟦json⟧‴{ "book" : [ { "name" : "Bambi"} , { "name" : "Cinderella" } ] }‴
♥jsonArrLength = 0
♥hasExceptionOccurred = false
while ⊂!♥hasExceptionOccurred⊃
try errorcall NoMoreElements
♥test = ♥jsonImage⟦book[♥jsonArrLength]⟧
♥jsonArrLength = ♥jsonArrLength + 1
end try
end while
dialog ♥jsonArrLength
procedure NoMoreElements
♥hasExceptionOccurred = true
end procedure

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

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.

How to do conditional variables definition on Karate

I had written karate tests for one environment only (staging). Since the tests are successful on capturing bugs (thanks a lot Karate and Intuit team!), there is now request to run the tests on production.
Our tests are graphql-based where most of the requests are query. I wonder if it is possible for us to switch variables based on karate.env we passed on terminal?
Most of our requests look like this:
And def variables = {objectID:"1234566", cursor:"1", cursorType:PAGE, size:'10', objectType:USER}
And request { query: '#(query)', variables: '#(variables)' }
When method POST
Then status 200
I had tried reading the conditional-logic page on github page but haven't yet found a success.
What I tried so far is:
* if (karate.env == 'staging') * def variables = {objectID:"1234566", cursor:"1", cursorType:PAGE, size:'10', objectType:USER}
But to no success.
Any help will be greatly appreciated. Thanks a lot!
We keep our graphql queries & variables in separate json files, but, we're attempting to solve the same issue. Based on what Peter wrote I came up with this, though it will likely get cleaned up before deployment.
Given def query = read('graphqlQuery.graphql')
And def prodVariable = read('prod-variables.json')
And def stageVariable = read('stage-variables.json')
And def variables = karate.env == 'prod' ? prodV : stageV
And path 'api/' + 'graphql'
And request { query: '#(query)', variables: '#(variables)' }
When method post
Then status 200
This should be easy:
* def variables = karate.env == 'staging' ? { objectID: "1234566", cursor: "1", cursorType: 'PAGE', size: '10', objectType: 'USER' } : { }
Here is another hint:
* def data = { staging: { foo: 'bar }, production: { foo: 'baz' } }
* def variables = data[karate.env]
EDIT: also see this explanation: https://stackoverflow.com/a/59162760/143475