Deep assertion on JSON array with contains in Karate - karate

Scenario:
Given def cat =
"""
{
name: 'Billie',
kittens: [
{ id: 23, name: 'Bob', age: 35 },
{ id: 42, name: 'Wild', age: 25 }
]
}
"""
Then match cat.kittens contains [{ id: 42, name: 'Wild' }, { id: 23, name: 'Bob' }]
As seen in the example, I am not worried about 'age'. I understand that I can use '#ignore'. Is there any other way, if I have lot of such nodes that I have to ignore.
I am just thinking, can it work with JSON arrays as it does with JSON Objects. asserting only specified nodes.
error:
assert.feature:24 - path: $.kittens[*], actual: [{"id":23,"name":"Bob","age":35},{"id":42,"name":"Wild","age":25}], expected: {id=42, name=Wild}, reason: actual value does not contain expected
EDIT:
I tried something suggested in Karate - how to check if array contains values?
but that did not help me. I am not looking for schema-validation instead I am looking for functional validation where every object may have different values for keys.
Below one fails
Scenario:
Given def cat =
"""
{
name: 'Billie',
kittens: [
{ id: 23, name: 'Bob', age: 35 },
{ id: 42, name: 'Wild', age: 25 }
]
}
"""
* def expected = [{ id: 42, name: 'Wild' }, { id: 23, name: 'Bob' }]
Then match cat.kittens contains '#(^expected)'
This one works fine but this is not helping me.
Scenario:
Given def cat =
"""
{
name: 'Billie',
kittens: [
{ id: 23, name: 'Bob', age: 35 },
{ id: 42, name: 'Wild', age: 25 }
]
}
"""
* def expected = { id: 42, name: 'Wild' }
Then match cat.kittens contains '#(^expected)'
Currently, I am reading arrays separately and asserting them with loop.

Just adding the word deep works in 0.9.6.RC4
Then match cat.kittens contains deep [{ id: 42, name: 'Wild' }, { id: 23, name: 'Bob' }]
I don't understand why the linked answer when I closed your first question did not help you. Maybe I don't understand, and someone else can provide a better answer.

Related

How to compare two arrays in Standard SQL (BigQuery)?

