Jest Expected and receive are identical - jestjs

Is there a reason why Jest would see this as a not identical when both seem exactly the same?
So here is the code I am using to do the test, it's basically just a function that calls for an event emiter, in the event emiter if the date is invalid, I let it as is :
const datepickerComponent: Datepicker = new Datepicker();
const mockEvent = {
target: {
classList: {
remove: jest.fn(),
add: jest.fn(),
},
value: '01-01-197',
},
} as unknown as InputEvent;
datepickerComponent.onInput(mockEvent);
const emitMock: jest.Mock = jest.fn();
datepickerComponent.dsdDatepickerInputChange = { emit: emitMock } as unknown as EventEmitter<dsdDatepickerInputChangeEvent>;
// when
datepickerComponent.onInput(mockEvent);
const dateValue = new Date('197-01-01T00:00:00');
// then
expect(emitMock).toHaveBeenCalledWith({ value: '197-01-01', valueAsDate: dateValue });

The reason why you are observing this error is because whilst Date { NaN } values look the same, they actually refer to different object instances and cannot be traversed for equality any further, hence the actual error should be the following:
Expected: {"value": "197-01-01", "valueAsDate": Date { NaN }}
Received: serializes to the same string
(To reproduce this error - create two new dates using new Date('197-01-01T00:00:00') and pass them into .equals())
To get past this error, all you need to do is to simply refactor your .toHaveBeenCalledWith test into the following:
const calledWithArg = emitMock.mock.calls[0][0];
expect(JSON.stringify(calledWithArg)).toEqual(JSON.stringify({ value: '197-01-01', valueAsDate: dateValue }));
The reason why .toHaveBeenCalledWith does not work is because it does not allow us to reshape the argument object before a comparison (in our case we need to stringify it), hence we can alternatively extract the argument that the mock was called with via .mock.calls[0][0], stringify it and then compare it to the stringified version of the expected object.

Reference of valueAsDate is different. But Jest doc affirm it uses .toEqual for comparison. That means it try to deeply compare two new Date. This is a bad idea, you don't control the Date class, and there are probably some moving parts inside.
To loose match a value, you can check this issue: https://stackoverflow.com/a/55569458/7696155

Related

populate object properties using lambda expression in typescript

