1

While I have not looked at contains any in a while, I do have tests setup, as mentioned in the documentation, https://github.com/karatelabs/karate#match-contains-any, with the original values ... contains any... options in my assertions, but in working on my current flow, I am seeing that I have to place the options first. Was this a recent change?

lines 42 and 43 show the options listed first and passing, while lines 45 and 46 show the method listed in the documentation failing enter image description here

I also tired response versus $ and see the same results enter image description here

Did something change that would affect the order of the match?

Code samples added for troubleshooting as requested:

Feature: Match Testing
  Background: Setup Info
    * url "https://swapi.dev/api/"
        * def namesEnumeration = [ "Luke Skywalker", "Darth Vader", "Beru Whitesun lars", "R5-D4", "Obi-Wan Kenobi" ]
        * configure continueOnStepFailure = true

        # matches defined for the response object - https://github.com/karatelabs/karate#response
        # the three lines below are equivalent
        # Then match response.name == 'Billie'
        # Then match response $.name == 'Billie'
        # Then match $.name == 'Billie' - this example shows the $.name on the left side so unclear on why these tests all fail
            # this also contradicts or is convoluted by the following statement a little lower in the same reposne object
                # There is no need to prefix variable names with $ on the left-hand-side of match statements because it is implied. 
                # You can if you want to, but since only JsonPath (on variables) is allowed here, Karate ignores the $ and looks only at the variable name. 
                # None of the examples in the documentation use the $varName form on the LHS, and this is the recommended best-practice.
                    # Maybe a distinction between the response short-cut and the $variable reference could clarify

  Scenario: Match Testing as variable - method 1 - everything defined as a variable
        # match contains any reference - https://github.com/karatelabs/karate#match-contains-any
    Given path 'people'
    When method GET
    Then status 200
            * def names = $.results[*].name
            * print "Current names from variable are available are: ", names
            * match names contains any namesEnumeration
            * def matchResult = karate.match("names contains any namesEnumeration")
            * print "matchResult is - ", matchResult
            * match namesEnumeration contains any names
            * def matchResult = karate.match("namesEnumeration contains any names")
            * print "matchResult is - ", matchResult

    Scenario: Match Testing with response as defined variable - attempt 2 - Issue scenario 1
        Given path 'people'
        When method GET
      Then status 200
            * def responseObj = $
            * print "Current response from variable are available is: ", responseObj
                * match responseObj.results[*].name contains any namesEnumeration
                * def matchResult = karate.match("responseObj.results[*].name contains any namesEnumeration")
                * print "matchResult is - ", matchResult
                # The following do not work due to the RH side containing "[*]"
                * match namesEnumeration contains any responseObj.results[*].name
                * def matchResult = karate.match("namesEnumeration contains any responseObj.results[*].name")
                * print "matchResult is - ", matchResult

    Scenario: Match Testing with response defined in karate.jsonPath and karate.get functions - attempt 3
            # methods implemented per https://stackoverflow.com/questions/71749751/karate-cant-print-values-from-the-response-array-of-json-objects
            # unsure why we would need to use karate.jsonPath if the response value is already pure jsonPath
            # As a short-cut, when running JsonPath expressions - $ represents the response. This has the advantage that you can use pure JsonPath and be more concise.     
        Given path 'people'
        When method GET
      Then status 200
            * print karate.jsonPath(response, '$.results[*].name')
                    * match karate.jsonPath(response, '$.results[*].name') contains any namesEnumeration
                    * def matchResult = karate.match("karate.jsonPath(response, '$.results[*].name') contains any namesEnumeration")
                    * print "matchResult is - ", matchResult
                    * match namesEnumeration contains any karate.jsonPath(response, '$.results[*].name')
                    * def matchResult = karate.match("namesEnumeration contains any karate.jsonPath(response, '$.results[*].name')")
                    * print "matchResult is - ", matchResult
                * print karate.get('$.results[*].name')
                    * match karate.get('$.results[*].name') contains any namesEnumeration
                    * def matchResult = karate.match("karate.get('$.results[*].name') contains any namesEnumeration")
                    * print "matchResult is - ", matchResult
                    * match namesEnumeration contains any karate.get('$.results[*].name')
                    * def matchResult = karate.match("namesEnumeration contains any karate.get('$.results[*].name')")
                    * print "matchResult is - ", matchResult

    Scenario: Match Testing with built in JSON response variable - attempt 4 - Issue scenario 2
            Given path 'people'
        When method GET
      Then status 200
                # Based on your comment here - https://stackoverflow.com/questions/62869540/printing-database-query-response-as-json-array-list-in-karate
                    # when you see a * or .. it is JsonPath
                        # This explains why the following line does not work since it is not a js object
            # * print "Current names from response are available are: ", response.results[*].name
            * match $.results[*].name contains any [ "Luke Skywalker", "Darth Vader", "Beru Whitesun lars", "R5-D4", "Obi-Wan Kenobi" ]
            * def matchResult = karate.match("$.results[*].name contains any namesEnumeration")
            * print "matchResult is - ", matchResult
            * match namesEnumeration contains any $.results[*].name
            * def matchResult = karate.match("namesEnumeration contains any $.results[*].name")
            * print "matchResult is - ", matchResult

            * match $.results[?(@.height == "172")].name contains any [ "Luke Skywalker", "Darth Vader", "Beru Whitesun lars", "R5-D4", "Obi-Wan Kenobi" ]
            # * def matchResult = karate.match("$.results[?(@.height == "172")].name contains any namesEnumeration")
            # * print "matchResult is - ", matchResult
            # had to declare as variable because placing the jsonPath with a condition, in the LH side of the match checks results in error that stops further evaluations
            * def jsonPart = $.results[?(@.height == "172")].name
            * print "jsonPart is - ", jsonPart
            * match jsonPart contains any [ "Luke Skywalker", "Darth Vader", "Beru Whitesun lars", "R5-D4", "Obi-Wan Kenobi" ]
            * def matchResult = karate.match("jsonPart contains any namesEnumeration")
            * print "matchResult is - ", matchResult
            * match namesEnumeration contains any $.results[?(@.height == '172')].name
            * def matchResult = karate.match("namesEnumeration contains any $.results[?(@.height == '172')].name")
            * print "matchResult is - ", matchResult

        Scenario: Match Testing with built in JSON response variable - attempt 5 - Issue scenario 3

            # example of match with response on the left side - https://stackoverflow.com/questions/73530906/karate-test-framework-how-to-check-presence-of-parameter-in-response/73545783#73545783
            Given path 'people/1'
        When method GET
      Then status 200
            * print "Current response name is: ", response.name
            * match response.name == [ "Luke Skywalker", "Darth Vader", "Beru Whitesun lars", "R5-D4", "Obi-Wan Kenobi" ]           
            * match response.name contains [ "Luke Skywalker", "Darth Vader", "Beru Whitesun lars", "R5-D4", "Obi-Wan Kenobi" ]
            * match response.name contains any [ "Luke Skywalker", "Darth Vader", "Beru Whitesun lars", "R5-D4", "Obi-Wan Kenobi" ]



            ########################
            # Summary
            ########################
            
            # since actual is typically on the left, and expected on the right, per documentation, changing the actual to the RH seems
            # a little confusing when other review the scenarios and assertions.
                # something like the following might be a solution to eliminate the confusion as this topic appears to have come up before
            # * match response.name isIncludeIn [ "Luke Skywalker", "Darth Vader", "Beru Whitesun lars", "R5-D4", "Obi-Wan Kenobi" ]
            # * match response.name isPartOf [ "Luke Skywalker", "Darth Vader", "Beru Whitesun lars", "R5-D4", "Obi-Wan Kenobi" ]
            # * match response.name isListedIn [ "Luke Skywalker", "Darth Vader", "Beru Whitesun lars", "R5-D4", "Obi-Wan Kenobi" ]
            
