Chai assertion, unable to identify property using should / expect - mocha.js

Hello: Need your help on a chai assertion.
I have a JSON response as shown below. I want to assert that it contains "Lastname is mandatory" only.
I tried using this statement but the error i get is AssertionError: expected [ Array(2) ] to have a deep property '#text'. Please help how to write this correctly.
using expect
chai.expect(data.response.error).to.have.deep.property('#text', 'Lastname is mandatory.');
using should
data.response.error.should.have.deep.property('#text', 'Lastname is mandatory.');
Response JSON
{
response: {
error: [
{
'#id': '1000',
'#text': 'Firstname is mandatory.'
},
{
'#id': '10001',
'#text': 'Lastname is mandatory.'
}
],
result:
{
status: '0'
}
}
}

Prior to Chai version 4
The use of deep with property requires that you pass a complete path to the property you want to test. In other words, deep.property won't do a search through all the properties for you. As the documentation puts it:
If the deep flag is set, you can use dot- and bracket-notation for deep references into objects and arrays.
Something like:
data.response.should.have.deep.property("error[0].#text");
Or you can start the path to the property with an array index if the object on which you use should is an array:
data.response.error.should.have.deep.property("[0].#text");
Here is a complete example derived from the code you show:
const chai = require("chai");
chai.should();
const data = {
response: {
error: [
{
'#id': '1000',
'#text': 'Firstname is mandatory.'
},
{
'#id': '10001',
'#text': 'Lastname is mandatory.'
}
],
result:
{
status: '0'
}
}
};
it("works", () => {
data.response.should.have.deep.property("error[0].#text");
// Or this, which looks weird but is allowed...
data.response.error.should.have.deep.property("[0].#text");
});
Chai version 4 and later
The OP was using a release of Chai earlier than version 4. If you are using Chai version 4 and over, the flag to use to is not .deep anymore but .nested. So in earlier versions where you would use data.response.should.have.deep.property("error[0].#text"); in version 4 or later you'd use data.response.should.have.nested.property("error[0].#text");

Thanks to answer from #shvaikalesh at github. It has the relevant answer to my question which i provide here for future reference + the code extract is also below for quick reference.
chai.expect(data.response.error.some(e => e['#text'] == 'Lastname is mandatory.')).to.be.true

Related

How to combine Aggregate function with update

I could not find a way to translate the fowling MongoDb command into C#
db.Queue.aggregate(
[
{ $match: { "Processed": false } },
{ $sort: { "LastTimeChanged": 1  } },
{ $limit: 1 },
{ $set: { "WorkerName": "WORKER_NAME", "Processed": true }  },
{ "$merge": "Queue"  }])
The issues that I fund was with the $set and $merge command
$set -> in the MongoDb.Driver for .NET, associated with the Aggregate command I could not find any command that look like the $set
$merge -> the merge command examples are exclusive for merging collections and in this case, I could not find a way to use the Merge method in the API.
Any one can throw light here!??
thanks
Paulo Aboim Pinto
I found a way to execute the command using the MongoDb.Driver but I thing there should be a better and fluent way of doing it
var filter = Builders<QueueCollection>.Filter.And
(
Builders<QueueCollection>.Filter.Eq(x => x.WorkerName, string.Empty),
Builders<QueueCollection>.Filter.Eq(x => x.Processed, false)
);
var sortOptions = Builders<QueueCollection>
.Sort.Ascending("LastTimeChanged");
this.queueCollection.Aggregate()
.Match(filter)
.Sort(sortOptions)
.Limit(1)
.AppendStage<QueueCollection>("{ $set: { 'WorkerName': 'WORKER_NAME' } }")
.AppendStage<QueueCollection>("{ $merge: 'Queue' }")
.ToList();
This works for now, but I would like to want still to know:
How do I replace the $set in the Aggregate pipeline
How do I write a proper $merge command.
thanks in advance for any answer
Paulo Aboim Pinto

Made a query in Watson discovery, tried to duplicate via nodejs sdk and the passages array is empty

After doing a simple natural language query in the build query page, set the options for "include relevant passages to Yes. I get back 5 passages and results. All good. When I try from npm ibm-watson 6 nodejs sdk. I get the results, but an empty passages array with the same natural langauge text.
Here is the the url from the query page showing the options, which I tried all of them
https://api.us-east.discovery.watson.cloud.ibm.com/instances/d45df72b-93e4-4897-b9ac-98dc1e088afc/v1/environments/xx/collections/xx/query?version=2018-12-03&deduplicate=false&highlight=true&passages=true&passages.count=5&natural_language_query=what%20is%20autism
Here is the answer from the query builder page
Here is code example,
var discovery = new watson_discovery_v1({
authenticator : new IamAuthenticator({apikey: msg.startup.discovery_password}),
serviceUrl : msg.startup.discovery_endpoint,
version: '2020-09-22'
});
msg.WDSParams = {
environmentId: "x",
collectionId: "x",
passages: true,
count:5,
natural_language_query: msg.params.input.text
}
discovery.query(msg.WDSParams)
.then(results => {
msg.WDSResults = results; //your query results
node.send(msg);
})
.catch(err => {
console.log('error:', err);
});
Here is the json that came back from the discovery call
I have tried all of the passage options, duplicated the exact options that the query builder used. The same results come back, but no passages. Anyone have an idea? BTW using the Lite plan until I can prove passages works.
The problem was related to the way I called the query method. Below code resolved the issue. This code is for a nodeRed function node.
const watson_discovery_v1 = global.get('watson_discovery_v1');
const { IamAuthenticator } = global.get('ibm_auth');
const discovery = new watson_discovery_v1({
authenticator : new IamAuthenticator({apikey:
msg.startup.discovery_password}),
serviceUrl : msg.startup.discovery_endpoint,
version: '2019-04-30'
});
async function run() {
try {
const result = await discovery.query({
environmentId: 'x',
collectionId: 'x',
passages: true,
passagesCount: 2,
count: 5,
naturalLanguageQuery: msg.params.input.text
})
msg.WDSResults = result
clearTimeout(myTM)
}
catch(e){
node.error(e)
}
node.send(msg);
}
run()

