forked from karatelabs/karate
-
Notifications
You must be signed in to change notification settings - Fork 0
/
type-conv.feature
227 lines (197 loc) · 7.26 KB
/
type-conv.feature
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
Feature: convert between json, xml and string
Scenario: multi-line text
# although the value starts with '{' it is not parsed as JSON, and line-feeds are retained
* text query =
"""
{
hero(name: "Luke Skywalker") {
height
mass
}
}
"""
* match query == read('type-conv-query.txt').replaceAll("\r", "")
Scenario: multi-line text with the starting line indented
* text query =
"""
{
abcd
efgh
}
"""
* match query == read('type-conv-query2.txt').replaceAll("\r", "")
Scenario Outline: multi-line text in a scenario outline
* text query =
"""
{
hero(name: "<name>") {
height
mass
}
}
"""
* match query == read('type-conv-query.txt').replaceAll("\r", "")
Examples:
| name |
| Luke Skywalker |
Scenario: multi-line string expression
# this is normally never required since you can use replace
* def name = 'Luke Skywalker'
* string expectedOnUnix = '{\n hero(name: "' + name + '") {\n height\n mass\n }\n}'
* string expectedOnWindows = '{\r\n hero(name: "' + name + '") {\r\n height\r\n mass\r\n }\r\n}'
* def actual = read('type-conv-query.txt')
* assert actual === expectedOnUnix || actual === expectedOnWindows
Scenario: string to json
# this would be of type string (not JSON)
* def strVar = '{ "foo": "bar" }'
* json jsonVar = strVar
* match jsonVar == { foo: 'bar' }
Scenario: json to string
* def jsonVar = { foo: 'bar' }
* string strVar = jsonVar
* assert strVar == '{"foo":"bar"}'
Scenario: string to xml
* def strVar = '<root><foo>bar</foo></root>'
* xml xmlVar = strVar
* match xmlVar == <root><foo>bar</foo></root>
Scenario: xml to string (improved in 1.0)
* def xmlVar = <root><foo>bar</foo></root>
# the parentheses forces evaluation as javascript and converts the xml to a map
* string strVar = (xmlVar)
# karate auto detects xml when needed
* match strVar == '<root><foo>bar</foo></root>'
Scenario: xml to string
* def xmlVar = <root><foo>bar</foo></root>
# note that the keyword here is 'xmlstring' not 'string'
* xmlstring strVar = xmlVar
* match strVar == '<root><foo>bar</foo></root>'
Scenario: xml to json
* def xmlVar = <root><foo>bar</foo></root>
* json jsonVar = xmlVar
* match jsonVar == { root: { foo: 'bar' } }
Scenario: json to xml
* def jsonVar = { root: { foo: 'bar' } }
* xml xmlVar = jsonVar
* match xmlVar == <root><foo>bar</foo></root>
Scenario: xml with attributes
* def xmlVar = <root><foo fizz="buzz">bar</foo></root>
* json jsonVar = xmlVar
# it ain't pretty but this is how karate converts xml to a map-like object internally for parity with json
* match jsonVar == { root: { foo: { _ : 'bar', @: { fizz: 'buzz' }}}}
# which means that json can be used instead of xpath
* match jsonVar $.root.foo._ == 'bar'
* match jsonVar $.root.foo.@ == { fizz: 'buzz' }
* match jsonVar $.root.foo.@.fizz == 'buzz'
* match jsonVar $..foo.@.fizz == ['buzz']
* match jsonVar $..@.fizz contains 'buzz'
* match jsonVar $..foo.@ contains { fizz: 'buzz' }
Scenario: xml with namespaces
* def xmlVar = <ns1:root xmlns:ns1="http://foo.com" xmlns:ns2="http://bar.com"><ns2:foo fizz="buzz" ping="pong">bar</ns2:foo></ns1:root>
* json jsonVar = xmlVar
* match jsonVar ==
"""
{
"ns1:root": {
"@": { "xmlns:ns1": "http://foo.com", "xmlns:ns2": "http://bar.com" },
"_": {
"ns2:foo": {
"_": "bar",
"@": { "fizz": "buzz", "ping": "pong" }
}
}
}
}
"""
* match jsonVar $.ns1:root..ns2:foo.@ == [{ fizz: 'buzz', ping: 'pong' }]
* match jsonVar $..ns2:foo.@ == [{ fizz: 'buzz', ping: 'pong' }]
* match jsonVar $..ns2:foo.@ contains { fizz: 'buzz', ping: 'pong' }
* match jsonVar $..ns2:foo.@ contains only { fizz: 'buzz', ping: 'pong' }
* match each jsonVar $..ns2:foo.@ contains { ping: 'pong' }
Scenario: get the "first key" out of a given json
* def response = { "key1": { "a" : 1 }, "key2" : { "b": 1 } }
* def first = karate.keysOf(response)[0]
* match first == 'key1'
Scenario: java pojo to json
* def className = 'com.intuit.karate.core.SimplePojo'
* def Pojo = Java.type(className)
* def pojo = new Pojo()
* json jsonVar = pojo
* match jsonVar == { foo: null, bar: 0 }
* def testJson = { foo: 'hello', bar: 5 }
* def testPojo = karate.toBean(testJson, className)
* assert testPojo.foo == 'hello'
* assert testPojo.bar == 5
Scenario: java pojo to xml
* def Pojo = Java.type('com.intuit.karate.core.SimplePojo')
* def pojo = new Pojo()
* xml xmlVar = pojo
* match xmlVar == <root><foo></foo><bar>0</bar></root>
Scenario: parsing json, xml or string
* def temp = karate.fromString('{ "foo": "bar" }')
* match karate.typeOf(temp) == 'map'
* match temp == { foo: 'bar' }
* def temp = karate.fromString('<foo>bar</foo>')
* match karate.typeOf(temp) == 'xml'
* match temp == <foo>bar</foo>
* def temp = karate.fromString('random text')
* match karate.typeOf(temp) == 'string'
* match temp == 'random text'
Scenario: parsing json, xml or string within a js block (use asMap)
* eval
"""
var temp = karate.fromString('{ "foo": "bar" }');
if (karate.typeOf(temp) != 'map') karate.fail('expected map');
var res = karate.match(temp, { foo: 'bar' });
if (!res.pass) karate.fail(res.message);
"""
Scenario: inspecting an arbitrary object
* def foo = { foo: 'bar' }
* match karate.typeOf(foo) == 'map'
* def foo = ['foo', 'bar']
* match karate.typeOf(foo) == 'list'
Scenario: json manipulation using string-replace
* def data =
"""
{
foo: '<foo>',
bar: { hello: '<bar>'}
}
"""
# replace is convenient sometimes because you don't need to worry about complex nested paths
* replace data
| token | value |
| foo | 'bar' |
| bar | 'baz' |
# don't forget to cast back to json though
* json data = data
* match data == { foo: 'bar', bar: { hello: 'baz' } }
Scenario: json path on a string should auto-convert
* def response = "{ foo: { hello: 'world' } }"
* def foo = $.foo
* match foo == { hello: 'world' }
Scenario: js and numbers - float vs int
* def foo = '10'
* string json = { bar: '#(1 * foo)' }
* match json == '{"bar":10}'
* string json = { bar: '#(parseInt(foo))' }
* match json == '{"bar":10}'
* def foo = 10
* string json = { bar: '#(foo)' }
* match json == '{"bar":10}'
* def foo = '10'
* string json = { bar: '#(~~foo)' }
* match json == '{"bar":10}'
# JS math can introduce a decimal point in some cases
* def foo = 100
* string json = { bar: '#(foo * 0.1)' }
* match json == '{"bar":10.0}'
# but you can easily coerce to an integer if needed
* string json = { bar: '#(~~(foo * 0.1))' }
* match json == '{"bar":10}'
Scenario: large numbers in json - use java BigDecimal
* def big = 123123123123
* string json = { num: '#(big)' }
* match json == '{"num":1.23123123123E11}'
* def big = new java.math.BigDecimal(123123123123)
* string json = { num: '#(big)' }
* match json == '{"num":123123123123}'