karate

Assertion for json array in Karate using match contains


I am seeing a potential issue with match contains assertion. Below is the scenario with assertion statements

Scenario: 

 * def statusEnum = ["ACTIVE", "PENDING"] 
 * def actualStatus = ["PENDING", "PENDING", "PENDING"] 

 * match actualStatus contains statusEnum // actual array does not contain expected item - ACTIVE
 * match statusEnum contains actualStatus // FAILS actual array length is less than expected - 2:3

The first assertion statement works as expected and fails with an error that the array does not contain ACTIVE.

The 2nd match statement fails because of array size. As karate documentation states size and order of the actual array does not matter, I was expecting this statement to pass.

Is this a bug in karate?

Karate documentation link- https://github.com/karatelabs/karate?tab=readme-ov-file#json-arrays

Note:- The array actualStatus is from JSON response. So its size, values and order will vary.


Solution

  • After reading your original post and the comments in @cyrilgeorge153's answer, I think what you are trying to achieve is the following * match each actualStatus == '#? statusEnum.includes(_)' . This solution also allows you to add more elements to your ENUM without having to update the validation expression.

    Scenario: Validate elements against ENUM
    * def statusEnum = ["ACTIVE", "PENDING"]
    * def actualStatus = ["PENDING", "PENDING", "PENDING"]
    * match each actualStatus == '#? statusEnum.includes(_)'
    

    here is what each part of that syntax means

    The following line tells karate to iterate over each element in actualStatus and assert that each element meets the condition on the right hand side

    * match each actualStatus ==
    

    this line

    '#? statusEnum.includes(_)'
    

    is a bit more contrived where

    #? idicates that a custom JS expression follows and tells karate to evaluate it as JS

    statusEnum.includes(_) This is the actual condition being checked. The includes method checks if the array statusEnum contains the current element being iterated over from actualStatus

    _ the underscore inside of the parenthesis acts as a placeholder for the current element in the array being iterated over and checked.

    Another way to think about this validation is by writing it like so

    * match each actualStatus == '#? _ == "ACTIVE" || _ == "PENDING"'
    

    The shorthand expessions for #? & the _ stay the same but validation against the enum is split out and statically defined to achieve the same results. The only drawback to this is if your ENUM grows you will have to keep adding the values to every instance of this validation so I suggest going with the first solution in my answer.