Automated testing with chai js - javascript

I want to load a configuration file for tests.
One of the parameters is type.
So how can I replace the next line.
expect(res.body).to.deep.equal(test.expect)
with "to.deep.equal" string.
I tried :
let exp = expect(res.body);
test.type.split('.').forEach(t => exp = exp[t])
exp(test.expect)
But then i got:
Uncaught TypeError: this.assert is not a function
at assertEqual (node_modules\chai\lib\chai\core\assertions.js:1026:12)
EDIT:
I managed to do it in the following way:
let exp = expect(res.body);
test.type.split('.').slice(0,-1).forEach(t => exp = exp[t])
exp[_.last(test.type.split('.'))](test.expect)
I'd love to get an explanation for that. and if is exist another way for it.

Because you're breaking the thisValue of the last member (equal), which it tries to access but is no longer bound to deep object.
(I'm really butchering the explanation).
You can do:
let exp = expect(res.body);
test.type.split('.').forEach(t => {
exp = typeof exp[t] === 'function'
? exp[t].bind(exp)
: exp[t];
});
exp(test.expect)
To further explain, this is why you're seeing the TypeError: this.assert is not a function - the equal call is trying to access this.assert of the deep object, but the this is no longer bound to it. By explicitly binding it via .bind() we can retain it.
That's also why your second code example works, because you're properly calling the equal() as a method of deep.

Related

How to test this statement using jest and enzyme

In our code, I have two statements
const { column, showTooltip, tooltipValue, data } = props;
const key = column.bindProperties[0].properties[0].name;
on testing, this gives error as
"TypeError: Cannot read property '0' of undefined."
what is the meaning of this statement column.bindProperties[0].properties[0].name; and how to test it.
In JS you can't guarantee that objects have certain properties.
When you try to access column.bindProperties[0].properties[0].name, either column.bindProperties or column.bindProperties[0].properties is undefined - hence the error you're getting.
You can either use lodash's _.get() or validate the keys are defined using the redundantly annoying:
const key = column
&& column.bindProperties
&& column.bindProperties[0]
&& column.bindProperties[0].properties
&& column.bindProperties[0].properties[0]
&& column.bindProperties[0].properties[0].name;
This will make sure your code won't break. If one expression in the chain isn't defined, the expression will stop evaluating and you'll just get undefined as the result.
Since no one has really just spelt it out, here's an example of optional chaining:
const key = column?.bindProperties?.[0]?.properties?.[0]?.name;
and with nullish coalescing:
const key = column?.bindProperties?.[0]?.properties?.[0]?.name ?? "I'm a fallback value";

How can I use optional chaining with arrays and functions?

I'm trying to use optional chaining with an array instead of an object but not sure how to do that:
Here's what I'm trying to do myArray.filter(x => x.testKey === myTestKey)?[0].
Also trying similar thing with a function:
let x = {a: () => {}, b: null}
console.log(x?b());
But it's giving a similar error - how can I use optional chaining with an array or a function?
You need to put a . after the ? to use optional chaining:
myArray.filter(x => x.testKey === myTestKey)?.[0]
Playground link
Using just the ? alone makes the compiler think you're trying to use the conditional operator (and then it throws an error since it doesn't see a : later)
Optional chaining isn't just a TypeScript thing - it is a finished proposal in plain JavaScript too.
It can be used with bracket notation like above, but it can also be used with dot notation property access:
const obj = {
prop2: {
nested2: 'val2'
}
};
console.log(
obj.prop1?.nested1,
obj.prop2?.nested2
);
And with function calls:
const obj = {
fn2: () => console.log('fn2 running')
};
obj.fn1?.();
obj.fn2?.();
Just found it after a little searching on the what's new page on official documentation
The right way to do it with array is to add . after ?
so it'll be like
myArray.filter(x => x.testKey === myTestKey)?.[0]
I'll like to throw some more light on what exactly happens with my above question case.
myArray.filter(x => x.testKey === myTestKey)?[0]
Transpiles to
const result = myArray.filter(x => x.testKey === myTestKey) ? [0] : ;
Due to which it throws the error since there's something missing after : and you probably don't want your code to be transpilled to this.
Thanks to Certain Performance's answer I learned new things about typescript especially the tool https://www.typescriptlang.org/play/index.html .
ECMA 262 (2020) which I am testing on Edge Chromium 84 can execute the Optional Chaining operator without TypeScript transpiler:
// All result are undefined
const a = {};
console.log(a?.b);
console.log(a?.["b-foo-1"]);
console.log(a?.b?.());
// Note that the following statements throw exceptions:
a?.(); // TypeError: a is not a function
a?.b(); // TypeError: a?.b is not a function
CanIUse: Chrome 80+, Firefox 74+
After a bit of searching the new page in the official documentation, it was discovered.
You need to put a . after the ? to use optional chaining.
So it will be so,
myArray.filter(x => x.testKey === myTestKey)?.[0]
Used only ? Makes the compiler think that you are trying to use a conditional operator (then it causes an error because it doesn't see a : later)
It's not necessary that the function is inside the object, you can run a function using optional chaining also like this:
someFunction?.();
If someFunction exists it will run, otherwise it will skip the execution and it will not error.
This technique actually is very useful especially if you work with reusable components and some components might not have this function.
Well, even though we figured out the correct syntax, the code doesn't make much sense to me.
The optional chaining in the code above is making sure, that the result of myArray.filter(x => x.testKey === myTestKey) is not null and not undefined (you can have a look at the TS output). But it is not possible anyway, because the result of the filter method is always an array. Since JavaScript doesn't throw "Array bounds exceeded", you are always safe when you try to access any index - you will get undefined if this element doesn't exist.
More example to make it clear:
const myArray: string[] = undefined
console.log(myArray.filter(x => x)?.[0]) //throws Cannot read property 'filter' of undefined
//in this example the optional chaining protects us from undefined array
const myArray: string[] = undefined
console.log(myArray?.filter(x => x)[0]) //outputs "undefined"

What is the reason of using two sets of parentheses on object method call

I'm currently learning and educating myself on javascript, i just found one simple code which is using this '()();' what is this called, didnt find much information about it, what is it and how it is used, here the code i found :
'use strict';
let obj, method;
obj = {
go: function() { alert(this); }
};
obj.go();
(obj.go)();
(method = obj.go)();
(obj.go || obj.stop)();
sory english is not my mother language if some mistake.
Used on their own, parenthesis are grouping operators. They group expressions to control the order or precedence of the evaluation. You can read MDN here about it.
// example // is the same as
(obj.go)(); obj.go();
(method = obj.go)(); method = obj.go; method();
(obj.go || obj.stop)(); // calling go or stop after assinging to a temp variable
That piece of code is demonstrating how this is bound within a function execution content (in this case in go). It shows that simply putting parentheses around a method does not alter that behaviour: this is still bound to obj.
As soon as the parentheses surround an expression involving operator(s) the situation changes, and the method that results from the expression is called without a specific this binding: the default applies (undefined).
Another variant is the following:
(0,obj.go)();
Here the comma-operator kicks in, and so we are in the expression case: this is no longer bound to obj in the method call.
It just controls the order of the execution. You could write everything like this too, to make it more clear:
// (obj.go)();
obj.go();
// (method = obj.go)();
method = obj.go;
method();
// (obj.go || obj.stop)();
var method = obj.go || obj.stop;
method();

Why is `s.len` undefined (and not 4) while `s` has the value `test`? - JavaScript

I am puzzled with this one. I have the following code.
var s = "test";
s.len = 4;
var t = s.len;
The question is why the variable t has a value of undefined.
If you check the s.len after that code it is undefined.
If you check s the value is test. Not sure what is going on here. I am sure there is an explanation, but can't get my head around that and don't know how to search that.
For those who consider to vote down. This is a question we got in a course, and we are expected to prepare for the next session with this riddle.
I am not new to programming, but I fail to research how JavaScripts treats this code. It is valid code really, execute it in your Dev Tools and you will see.
I define a property for the string s called len assign to it the value 4. This property is, I believe created, but undefined. I would like to now why is it ? Is it specific to strings in JavaScript ?
but I fail to research how JavaScripts treats this code.
That is easy: strings are primitive types in JS, which means they don't have properties by themselves.
For . operator to work with them (e.g. for .length call) javascript defines such a thing called "wrapper objects".
So when you try to access a property of a primitive object - a temporary wrapper object is created that does behave as an object, hence you can access and assign properties to it.
The problem is that the wrapper object is temporary, so after it's used to access a property the object is discarded with all its state.
That's why when you assign a .len property you cannot access it on the next line: it's lost.
So a pseudo code for what actually happens behind the scenes for your code is
var s = "test";
(new String(s)).len = 4; // here you add an attribute for a new object
// and `s` is left untouched
var t = s.len;
The question is why the variable t has a value of undefined.
Because you have defined s as a string not as an object. so s.len should be undefined!
I am not sure what are you trying to do. But if you want to get the length of s then t = s.length will simply work.
I define a property for the string s called len assign to it the value 4. This property is, I believe created, but undefined. I would like to now why is it ? Is it specific to strings in JavaScript ?
You can find the answer from this question
run :
var s1 = "test";
console.log(typeof s1)//string
var s2 = {}
console.log(typeof s2)//object
s1.len = 4;
s2.len = 4;
console.log(s1.len);//undefine
console.log(s2.len);//4

What is the result of the expression?

Does this code would work as expected in all browsers? Is there any notes in specification about it?
var attributes = this._attributes ? this._attributes : (this._attributes = []);
I.e. if *this._attributes* not initialized, then new array will be created and that array will be assigned to *this._attributes* and to attributes.
There's nothing special about that expression, and you'll have no problems in any major browser. You could shorten it by using the || operator:
var attributes = this._attributes || (this._attributes = []);
That will work in all browsers.
It could be actually made terser with...
var attributes = this._attributes || (this._attributes = []);
No, I think unfortunately you may not access _attributes when it's undefined. So you have to check typeof attributes != "undefined".
I don't see any reason why not. I don't think I'd write it that way, I'm not a fan of assignments with side-effects, but syntactically it's fine.
This works just fine, when accessing an undefined property of any object, that access will return undefined. The single thing you have to watch out for is that you don't extend the Object.prototype to have a _attributes attribute because this will screw you up, but then again, never extend native prototypes.
From the spec :
8.12.2 [[GetProperty]] (P)
Let prop be the result of calling the [[GetOwnProperty]] internal method of O with property name P.
If prop is not undefined, return prop.
Let proto be the value of the [[Prototype]] internal property of O.
If proto is null, return undefined.
Return the result of calling the [[GetProperty]] internal method of proto with argument P.
So it checks whether the object has the property, if so it returns it, if not it searches up the prototype chain, if it finds something there it returns it, otherwise it returns undefined.

Categories

Resources