1

I am using karate 1.1.0 version. I need to create a mock service where an object is optional. When I create a service like this

Feature: Karate netty - testing for optional. The request payload may have either benefiaciary.cardInfo object or beneficiary.cardTokenInfo object
Ex: "beneficiary":{
          "cardInfo":{
               "number": "12345" 
               }
          }   
OR 
    "beneficiary":{
         "cardTokenInfo":{
               "token": "98765"
             }
    }

Background:
 * def happyPathResponse_json = {status: 'Payment accepted'}
 * def invalidResponse_json = {status: 'Invalid request'}

## Happy path if cardNumber is passed
Scenario: pathMatches('/mock/payment/v5')
         && request.beneficiary.cardInfo.number == '12345'

* def response = happyPathResponse_json
* def responseStatus = 201
* def responseHeaders = {'Content-Type': 'application/json'}


## Happy path if card token is passed 
Scenario: pathMatches('/mock/payment/v5')
         && request.beneficiary.cardTokenInfo.number == '98765'

* def response = happyPathResponse_json 
* def responseStatsus = 201
* def responseHeaders = {'Content-Type':'application/json'}


## Catch all scenario if nothing matches
Scenario: pathMatches('/mock/payment/v5')
* def response = invalidRespose_json
* def responseStatus = 201
* def responseHeaders = {'Content-Type': 'application/json'}   

The code works when I pass the request payload as below

{
  "beneficiary:{
       "cardInfo":{
             "number": "12345"
        }
  }
}

However when I pass the payload as below

{
  "beneficiary": {
      "cardTokenInfo":{
           "token": "98765"
       }
    }
}

The karate netty server throws error as

Cannot read property "number" from undefined

This is expected, because it is not able to go beyond the first scenario, where it expects that "cardInfo" object will be passed. To solve this issue I am trying to use schema match to check that

when beneficiary.cardInfo == '#present' then scenario should match.

The schema match works BUT not in case of netty/mock server. This is what I tried

Scenario: pathMatches('/mock/payment/v5')
             && request.beneficiary.cardInfo == '#present' 
             && request.beneficiary.cardInfo.number == '12345'
   * def response = happyPathResponse_json
   * def responseStatus = 201
   * def responseHeaders = {'Content-Type': 'application/json'}

The schema match is coming as false with karate netty/mock but it is actually true when I test it with karate test.

What am I missing here? Does schema match not work with karate netty? If not then what is the alternative. I don't want to use

"* if() karate.abort()" as it will abort the feature and hence next set of scenarios will not be executed.

UPDATE: I found a work around using "bodyPath". In one of questions answered by @PeterThomas , he mentioned that in with "pathMatches", the condition code is treated as javascript and provided a workaround for XML but it worked for json as well.

When I replace

request.beneficiary.cardInfo.number == '12345'

With

bodyPath('$.beneficiary.cardInfo.number') == '12345'

I get the scenario working as well but again '#present' is still not working.

SOLUTION: For people who landed on this page looking for a similar solution.Here are two ways:

Option 1: Use bodyPath

bodyPath('$.beneficiary.cardInfo.number') == '12345'

Option 2: As @PeterThomas already confirmed that only JS is supported(see comment below). we can use karate.match to first confirm that a key is present.

pathMatches('/mock/payment/v5') && karate.match("request.beneficiary.cardInfo == '#present'").pass && request.beneficiary.cardInfo.number == '12345'

NOTE You will also find a third solution where you can just use

request.beneficiary.cardInfo.number.contains('12345')

This solution will work BUT if you try and pass a request payload with an unknown field then your code will blow up ex:

"beneficiary":{
          "cardInfo":{
               "someUnknownKey": "12345" 
               }
          }   
Dinesh Arora
  • 2,115
  • 3
  • 24
  • 30
  • short answer, `#present` etc. is karate's `match` speciality. but here in mocks, only JS is supported – Peter Thomas Jun 02 '22 at 02:10
  • @PeterThomas Thanks for SO links. I did see the solution that you mentioned here - https://stackoverflow.com/questions/57457297/karate-mock-how-to-match-against-request-body-content/57463815#57463815 which helped me solve this using bodyPath. I was not aware that I could also use karate.match(). For my use case where I have optional object in the payload, using "String.contains() or String.include()" only solves part of the question. I have posted the reason and the two options from the links you posted. – Dinesh Arora Jun 02 '22 at 04:15
  • I don't understand if you still have a problem or not. please ask a new question if needed and keep it simple – Peter Thomas Jun 02 '22 at 04:35
  • 1
    No. The problem is resolved using either of the two options that I posted. – Dinesh Arora Jun 02 '22 at 05:08
  • ok. also do try `karate.get('request.beneficiary.cardInfo.number') == '12345'` that might be the best option – Peter Thomas Jun 02 '22 at 06:01

0 Answers0