Search code examples
javascriptarraysjsonpathkarate

Array sorting and matching in Karate using JsonPath and karate.eval


I am trying to validate whether a collection being returned is in alphabetical order.

There are two parts to this collection though, as the first six are sorted separately from the rest. e.g.

  • Bob
  • Edith
  • Egbert
  • Nial
  • Simone
  • Sasha
  • Aaron
  • Bertha
  • Charlie
  • etc.

I can hard code the first six using JsonPath and doing a simple match, but I am uncertain how to match the rest (there are lots, and the dataset can change).

This is my feature file:

Feature: Array should be sorted alphabetically, with the first important 6 sorted separately

  Background:
    * call read('common-config.feature')

  @wip
  Scenario: I request brand options by region
    Given url baseUrl
    And path '/importantEmployees'
    When method GET
    Then status 200

    # match first six
    And def importantSix = $..employees[0:6]
    And def importantSixNames = get importantSix[*].name
    And match importantSixNames == [ 'Bob', 'Edith', 'Egbert', 'Nial', 'Simone', 'Sasha' ]

    # match the rest to a sorted array
    And def otherPeople = $..employees[6:]
    And def otherPeopleNames = get otherPeople[*].name
    And eval
    """
    var sortedOtherPeopleNames = karate.get('otherPeopleNames').sort();
    karate.set('sortedOtherPeopleNames', sortedOtherPeopleNames);
    """
    And match otherPeopleNames == sortedOtherPeopleNames

I've tried following the example of using an eval call, but I can't get it to work.

https://github.com/intuit/karate#eval

EDIT: I have found out how to share variables between the Javascript and Karate Feature file. I need to use karate.get('varName') in the Javascript. The sorting is still an issue though. I've edited the feature file to reflect this.


Solution

  • EDIT: Karate now has a karate.sort() API that is very versatile: https://stackoverflow.com/a/77318045/143475

    First, eval was introduced in 0.7.0 onwards, I apologize since the documentation is being revised. I recommend that you use version 0.7.0.RC4 which is available at the time of this post.

    Great question ! I reckon this is a case where diving into Java makes sense. The good news is that you can do this 'as JS' itself. The code below uses the eval keyword, but if are not in a position to upgrade you should be able to figure out a way to use JS functions as you already know.

    * def ArrayList = Java.type('java.util.ArrayList')
    * def Collections = Java.type('java.util.Collections')
    
    * def json = [{ v: 'C' }, { v: 'b' }, { v: 'A' }]
    * def actual = $json[*].v
    * print actual
    * def list = new ArrayList()
    * eval for(var i = 0; i < actual.length; i++) list.add(actual[i])
    * print list
    * eval Collections.sort(list, java.lang.String.CASE_INSENSITIVE_ORDER)
    * print list
    * match list != actual
    * match list == ['A', 'b', 'C']
    

    And here is the output of the 3 print statements:

    21:59:34.211 [main] INFO  com.intuit.karate - [print] [
      "C",
      "b",
      "A"
    ]
    
    21:59:34.241 [main] INFO  com.intuit.karate - [print] [
      "C",
      "b",
      "A"
    ]
    
    21:59:34.273 [main] INFO  com.intuit.karate - [print] [
      "A",
      "b",
      "C"
    ]