mike
  • 383
  • 1
  • 12
  • I don't the documentation ever recommends using `karate.match()` or referring to `$` on the right-hand-side of a match, which I think will not work as you expect. I request that you edit your question to simplify the example, and use variables only if needed, for e.g. `* def foo = 2` and then `* match ([1, 2]) contains foo`, please note that images are not encouraged on stack-overflow, since it is impossible to try your example locally: https://stackoverflow.com/help/how-to-ask – Peter Thomas Aug 25 '23 at 10:25
  • I don't think I said that the documentation recommended using karate.match, so unsure what you mean by that. – mike Aug 25 '23 at 21:39
  • Typically, most say a picture is worth a thousand words, but in this case, I guess not. The pictures were to show the results for the $`response` built in variable (https://github.com/karatelabs/karate#response) not working as a normal variable, and that the example noted in the link (https://github.com/karatelabs/karate#match-contains-any) shows the value being tested (in this case the response) and possible values or enumerations, on the right, not left as you noted. – mike Aug 25 '23 at 21:39
  • I have added an example scenario that goes thru the differences so hopefully these few words make up for the thousand the picture did not appear to convey. However, it appears as though the detailed setup in the documentation (actual -> condition -> expected) is not always the case as shown, nor is jsonpath always allowed as a condition for match – mike Aug 25 '23 at 21:40
  • the example you have provided is too complicated - refer stack overflow guidelines on a minimum example: https://stackoverflow.com/help/minimal-reproducible-example - I will see if I can get around to it sometime - but in the meantime, lets hope someone else from the community can answer – Peter Thomas Aug 26 '23 at 03:11
  • too few words to too complicated...funny – mike Aug 26 '23 at 23:21
  • all I'm requesting is an example thats max 4 lines long to demonstrate the issue and nothing else. is that too much to ask ? – Peter Thomas Aug 27 '23 at 05:26
  • The summary of the issue is noted in the last 5 lines of the code section. The issue is that match details that actual -> expected, but if there is a single value compared to an array, the values have to be expected -> actual. This makes code reviews a little difficult since there is no documented format is not followed and becomes hard to follow with the flip flop of the actual and expected values based on match being made. I also offered a solution to keep the actual on the LH which is also mentioned in the code portion. – mike Aug 28 '23 at 14:59

1 Answers1

0

If the issue is that Karate appears to be missing the reverse of a contains matcher, the criticism is valid. This is a potential feature request. My personal vote is to use within as a keyword. For example:

* match 'foo' within ['a', 'foo', 'c']

Most teams are happy with contains. We welcome a PR to add this, but it is not a priority.

Added feature request to track: https://github.com/karatelabs/karate/issues/2388

Peter Thomas
  • 54,465
  • 21
  • 84
  • 248
  • This is also uncovered when trying to validate a schema using a list as shown in this error `$.part2 | match each failed at index 0 (LIST:MAP) [{"status":"CONNECTED"}] {"status":"#(^*enumList.ConnectivityStatus)"} $.part2[0] | not equal | match failed for name: 'status' (MAP:MAP) {"status":"CONNECTED"} {"status":"#(^*enumList.ConnectivityStatus)"} $.part2[0].status | data types don't match (STRING:LIST) 'CONNECTED' ["CONNECTED","NOT_CONNECTED","UNKNOWN","ERROR"]` – mike Aug 31 '23 at 21:59