可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I've got this really weird problem.
I want to append two lists into one list, but it seems like Karate does not support this function, so I write a JS function.
function(lists){ var arr = [] for each (var list in lists){ for each (var item in list){ arr.push(item); } } return arr; }
And I write this feature file for testing:
Feature: Scenario: * def appendList = read('../utils/append-list.js') * def arr = [{a: 'a'}, {b: 'b'}, {c: 'c'}] * def arr1 = [{a: 'a'}, {b: 'b'}, {c: 'c'}] * def arr2 = appendList([arr, arr1]) * print 'arr2', arr2 * def xx = { aa: '#(arr2)' } * print 'xx', xx * copy yy = xx * print 'yy', yy * match xx == yy
Here's the log:
I don't understand why sometimes the array is the array, sometimes it becomes object?
回答1:
You can try to convert the return data in JavaScript function to JSON. Below is explain what happening in karate as my understand:
* def appendList = read('../utils/append-list.js') * def arr = [{a: 'a'}, {b: 'b'}, {c: 'c'}] * def arr1 = [{a: 'a'}, {b: 'b'}, {c: 'c'}] * def arr2 = appendList([arr, arr1]) # return JS[] variable type instead of JSON object * print 'arr2', arr2 * def xx = { aa: '#(arr2)' } * print 'xx', xx * copy yy = xx * print 'yy', yy * match xx == yy
Below is how to fix it:
* def appendList = read('append-list.js') * json arr = [{a: 'a'}, {b: 'b'}, {c: 'c'}] * json arr1 = [{a: 'a'}, {b: 'b'}, {c: 'c'}] * json arr2 = appendList([arr, arr1]) # convert to JSON * print 'arr2', arr2 * json xx = { aa: '#(arr2)' } * print 'xx', xx * copy yy = xx * print 'yy', yy * match xx == yy
Log Info:
20:37:02.034 [main] WARN com.intuit.karate - skipping bootstrap configuration: could not find or read file: karate-config.js, prefix: CLASSPATH 20:37:02.139 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 20:37:02.142 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 20:37:02.149 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 20:37:02.149 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 20:37:02.168 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 20:37:02.169 [main] INFO com.intuit.karate - [print] arr2 [ { "a": "a" }, { "b": "b" }, { "c": "c" }, { "a": "a" }, { "b": "b" }, { "c": "c" } ] 20:37:02.173 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 20:37:02.177 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 20:37:02.178 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $['aa'] 20:37:02.179 [main] DEBUG com.jayway.jsonpath.internal.JsonContext - Set path $['aa'] new value [{a=a}, {b=b}, {c=c}, {a=a}, {b=b}, {c=c}] 20:37:02.182 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 20:37:02.183 [main] INFO com.intuit.karate - [print] xx { "aa": [ { "a": "a" }, { "b": "b" }, { "c": "c" }, { "a": "a" }, { "b": "b" }, { "c": "c" } ] } 20:37:02.188 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 20:37:02.188 [main] INFO com.intuit.karate - [print] yy { "aa": [ { "a": "a" }, { "b": "b" }, { "c": "c" }, { "a": "a" }, { "b": "b" }, { "c": "c" } ] } 20:37:02.189 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 20:37:02.189 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $ 1 Scenarios ([32m1 passed[0m) 10 Steps ([32m10 passed[0m) 0m0.680s html report: (paste into browser to view)
Result
回答2:
Yes, by default, JSON is internally converted to Java lists which can be confusing. Best practice is to use 'Java style' wherever possible. And when iterating, use for-loops with indexes. For example, try these:
* def first = [{a: 1}, {b: 2}] * def second = [{c: 3}, {d: 4}] * eval first.addAll(second) * print first
This has the same effect as the above, but is more convoluted:
* def append = function(f, s){ for (var i = 0; i < s.length; i++) { f.add(s[i]) }; return f } * def first = [{a: 1}, {b: 2}] * def second = [{c: 3}, {d: 4}] * def result = append(first, second) * print result
Note that we use the Java List.add() and List.addAll() methods, not the JS push. You can of course write your custom function that does this behind the scenes.
BTW the next version of Karate will introduce karate.forEach and even map and filter operations to make iterating easier. Maybe we need a karate.append() and karate.merge() (for merging 2 JSON objects). Feel free to raise a feature request.