Feature: dynamic params using scenario-outline, examples and json see also the file demo/outline/examples.feature Background: * url demoBaseUrl Scenario Outline: using a javascript function to pre-process the search parameters this particular example has been deliberately over-complicated, the next scenario-outline below is simpler * def query = { name: '<name>', country: '<country>', active: '<active>', limit: '<limit>' } # all this function does is to set any empty string value to null, because that is what empty cells in 'Examples' become * def nullify = """ function(o) { for (var key in o) { if (o[key] == '') o[key] = null; } return o; } """ # here we load a java-script function from a re-usable file * def getResponseParam = read('get-response-param.js') * def query = nullify(query) * print query Given path 'search' # the 'params' keyword takes json, and will ignore any key that has a null value And params query When method get Then status 200 And assert getResponseParam('name') == query.name And assert getResponseParam('country') == query.country And assert getResponseParam('active') == query.active And assert getResponseParam('limit') == query.limit # response should NOT contain a key expected to be missing And match response !contains { '<missing>': '#notnull' } Examples: | name | country | active | limit | missing | | foo | IN | true | 1 | | | bar | | | 5 | country | | baz | JP | | | active | | | US | | 3 | name | | | | false | | limit | Scenario Outline: here the parameters are set to null within the 'Examples' table itself # notice how this is different from the above, the quotes come from the 'Examples' section * def query = { name: <name>, country: <country>, active: <active>, limit: <limit> } * print query Given path 'search' And params query When method get Then status 200 # response should NOT contain a key expected to be missing And match response !contains <missing> # observe how strings are enclosed in quotes, and we set null-s here below # and you can get creative by stuffing json into table cells ! Examples: | name | country | active | limit | missing | | 'foo' | 'IN' | true | 1 | {} | | 'bar' | null | null | 5 | { country: '#notnull', active: '#notnull' } | | 'baz' | 'JP' | null | null | { active: '#notnull', limit: '#notnull' } | | null | 'US' | null | 3 | { name: '#notnull', active: '#notnull' } | | null | null | false | null | { name: '#notnull', country: '#notnull', limit: '#notnull' } | Scenario: using a data-driven called feature instead of a scenario outline this and the above example are the two fundamentally different ways of data-driven test 'looping' in Karate * table data | name | country | active | limit | missing | | 'foo' | 'IN' | true | 1 | [] | | 'bar' | | | 5 | ['country', 'active'] | | 'baz' | 'JP' | | | ['active', 'limit'] | | | 'US' | | 3 | ['name', 'active'] | | | | true | | ['name', 'country', 'limit'] | # the assertions in the called feature use some js for the sake of demo # but the next scenario below is far simpler and does not use js at all * def result = call read('search-complex.feature') data Scenario: using the set keyword to build json and nulls are skipped by default this is possibly the simplest form of all the above, avoiding any javascript but does require however - a 'call' to a second feature file # table would have been sufficient below, but here we demo how 'set' is simply a 'transpose' of table * set data | path | 0 | 1 | 2 | 3 | 4 | | name | 'foo' | 'bar' | 'baz' | | | | country | 'IN' | | 'JP' | 'US' | | | active | true | | | | false | | limit | 1 | 5 | | 3 | | # note how you can 'compose' complex JSON by referring to existing JSON chunks, e.g: 'data[0]' * table search | params | expected | missing | | data[0] | { name: '#[1]', country: '#[1]', active: '#[1]', limit: '#[1]' } | {} | | data[1] | { name: ['bar'], limit: ['5'] } | { country: '#notnull', active: '#notnull' } | | data[2] | { name: ['#(data[2].name)'], country: ['#(data[2].country)'] } | { active: '#notnull', limit: '#notnull' } | | data[3] | { country: '#[1]', limit: '#[1]' } | { name: '#notnull', active: '#notnull' } | | data[4] | { active: '#[1]' } | { name: '#notnull', country: '#notnull', limit: '#notnull' } | * def result = call read('search-simple.feature') search Scenario: params json with embedded expressions * def data = { one: 'one', two: 'two' } Given path 'search' # using enclosed javascript instead of an embedded expression for convenience And params ({ name: data.one, country: data.two }) When method get Then status 200 And match response == { name: ['one'], country: ['two'] } Scenario: test that multi-params work as expected Given path 'search' And param foo = ['bar', 'baz'] When method get Then status 200 And match response == { foo: ['bar', 'baz'] } Given path 'search' And params { foo: ['bar', 'baz'] } When method get Then status 200 And match response == { foo: ['bar', 'baz'] } Given path 'search' And param foo = 'bar,baz' When method get Then status 200 And match response == { foo: ['bar,baz'] } Given path 'search' And params { foo: 'bar,baz' } When method get Then status 200 And match response == { foo: ['bar,baz'] }