Newbie Alert! I feel silly asking this question but I need someone to teach me the correct syntax.
I have code that looks like this:
let thing: INewThing;
thing.personId = another.personId;
thing.address = another.work.address;
thing.greades = another.subjectInfo.grades;
thing.isCurrent = another.student.isCurrent;
I know it can be written cleaner. I want to use a lamda expression, something like this:
let thing: INewThing => {
personId = another.personId,
address = another.work.address,
grades = another.subjectInfo.grades,
isCurrent = another.student.isCurrent
} as IThingUpdate;
I have looked and looked for an example. I have yet to find one that works for me. It's just syntax but no matter what I try it doesn't work.
You're just looking to create a new object, which is a pretty different thing from a "lambda" (function). Just declare the object. You don't need a function.
const thing = {
personId: another.personId,
address: another.work.address,
// use the correct spelling below - no 'greades'
grades: another.subjectInfo.grades,
isCurrent: another.student.isCurrent,
};
If the another is typed properly, that should be sufficient.
If the another object had more properties using the same path, another option would be to destructure those properties out, then declare the object with shorthand, eg:
const originalObj = { prop: 'val', nested: { foo: 'foo', bar: 'bar', unwanted: 'unwanted' } };
const { foo, bar } = originalObj.nested;
const thing = { foo, bar };
Destructuring like this, without putting the values into differently-named properties, helps reduce typos - if a property starts out, for example, as someLongPropertyName, putting it into a standalone identifier someLongPropertyName and then constructing an object with shorthand syntax ensures that the new object also has the exact property name someLongPropertyName (and not, for example, someLongPRopertyName - which isn't that uncommon of a mistake when using the more traditional object declaration format).
But since all the paths in your another object are different, this approach wouldn't work well in this particular situation.

How to get entity from the argument and create if condition in Dialogflow Inline editor for fulfilment

I am completely new to Dialogflow and nodejs. I need to get the entity value from the argument to the function (agent) and apply if the condition on that. How can I achieve this?
I am trying below but every time I get else condition become true.
I have created an entity named about_member.
function about_member_handeller(agent)
{
if(agent.about_member=="Tarun")
{
agent.add('Yes Tarun');
}
else
{
agent.add("No tarun");
}
}
Please help.
In such cases, you may use console.log to help unleash your black box, like below:
function about_member_handeller(agent) {
console.log(JSON.stringify(agent, null, 2));
if(agent.about_member=="Tarun") {
agent.add('Yes Tarun');
}
else {
agent.add("No tarun");
}
}
JSON.stringfy() will serialize your json object into string and console.log will print the same on the stdOut. So once you run your code this will print the object structure for agent and after which you will know on how to access about_member. Because in the above code it's obvious that you are expecting about_member to be a string, but this code will let you know on the actual data in it and how to compare it.
To get the parameter you can use the following;
const valueOfParam = agent.parameters["parameterName"];

Cannot pass array of string to function

I have this function:
function proc(unames: Array<string>){}
I try to pass it this:
import _ = require('lodash');
const usernames = _.flattenDeep([unames]).filter(function (item, index, arr) {
return item && arr.indexOf(item) === index;
});
const recipient = 'foobarbaz';
proc(usernames.concat(recipient));
I get this error:
Does anyone know how to mitigate this?
I tried this, and I get an even longer and crazier error:
function proc(unames: Array<string | ReadonlyArray<string>>){}
however, this made the error go away:
function proc(unames: Array<string | ReadonlyArray<any>>){}
not really sure what's going on.
The warning seems to be referring to the use of .concat() rather than proc().
When called on an Array, such as usernames, TypeScript is validating that the arguments given to .concat() are also Arrays.
To resolve the warning, you have a few options:
Since you're using Lodash, its own _.concat() allows for appending individual values, and TypeScript's validation should be aware of that:
const recipient = 'foobarbaz';
proc(_.concat(usernames, recipient));
Define recipient as an Array or wrap it when calling .concat():
const recipient = [ 'foobarbaz' ];
proc(usernames.concat(recipient));
const recipient = 'foobarbaz';
proc(usernames.concat( [recipient] ));
You may also be able to configure TypeScript to validate for a later version of ECMAScript. Between 5.1 and 2015 (6th edition) of the standard, the behavior of the built-in .concat() was changed to support individual values (by detecting spreadable).
For now, TypeScript is validating .concat() for 5.1 or older.

Botframework (Node) - dialogData stripping out regex

Does the BotBuilder Node SDK actively strip out anything that is stored the dialogData object?
For example, I have created a simple loop and I am storing a regex in session.dialogData.questions. When I console log this after storing it, I can see that my regex is stored as expected:
{
validation: /^[0-9]{19}$/,
}
However, when I try and log the same session.dialogData.questions object in the next step of my waterfall, then the regex seems to have been converted into an empty object:
{
validation: {}
}
I presume this a deliberate attempt to prevent XSS and other types of exploitation?
The code for this example can be found below:
const builder = require('botbuilder')
const lib = new builder.Library('FormBuilder')
lib.dialog('/', [
(session, args) => {
session.dialogData.questions = {
validation: /^[0-9]{19}$/
}
console.log(session.dialogData.questions)
builder.Prompts.confirm(session, 'Would you like to proceed?')
},
(session, results) => {
console.log(session.dialogData.questions)
}
])
module.exports.createLibrary = () => {
return lib.clone()
}
Regarding your initial question, no the SDK doesn't actively strip anything out of the dialogData object. Anything that is, except for regexp...
I'm not sure why this is, but for the time being I recommend storing your pattern as a string, '^[0-9]{19}$', and then constructing a new regexp via new RegExp(session.dialogData.questions.validation) when needed.
I tried storing a method to construct a new RegExp using this.questions.validation, but likewise this was also stripped out.
Edit:
Per Ezequiel's comment, this isn't a Bot Framework issue in the end. It is not possible to store non-serializable data inside JSON.

Query value gets quoted automatically before sending it to MongoDB?

The following is confusing me a lot. I have been spending quite a bit of time trying to understand why collection.find() doesn't work with regex passed as an object. The regex match is coming over HTTP wrapped in the body of a POST request. Then I try to gather the query (in string format) and perform the query. The problem seems to be that unless the regex is written inside Node without quotes, it won't work. That is, it must be a literal without quotes.
For example, the following works fine:
var query1 = {
company: {
'$regex': /goog/
}
};
collection.find(query1, {}).toArray(function (err, docs) {
// Got results back. Awesome.
});
However, if the data comes wrapped in an object, it doesn't return anything. I suspect it's because the value gets quoted behind the scenes (i.e. "/goog/"):
// Assume
var query2 = {
company: {
'$regex': query.company
}
};
collection.find(query2, {}).toArray(function (err, docs) {
// Got nothing back.
});
I have tested it with the mongo shell and I can confirm the following:
// Returns 5 results
db.getCollection("contacts").find( { "company": /goog/ } )
// Doesn't match anything
db.getCollection("contacts").find( { "company": "/goog/" } )
Furthermore, I just discovered the following: if I write the value with quotes
// Works fine
var companyRegex = {'$regex': /goog/};
var query3 = {
company: companyRegex
};
So technically, a "literal" regex without quotes wrapped in an object works fine. But if it's a string, it won't work. Even after trying to replace the double-quotes and single-quotes with nothing (i.e. essentially removing them.)
Any idea how can I get the regex match be passed verbatim to find()? I've researched it, finding lots of potential solutions, alas it's not working for me.
Thanks in advance!
Let me focus on one line of your post. This is where the problem might be:
The regex match is coming over HTTP wrapped in the body of a POST request.
This seems problematic because:
The only structures that survive serialization between client/server are:
boolean
number
string
null *
objects and arrays containing these basic types
objects and arrays containing object and arrays [of more obj/array] of these basic types
Regexp, Date, Function, and a host of others require reconstruction, which means
passing a string or pair of strings for the match and option components of the Regexp and running Regexp() on the receiving end to reconstruct.
Regexp gets a bit messy because Regexp.toString() and Regexp() do not appear to be inverses of each others: /someMatch/.toString() is "/someMatch/" but RegExp("/someMatch/") is //someMatch// and what was needed instead to rebuild the regexp was just RegExp("someMatch"), which is /someMatch/. I hope this helps.
JSON.stringify(/someMatch/) is {} (at least on Chrome).
So instead of trying to build a general transport, I recommend re instantiating a particular field as a regexp.
* Irrelevant note: (null is fine but undefined is peculiar. JSON won't stringify undefineds in objects and turns undefined into null in Arrays. I recognize this isn't part of your problem, just trying to be complete in describing what can be serialized.)

Resources