New to Karate, and JSON, for that matter, but I've got a variable like:
response {
entries {
products [
{
names [
"Peter Parker",
"Tony Stark",
"Captain America"
]
},
{
names [
"Thomas Tinker",
"Jimmy Johnson",
"Mama Martha"
]
}
]
}
}
match each response.entries.products[*].names returns a list like:
["Peter Parker","Tony Stark","Captain America","Thomas Tinker","Jimmy Johnson","Mama Martha"]
But I'd like to assign that output to a variable, such as:
* def variable = response.entries.products[*].names
that would hold a similar value. When I use the above line, I get the following error:
Expected an operand but found *
Is it possible to achieve that, or something similar? If so, how?
Thanks!
Yes, there is syntax for that:
* def variable = $response.entries.products[*].names
Read the docs: https://github.com/intuit/karate#get
I am using Karate API framework for the API automation and came across with one scenario, the scenario is when I am hitting a post call it gives me some json response and few of the items are having tags whereas few of them are showing tags as blank to get all the tags below is the feature file scenario line
* def getTags = get response.items[*].resource.tags
It is giving me response as
[
[
],
[
],
[
{
"tags" : "Entertainment"
}
],
[
],
[
{
"tags" : "Family"
}
],
As you can see out of 5 or 6 tags only 2 tags are having the value, so I want to capture if any tags value is showing or not. What would be the logic for the assertion considering these tags can all come as empty and sometimes with come with a string value. In above case "Family" & "Entertainment"
Thanks in advance !
* match each response.items[*].resource.tags == "##string"
This will validate that tags either doesn't exist or is a string.
I think you can use a second variable to strip out the empties, or maybe your original JsonPath should use .., you can experiment:
* def allowed = ['Music', 'Entertainment', 'Documentaries', 'Family']
* def response =
"""
[
[
],
[
],
[
{
"tags":"Entertainment"
}
],
[
],
[
{
"tags":"Family"
}
]
]
"""
* def temp = get response..tags
* print temp
* match each temp == "#? allowed.contains(_)"
I receive large array of pairs:[number, {number,number, big array of numbers}]
First I add my main pair to beginning of the array:
prepend([target[0], {count : target[1].length, overall : target[1].length, items:target[1]}]),
Next I do:
Promise.all([
to_file_json(
token.user_id,
'connections_data',
JSON.stringify(
fromPairs(r[0])
))...
And I can find my main pair somewhere in the middle of my file.
So my question is, could fromPairs possibly change the order? If yes what can I do to prevent this?
Edit:
additional info:
1)r variable correspond to [[number, Friends][], Float64Array[]]
2) target variable correspond to [number,number[]]
3) Beginning of element which i'm prepend, it's always the biggest one, and it got in the middle of the file somehow.
"136444868":{"count":304,"overall":304,"items":[19363,234566,290677,1375661,2030175,2131497,2593602,2596894,2816890,2869895,3170377,3437884,3486703,3504543,4046799,4235623,5366101.....
4) Friends type :
interface Friends {
count:number,
overall:number,
items:number[]
};
sample data
{
"19363":{"count":5,"overall":3088,"items":[51177198,53119509,136035431,209482119,216378147]}
,"234566":{"count":6,"overall":6803,"items":[290677,3504543,23180680,75311610,178479726,196401211]}
,"290677":{"count":19,"overall":2213,"items":[234566,5686439,7873089,11175816,13726459,20697213,23180680,27419631,55209039,74493674,75311610,125041200,133272552,139307068,159591583,168386810,173599247,178429642,189097165]}
,"1375661":{"count":0,"overall":76,"items":[]},"2030175":{"count":14,"overall":86,"items":[2596894,6507568,11681736,17736119,49557638,117771194,127144880,141523415,147264238,153044182,156925389,160656334,223530741,262311445]},"2131497":{"count":16,"overall":301,"items":[13598979,15682478,20357560,20869716,27419631,30869837,33650605,40129023,68976427,88146695,90648231,101105191,118193129,145163503,216503667,387266562]},
I expect the issue is that you do a prepend without removing the element from its later place in the list.
Then you might end up with some data like:
[
[ 2131497, { count: 16, overall: 301, items: [ /* .. * ] } ], // duplicate
[ 19363, { count: 5, overall: 3088, items: [ /* .. * ] } ],
[ 234566, { count: 6, overall: 6803, items: [ /* .. * ] } ],
[ 290677, { count: 19, overall: 2213, items: [ /* .. * ] } ],
[ 1375661, { count: 0, overall: 76, items: [ /* .. * ] } ],
[ 2030175, { count: 14, overall: 86, items: [ /* .. * ] } ],
[ 2131497, { count: 16, overall: 301, items: [ /* .. * ] } ] // duplicate
]
Then, when you do fromPairs, the later version will override the earlier one, and it will end up back in the list at the original position, as per this line from the documentation:
If a key appears in multiple pairs, the rightmost pair is included in the object.
But... even if you fix this, you will still not get the behavior you want, because of the object property iteration order specification, which says that integer keys of an object are iterated first, in numeric order, before the non-integer keys. Axel Rauschmayer has a very readable description of this.
These complexities are one of the reasons that Ramda (disclaimer: I'm one of the authors) has not created a foldObj implementation.
Can someone tell me why the following code is not working? It is supposed to set the date in a field when it loads, then allow the date to be changed by clicking on the field. I'm using rebol/view 2.7.8 on linux. Actually, I think this code used to work years ago when I was using MS Windows, but not under linux for some reason.
drl
rebol []
trace true
out: layout [
style dater txt bold right [trans-date/date: copy (form now/date)] 48x24
dater "T-Date:" trans-date: field 80x24 (form now/date) feel [
engage: func [face action event][
if action = 'up [
lv-dat: request-date/date/offset (now/date) 450x375
if lv-dat <> none [
trans-date/text: form lv-dat
show trans-date
]
]
]
show trans-date
]
]
view out
Here is a cleaned up version of your code:
Rebol []
out: layout compose/deep [
style dater txt bold right 48x24
dater "T-Date:"
trans-date: field 80x24 (form now/date) feel [
engage: func [face action event][
if action = 'up [
lv-dat: request-date/date/offset (now/date) 450x375
if lv-dat [
face/text: form lv-dat
show face
]
]
]
]
]
view out
The main issue was the missing compose/deep call to evaluate the paren expressions before layout is called. However, that approach is not the usual way to initialize face properties, you should rather put init code in a do section of the VID block, like this:
Rebol []
out: layout [
style dater txt bold right 48x24
dater "T-Date:"
trans-date: field 80x24 feel [
engage: func [face action event][
if action = 'up [
lv-dat: request-date/date/offset now/date 450x375
if lv-dat [
face/text: form lv-dat
show face
]
]
]
]
do [trans-date/text: form now/date]
]
view out
Hope this helps.
So I want to do something like:
html unorderedList: [
group := html radioGroup.
self employeeNames do: [ :eachEmp |
html listItem: [
group radioButton
selected: <set tmpVar = empKey>
callback: [ self <dependent on button pushed> ].
html text: eachEmp ] ] ] ]
What I would like this to do is generate a list of employees, with radio buttons on each line. Then, depending on the radio button that's selected and which button is pushed, we do some action.
So a visual representation of what I want is something like:
|Post Timecard| --- |Timesheet History| --- |Print Paycheck| --- |Delete|
Employee 1 ..... data .... data .... data
Employee 2 ..... data .... data .... data
Employee 3 ..... data .... data .... data
Employee 4 ..... data .... data .... data
Employee 5 ..... data .... data .... data
So they could for example, select Employee 3 and then push |Delete| - this would trigger a delete for Employee 3.
I think I can handle what to do for the selected: portion of my code, but I've no clue how to handle the callback? Is there a way to dynamically choose what to call?
Since you are using a radio group anyway you'll only be able to select a single entry from the list of employees. Now, if you use a form element to wrap the controls, your action anchors could simply trigger a submit of the form:
formName := 'employee-form'.
html form
name: formName;
with: [
html unorderedList: [
group := html radioGroup.
self employeeNames do: [ :eachEmp |
html listItem: [
group radioButton
selected: nil "<set tmpVar = empKey>";
callback: [ :value | self "<dependent on button pushed>" ];
with: eachEmp ] ] ] ].
html anchor
submitFormNamed: formName;
callback: [ :value | self handleDelete ]
with: 'delete'
The callback of the anchor will be evaluated after all of the callbacks of the form elements.
Side note: notice the use of with: to set the anchor and radio button texts. You should almost always use with: as the last message to html.