Correct way to expect/receive state with Enzyme & MockProvider

I'm testing a component that is using a graphql useLazyQuery. MockProvider is provided by the Apollo recommended library #apollo/react-testing. I want to test that a certain message is being rendered base off the length of the data that is returned from the query. I have html elements structured like this:
<div className="message" data-id={props.data ? props.data.specials.length > 0 ? 'valid' : 'invalid' : ''}>
...children
</div>
I read through Apollo's docs about testing and wrote up a test like this:
mock = {
request: {
query: GET_PRODUCTS,
variables: { zip: "91001" }
},
result: {
data: {
specials: [
{
"_id": "5ecf28c459d3781a2e99738e",
},
{
"_id": "5ecf28c459d3781a2e99738f",
}
]
}
}
}
wrapper = mount(
<MockedProvider mocks={[mock]} addTypename={false}>
<Store.Provider value={[{ loading: false, zip: null }]}>
<GetZipCode />
</Store.Provider>
</MockedProvider>
)
await wait(0)
expect(wrapper.find(message).prop('data-id')).toEqual('valid')
But I've found that the tests do not update based on the mock that I put it. I have a test about this where I'm passing this value as the mock:
mock = {
request: {
query: GET_PRODUCTS,
variables: { zip: "32005" }
},
result: {
data: { specials: [] }
}
}
...after tests
expect(wrapper.find(message).prop('data-id')).toEqual('invalid')
And for both of these tests the expected value is "" which is the initial value for my data-id prop in my html element. If I were to set the initial value to "invalid" compared to "" then the expected value in my test would output "invalid".
It seems that no matter what I passed my mock provider it doesn't wait for it to be passed. I'm using the wait package that Apollo recommends as well.
If you wanna mock using jest, you use the following approach
jest.mock("apollo-client", () => ({
__esModule: true,
useQuery: (query: any) => {
//other mocks if needed
},
useLazyQuery: jest.fn().mockReturnValue([
jest.fn(),
{
data: {
yourProperties: "Add Here",
},
loading: false,
},
]),
}));
As you see, this approach even returns the mock function that is called in the code to be tested.
I faced in similar issues while testing with useLazyQuery. I would suggest writing a custom hook on top of useLazyQuery. This will have two benefits:
No need to wrap your test instance in Mock provider. You can mock the entire module (custom hook) using jest and use mockReturnValue method to simulate different behaviours (loading, data, error)
You can easily switch between actual query or some mock data in local file system while development.
Refer this blog for implementation details and demo app.

apollo watch method with variables

I am trying to use apollo client watch method in angular to query spring boot server. I am not able to pass arguments with this method.
Since "aid" is mandatory, when it is trying to make a call I getting error like
ERROR Error: GraphQL error: Variable 'aid' has coerced Null value for NonNull type 'String!'
Below is my code in typescript.
export class AgreementGQL extends Query {
document = gql`query agreement($aid: String!) {
agreement(id: $aid) {
id
name
}
}
Below is calling code to the agreement. Where agreement is injected in constructor.
this.agreement.watch({
aid: "1234567"
}).valueChanges.subscribe(result => {
console.log("*********** result : " + JSON.stringify(result.data));
});
I tried using "variables" as well, but no luck.
this.agreement.watch({ variables:{
aid: "1234567"
}}).valueChanges.subscribe(result => {
console.log("*********** result : " + JSON.stringify(result.data));
});
You just need to set the value as a key/value pair like:
const myVal = '123';
Then pass that as an object into the watch method...
const agreement = this.agreementQuery
.watch({ myVal })
.valueChanges.pipe(pluck('data'));
Then Subscribe to get the data out:
agreement.subscribe(data => console.log(data));
This approach worked for me.

Why is an Array in my payload being flattened in Sinatra / Rack::Test?

I'm trying to test a small Sinatra app using rspec. I want to pass a rather complex payload and am running into issues i do not understand: my payload contains an array of hashes. When I run the actual application this will work as expected, yet when I use the post helper to run my tests, the array will contain a merged hash:
post(
"/#{bot}/webhook",
sessionId: "test-session-#{session_counter}",
result: {
contexts: [
{ some: 'fixture' },
{ name: 'generic', parameters: { facebook_sender_id: 'zuck-so-cool' } }
]
}
)
In the sinatra handler I use params to access this payload:
post '/:bot/webhook' do |bot|
do_something_with(params)
end
When I now look at the structure of params when running the test suite, I will see the following structure:
[{"some" => "fixture", "name" => "generic", "parameters" => {"facebook_sender_id" => "zuck-so-cool"}}]
which I do not really understand. Is this a syntax issue (me being a ruby noob), am I using params wrong, or is this a bug?
EDIT: So i found out this is an "issue" with the way that Rack::Test will serialize the given payload when not specifying how to (i.e. as form data). If I pass JSON and pass the correct headers it will do what I expect it to do:
post(
"/#{bot}/webhook",
{
sessionId: "test-session-#{session_counter}",
result: {
contexts: [
{ some: 'fixture' },
{ name: 'generic', parameters: { facebook_sender_id: 'zuck-so-cool' } }
]
}
}.to_json,
{ 'HTTP_ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
)
Still I am unsure of this is an issue with the passed data structure not being possible to be serialized into form data or if this is a bug in the way that Rack::Test serializes data.
Looking at the relevant portion of the specs it looks like this is is expected behavior.

Resources