Search code examples
csvkaratedata-driven-tests

Handling empty cells and using null in Examples from a CSV file


The problem involves handling empty cells and using null in 'Examples'.

Our test data is read from CSV files with various combinations, and not all values are always present in the columns (specifically benchmarks to be compared with response values).

The comparison needs to be conditional:

  • If a value is not present in the CSV, the comparison should be skipped.
  • If a value is present, we need to read the response key and perform the comparison.

Solution

  • Yes, when you use a CSV file, it is a little harder to pre-process so that empty values are handled the way you expect. But it is possible, note that all the examples below can be tried locally, just cut and paste them into local / feature files.

    First let us see how to do this in a "normal" Examples block and see the difference later:

    Feature: using nulls and inline json
    
      Scenario Outline:
        Given url 'https://reqres.in/api'
        And path 'register'
        And request { email: '#(email)', password: '#(password)' }
        When method post
        Then status 400
        * print response
        * match response == errorResponse
    
        Examples:
          | email! | password! | errorResponse!                                             |
          | null   | null      | { error: 'Missing email or username' }                     |
          | 'aa'   | 'bb'      | { error: 'Note: Only defined users succeed registration' } |
    

    Note how the column names are suffixed with ! so that things like null are processed correctly instead of the default '' or empty-string. But when you use a CSV as the data-source, you need to do the pre-processing manually. Fortunately this is easy by using a @setup Scenario.

    Here we use a small JavaScript function to convert rows, and then map(). note that in the world of JavaScript, an empty string is considered false. Of course, you can use any custom conversion logic you want. If you need to completely filter out some rows, that's easy as well, just use the JavaScript filter() function.

    Feature: converting empty cells to null from a csv
    
      @setup
      Scenario:
        * def raw = read('examples.csv')
        * def convert = x => x || null
        * def data = raw.map(x => ({ email: convert(x.email), password: convert(x.password), error: x.error }))
    
      Scenario Outline:
        Given url 'https://reqres.in/api'
        And path 'register'
        And request { email: '#(email)', password: '#(password)' }
        When method post
        Then status 400
        * print response
        * match response == { error: '#(error)' }
    
        Examples:
          | karate.setup().data |
    

    For the above example, the contents of examples.csv are the following:

    email,password,error
    ,,Missing email or username
    aa,bb,Note: Only defined users succeed registration
    

    And for completeness, the other way of "looping" in the Karate world is this way:

    Feature: looping over a json array converted from a csv
    
      Scenario:
        * def raw = read('examples.csv')
        * def convert = x => x || null
        * def data = raw.map(x => ({ email: convert(x.email), password: convert(x.password), error: x.error }))
        * call read('@register') data
    
      @ignore @register
      Scenario:
        Given url 'https://reqres.in/api'
        And path 'register'
        And request { email: '#(email)', password: '#(password)' }
        When method post
        Then status 400
        * print response
        * match response == { error: '#(error)' }
    

    Also see: https://stackoverflow.com/a/62449166/143475