I have two tables with the exact same schema, one of the fields is a record and I try to compare this field between the two tables.
For example:
Table A:
{ Name: 'Mary',
DOB: '06.06.1970',
Children:[
{ Name: John, Age: 6 },
{ Name: Agatha, Age: 10}
]
},
{ Name: 'Bob',
DOB: '30.03.1982',
Children:[
{ Name: Anthony, Age: 9 },
{ Name: William, Age: 4 },
{ Name: Rose, Age: 2 }
]
},
{ Name: 'Adam',
DOB: '312.10.1980',
Children:[
{ Name: Andrew, Age: 9 },
{ Name: Kate, Age: 4 }
]
}
Table B:
{ Name: 'Mary',
DOB: '06.06.1970',
Children:[
{ Name: John, Age: 6 },
{ Name: Agatha, Age: 10}
]
},
{ Name: 'Bob',
DOB: '30.03.1982',
Children:[
{ Name: Anthony, Age: 9 },
{ Name: George, Age: 4 },
{ Name: Frank, Age: 2 }
]
},
{ Name: 'Adam',
DOB: '312.10.1980',
Children:[
{ Name: Andrew, Age: 9 },
{ Name: Kate, Age: 4 },
{ Name: Jonathan, Age: 2 }
]
}
The output I'd like to get is:
Name
----------
Bob
Adam
Since the Children details are not the same for Bob or Adam in table A and table B (whenever it's the size of the record (num of children) or the details (children names etc...))
I tried to use SELECT UNION DISTINCT but it doesn't work on an array, I also tried != and <> but it doesn't work on arrays...
It would be ideal to compare two arrays like you can compare two lists in Python (comparing the structure and the content).
Is there a way to implement something similar ?
Thank you
select name
from `project.dataset.tableA` a
join `project.dataset.tableB` b
using(name)
where a.dob != b.dob
or (select string_agg(format('%t', s) order by name) from a.children s)
!= (select string_agg(format('%t', s) order by name) from b.children s)

String replacement inside json not working with complex objects

I have this Javascript object:
{ person: { name: "john", age: 32 }}
And an endpoint returning:
{
"name": "john",
"age": 32
}
I have this steps:
Given path 'endpoint/'
When method get
Then status 200
And match response ==
"""
{
"name": #(person.name),
"age": #(person.age)
}
"""
This is not working because #(person.name) and #(person.age) both evaluate to null, how can I fix it? (putting them in a new variable is not the fix I'm looking for)
Here you go:
* def data = { person: { name: 'john', age: 32 } }
* def response = { name: 'john', age: 32 }
* match response == data.person
Since you appear to be confused, let me add this (but not recommended because of the above):
* match response == { name: '#(data.person.name)', age: '#(data.person.age)' }

Karate match each on response assertion is failing to identify missing keys in response

I have a match each assertion like below in my code. Just tried creating similar examples as my code, just to explain the issue.
Scenario: Example scenario 1
* def response =
"""
[
{
id: 1,
name: "John",
password: "abc123"
},
{
id: 2,
name: "David",
password: "abc123"
},
{
id: 3,
name: "Mike",
password: "abc123"
},
{
id: 4,
name: "Johny"
}
]
"""
* match each response[*].password contains 'abc123'
Test status : Pass
Password field is missing in object 4(where id=4). Above test is passing for me. I am expecting Karate to fail the test in this case. How can I make my test fail in this case?
Scenario: Example scenario 2
* def response =
"""
[
{
id: 1,
name: "John",
},
{
id: 2,
name: "David",
},
{
id: 3,
name: "Mike",
},
{
id: 4,
name: "Johny"
}
]
"""
* match each response[*].password contains 'abc123'
Test status : Pass
Here, there is no password field at all in response. But my test is passing.
Need a work around to fail these kind of scenarios.
Example 3 :
* def response =
"""
[
{
id: 1,
name: "John",
password: "abc123",
skills :[ "training", "management"
]
},
{
id: 2,
name: "David",
password: "abc123",
skills :[ "training", "management"
]
},
{
id: 3,
name: "David",
password: "abc123",
skills :[ "training", "coding"
]
},
{
id: 4,
name: "David",
password: "abc123",
skills :[ "training", "management"
]
}
]
"""
Considering * match each response contains { password: 'abc123' } format(mentioned by #peter) to check example 1 and 2, what if I want to check skills array having 'training' in each object under response? How can I achieve this?
you can use match each to validate the json schema
https://github.com/intuit/karate#match-each
Note that response[*].password is a JsonPath expression that will return an array of all the password key-values found and will return only 3 in your case.
What you are looking for is this:
* match each response contains { password: 'abc123' }

How do I perform a SQL update on a list inside one of my table rows?

I have a table with parameters as shown below.
{
id: 1,
title: 'waccos',
description: 'Making an operating system in wacc',
est_duration: 420,
exp_req: 'any',
langs: [ 1 ],
owner: 1,
members: [ 1, 2 ]
},
I want to use SQL to add a new member into the member list, but I do not know how to. The table is called testprojects. I've tried using
(update testprojects
set members = members || $1
where title is $2;', [name, title])
but I think that is wrong. Could anyone help me please?
This is the table of members so far.
[
{ id: 1, name: 'A' },
{ id: 2, name: 'K' },
{ id: 3, name: 'S' },
{ id: 5, name: 'd' },
{ id: 6, name: 'J' },
{ id: 7, name: 'E' },
{ id: 8, name: 'a' }
]

Karate: verify text contains in a list of kittens in cat return all key-values did not match error

I have the following code
* def cat =
"""
{
kittens: [
{
id: 23,
name: 'Bob'
},
{
id: 42,
name: 'Wild'
}
]
}
"""
* def id = {id: 23}
I am trying to follow Karate contains and all key-values did not match error to resolve all key-values did not match error
here is what I have
* match cat == {kittens: '#(^id)'}
* match cat contains {kittens: '#(^id)'}
but I get the following error
com.intuit.karate.exception.KarateException: - path: $, actual: {kittens=[{"id":23,"name":"Bob"},{"id":42,"name":"Wild"}]}, expected: {kittens=#(^id)}, reason: all key-values did not match
Now I have added another colour field for each kitten:
* def cat =
"""
{
kittens: [
{
id: 23,
colour: 'black',
name: 'Bob'
},
{
id: 42,
colour: 'grey',
name: 'Wild'
}
]
}
"""
* def id = {id: 23, name: 'Bob'}
using the provided answer cat.kittens contains '#(^id)' STILL works.
Alternative way to do it is
* def id = {id: 23, colour: '#number', name: 'Bob'}
Option1 is better as you don't need to specify colour: '#number'.
Here you go:
* match cat.kittens contains '#(^id)'
For an explanation, read: https://github.com/intuit/karate#contains-short-cuts