Karate: Match contains does exact matching 0.9.6.RC3+ for nested json and nested list ordering as opposed to 0.9.5

Created on 12 Jul 2020  路  11Comments  路  Source: intuit/karate

The following are passing on 0.9.5:

Feature: match_contains

    Scenario: Deeply nested contains used to work in 0.9.5 but in 0.9.6 seems to require all fields to be present
      Given def message =
      """
          {
              "correlationId": "101",
              "text": "Hello to everyone",
              "data": {
                  "deeply": {
                      "nested": "no",
                      "id": "1010"
                  }
              }
          }
          """
      Then match message contains { text: "Hello to everyone" }
      Then match message contains { data: { deeply: { nested: "no" } } } }



  Scenario: Match contains for sublist works even if simple list elements are reversed
    Given def message =
      """
      {
          order_id: 5,
          products: [100,101]
      }
      """
    Then match message contains { order_id: 5, products: [101, 100] }


  Scenario: Match contains for sublist works even if complex list elements are reversed
    Given def message =
      """
      {
          order_id: 5,
          products: [
            { product_id: 100, name: "bicycle" },
            { product_id: 101, name: "car" }
          ]
      }
      """
    Then match message contains
      """
      {
          order_id: 5,
          products: [
            { product_id: 101, name: "car" },
            { product_id: 100, name: "bicycle" }
          ]
      }
      """

0.9.6.RC3 + Latest develop (as of an hour ago or so)

Scenario 1:

match_contains.feature:22 - path: $.data.deeply, actual: {nested=no, id=1010}, expected: {nested=no}, reason: actual value has 1 more key(s) than expected: {id=1010}

Scenario 2:

21:15:30.173 [ForkJoinPool-1-worker-3] ERROR com.intuit.karate - assertion failed: path: $.products[0], actual: 100, expected: 101, reason: [path: $.products[0], actual: 100, expected: 101, reason: not equal (Integer)]

match_contains.feature:29 - path: $.products[0], actual: 100, expected: 101, reason: [path: $.products[0], actual: 100, expected: 101, reason: not equal (Integer)]

Scenario 3 equivalent of 2.

I have reproduced this here: https://github.com/KostasKgr/karate-issues/blob/match_contains_issues/src/test/java/examples/match_contains.feature

The above is with 0.9.5, tried with 0.9.6.RC3 and 2.0.0 which i hopefully built correctly from latest develop.

documentation fixed

Most helpful comment

@KostasKgr the rhs comes into the picture for the "docstring" variation. it will be null as a capturing group but will be set from karate internals (the stuff between the triple-quotes), I think I'll leave as it is now

All 11 comments

okay - we have a new contains deep that needs to be documented better thanks to @abhi-rao in #1080 - will keep this ticket open to fix the docs

Then match message contains deep { data: { deeply: { nested: "no" } } } }

can you confirm the rest is also ok ?

Thanks for the prompt response @ptrthomas!

Scenarios 1 & 2 work with contains deep. Scenario 3 seems to match two step definitions and fails, tested on 0.9.6.RC3 and latest (?) develop ( 2f8765b32ade37f8da2ef8b201d890fc7818874c )

I have updated the repo above with the contains deep version.

  Scenario: Match contains for sublist works even if complex list elements are reversed
    Given def message =
      """
      {
          order_id: 5,
          products: [
            { product_id: 100, name: "bicycle" },
            { product_id: 101, name: "car" }
          ]
      }
      """
    Then match message contains deep
      """
      {
          order_id: 5,
          products: [
            { product_id: 101, name: "car" },
            { product_id: 100, name: "bicycle" }
          ]
      }
      """
match_contains.feature:43 - more than one step-definition method matched: match message contains deep - [public void com.intuit.karate.StepActions.match(java.lang.String,java.lang.String,java.lang.String) [message , contains,  deep], public void com.intuit.karate.StepActions.matchDocstring(java.lang.String,java.lang.String,java.lang.String) [message contains , deep]]

Was checking out the 2 steps that match, made me wonder why scenario 2 works, if "message contains" ends up being the expression, but it seems the whole string is concatenated again later.

    @Override
    @When("^match (.+)(=|contains|any|only|deep)( .+)$")
    public void match(String expression, String operators, String rhs) {
        MatchStep m = new MatchStep(expression + operators + rhs);
        context.match(m.type, m.name, m.path, m.expected);
    }

image

@KostasKgr I tried a little bit and am giving up. you can do this in 2 steps:

* def expected =
"""
{
    order_id: 5,
    products: [
      { product_id: 101, name: "car" },
      { product_id: 100, name: "bicycle" }
    ]
}
"""
* match message contains deep expected

the regexes need tweaking, maybe you can figure :)

image

Yeah, was contemplating how to change the regexes, didnt have a good idea yet, because "contains" is a subset of "contains deep"

Are you considering tracking the docstring version of match in a separate issue, and have this one for the deep documentation?

Do "contains any" and "contains only" work with docstring? I suppose they have the same problem? Was it always like this or regressed in 0.9.6?

Cheers

@KostasKgr good news and thanks for the discussion - an alternative simpler approach clicked in my head. feels good to have solved it finally ! yes this was always like this :) very rarely needed though

Oh nice!

I was playing around with regex before i read your last response, ended up with the following for the normal ones:

^match (.*? )(contains deep|contains any|contains all|contains|==)( .*)$

If you remove the dollar it probably works to unify them in one step as you have it in your last commit

image


I tried out the one you committed earlier, not sure op2 and rhs is what you would expect, since you have only 3 capturing groups, so rhs will probably always be null.

image

If all you do is concatenate it and pass it to matchstep then it doesnt really matter matching them exactly though

It also matches the following, not sure if you want those either, I would have to check the documentation again:

match mpla deep
match mpla any
match mpla all
match mpla =

But it is interesting to have op2, i hadnt thought of that. Though since any is not valid and only contains any is valid it might work better as one operator. Not sure if java parses regex the same way as https://regex101.com/ , but when i put contains at the end of the alternative match it worked as I wanted it to.

Cheers

@KostasKgr the rhs comes into the picture for the "docstring" variation. it will be null as a capturing group but will be set from karate internals (the stuff between the triple-quotes), I think I'll leave as it is now

Oh! didn't know that rhs works like that! Awesome! :) I will give the latest commit a spin :)

All three scenarios I had posted pass with latest develop, cheers

0.9.6 released

Was this page helpful?
0 / 5 - 0 ratings