toBe(true) vs toBeTruthy() vs toBeTrue() - javascript

What is the difference between expect(something).toBe(true), expect(something).toBeTruthy() and expect(something).toBeTrue()?
Note that toBeTrue() is a custom matcher introduced in jasmine-matchers among other useful and handy matchers like toHaveMethod() or toBeArrayOfStrings().
The question is meant to be generic, but, as a real-world example, I'm testing that an element is displayed in protractor. Which matcher should I use in this case?
expect(elm.isDisplayed()).toBe(true);
expect(elm.isDisplayed()).toBeTruthy();
expect(elm.isDisplayed()).toBeTrue();

What I do when I wonder something like the question asked here is go to the source.
toBe()
expect().toBe() is defined as:
function toBe() {
return {
compare: function(actual, expected) {
return {
pass: actual === expected
};
}
};
}
It performs its test with === which means that when used as expect(foo).toBe(true), it will pass only if foo actually has the value true. Truthy values won't make the test pass.
toBeTruthy()
expect().toBeTruthy() is defined as:
function toBeTruthy() {
return {
compare: function(actual) {
return {
pass: !!actual
};
}
};
}
Type coercion
A value is truthy if the coercion of this value to a boolean yields the value true. The operation !! tests for truthiness by coercing the value passed to expect to a boolean. Note that contrarily to what the currently accepted answer implies, == true is not a correct test for truthiness. You'll get funny things like
> "hello" == true
false
> "" == true
false
> [] == true
false
> [1, 2, 3] == true
false
Whereas using !! yields:
> !!"hello"
true
> !!""
false
> !![1, 2, 3]
true
> !![]
true
(Yes, empty or not, an array is truthy.)
toBeTrue()
expect().toBeTrue() is part of Jasmine-Matchers (which is registered on npm as jasmine-expect after a later project registered jasmine-matchers first).
expect().toBeTrue() is defined as:
function toBeTrue(actual) {
return actual === true ||
is(actual, 'Boolean') &&
actual.valueOf();
}
The difference with expect().toBeTrue() and expect().toBe(true) is that expect().toBeTrue() tests whether it is dealing with a Boolean object. expect(new Boolean(true)).toBe(true) would fail whereas expect(new Boolean(true)).toBeTrue() would pass. This is because of this funny thing:
> new Boolean(true) === true
false
> new Boolean(true) === false
false
At least it is truthy:
> !!new Boolean(true)
true
Which is best suited for use with elem.isDisplayed()?
Ultimately Protractor hands off this request to Selenium. The documentation states that the value produced by .isDisplayed() is a promise that resolves to a boolean. I would take it at face value and use .toBeTrue() or .toBe(true). If I found a case where the implementation returns truthy/falsy values, I would file a bug report.

Disclamer: This is just a wild guess
I know everybody loves an easy-to-read list:
toBe(<value>) - The returned value is the same as <value>
toBeTrue() - Checks if the returned value is true
toBeTruthy() - Check if the value, when cast to a boolean, will be a truthy value
Truthy values are all values that aren't 0, '' (empty string), false, null, NaN, undefined or [] (empty array)*.
* Notice that when you run !![], it returns true, but when you run [] == false it also returns true. It depends on how it is implemented. In other words: (!![]) === ([] == false)
On your example, toBe(true) and toBeTrue() will yield the same results.

In javascript there are trues and truthys. When something is true it is obviously true or false. When something is truthy it may or may not be a boolean, but the "cast" value of is a boolean.
Examples.
true == true; // (true) true
1 == true; // (true) truthy
"hello" == true; // (true) truthy
[1, 2, 3] == true; // (true) truthy
[] == false; // (true) truthy
false == false; // (true) true
0 == false; // (true) truthy
"" == false; // (true) truthy
undefined == false; // (true) truthy
null == false; // (true) truthy
This can make things simpler if you want to check if a string is set or an array has any values.
var users = [];
if(users) {
// this array is populated. do something with the array
}
var name = "";
if(!name) {
// you forgot to enter your name!
}
And as stated. expect(something).toBe(true) and expect(something).toBeTrue() is the same. But expect(something).toBeTruthy() is not the same as either of those.

As you read through the examples below, just keep in mind this difference
true === true // true
"string" === true // false
1 === true // false
{} === true // false
But
Boolean("string") === true // true
Boolean(1) === true // true
Boolean({}) === true // true
1. expect(statement).toBe(true)
Assertion passes when the statement passed to expect() evaluates to true
expect(true).toBe(true) // pass
expect("123" === "123").toBe(true) // pass
In all other cases cases it would fail
expect("string").toBe(true) // fail
expect(1).toBe(true); // fail
expect({}).toBe(true) // fail
Even though all of these statements would evaluate to true when doing Boolean():
So you can think of it as 'strict' comparison
2. expect(statement).toBeTrue()
This one does exactly the same type of comparison as .toBe(true), but was introduced in Jasmine recently in version 3.5.0 on Sep 20, 2019
3. expect(statement).toBeTruthy()
toBeTruthy on the other hand, evaluates the output of the statement into boolean first and then does comparison
expect(false).toBeTruthy() // fail
expect(null).toBeTruthy() // fail
expect(undefined).toBeTruthy() // fail
expect(NaN).toBeTruthy() // fail
expect("").toBeTruthy() // fail
expect(0).toBeTruthy() // fail
And IN ALL OTHER CASES it would pass, for example
expect("string").toBeTruthy() // pass
expect(1).toBeTruthy() // pass
expect({}).toBeTruthy() // pass

There are a lot many good answers out there, i just wanted to add a scenario where the usage of these expectations might be helpful. Using element.all(xxx), if i need to check if all elements are displayed at a single run, i can perform -
expect(element.all(xxx).isDisplayed()).toBeTruthy(); //Expectation passes
expect(element.all(xxx).isDisplayed()).toBe(true); //Expectation fails
expect(element.all(xxx).isDisplayed()).toBeTrue(); //Expectation fails
Reason being .all() returns an array of values and so all kinds of expectations(getText, isPresent, etc...) can be performed with toBeTruthy() when .all() comes into picture. Hope this helps.

Related

Why Object not true? [duplicate]

This question already has answers here:
Which equals operator (== vs ===) should be used in JavaScript comparisons?
(48 answers)
Understanding JavaScript Truthy and Falsy
(9 answers)
Closed 2 years ago.
Why Object not true if checking consumer == true?
let consumer = {
"checked": true,
"ID": "680e543457-999fc-11e6",
"fio": "John Doe",
"office": {
"ID": "fgh4d"
},
"phone": ""
};
console.log('consumer == true', consumer == true); // false
console.log('consumer === true', consumer === true); // false
console.log('Boolean(consumer)', Boolean(consumer)); // true
console.log('!consumer', !consumer); // false
if (consumer) console.log('1') // 1
Objects can't be equal to boolean.
but you can check the property checked
console.log('consumer.checked == true', consumer.checked == true); // true
console.log('consumer.checked === true', consumer.checked === true); // true
console.log('!consumer.checked', !consumer.checked); // false
if (consumer.checked) console.log('1') // 1
Additional to #VLAZ answer you can check the consumer object for undefined which results in a boolean expression.
let consumer = {
"checked": true,
"ID": "680e543457-999fc-11e6",
"fio": "John Doe",
"office": {
"ID": "fgh4d"
},
"phone": ""
};
console.log('consumer != undefined', consumer != undefined); // true
console.log('consumer !== undefined', consumer !== undefined); // true
*edit: format
consumer == true
here consumer is object, and true is boolean. Since == operator converts both variable values into same type, even though values are different. So it is False.
for example if you compare 1 == '1' it will be true. but comparing object with boolean gonna be false only.
consumer === true.
=== does not do any type conversion (coercion) and returns true only if both values and types are identical for the two variables being compared.
for example, if you compare 1 === '1' it will be false. it will be true if you compare 1 === 1. But in your case, object definitely false if you compare with boolean.
!consumer
Basically Not operator(!) reverses the boolean result of the operand. consumer holds an object, so boolean result of the operand will be true. Not operator reverses it. so it is false.
Consumer holds an object. so It will be True. so that If condition says True. Even consumer holds empty object({}) it will be True only. because it has own property.
var a = {};
a.hasOwnProperty
In JS the == and === do not mean the same. When you use == you check if the element is equal to, however the === checks if the element is equal to and the same type as the element you are comparing it with
exsample:
1 === 1 // true
"1" === 1 // false
"1" == 1 // true
1 == 1 // true
However what you are doning when typing !consumer is that you are checking if the element exists (and is not undefined, NaN or Null)
Thanks to everyone, i found what I needed, may be it would be helpful for enyone. As MDN web docs says
Do not confuse the primitive Boolean values true and false with the
true and false values of the Boolean object.
And also:
The value passed as the first parameter is converted to a boolean
value, if necessary. If the value is omitted or is 0, -0, null, false,
NaN, undefined, or the empty string (""), the object has an initial
value of false. All other values, including any object, an empty array
([]), or the string "false", create an object with an initial value of
true.
So
Boolean(consumer) // true
Your consumer isn't a boolean, so it's not equal to true.
Looks like you want to see if the value is truthy of falsy.
!consumer checks if the value is falsy.
You can do this process again:
!!consumer checks if the value is truthy.
More info about understanding truthy and falsy values in javascript

Why does an empty array map to different boolean values in different contexts? [duplicate]

Empty arrays are true but they're also equal to false.
var arr = [];
console.log('Array:', arr);
if (arr) console.log("It's true!");
if (arr == false) console.log("It's false!");
if (arr && arr == false) console.log("...what??");
I guess this is due to the implicit conversion operated by the equality operator.
Can anyone explain what's going on behind the scenes?
You're testing different things here.
if (arr) called on object (Array is instance of Object in JS) will check if the object is present, and returns true/false.
When you call if (arr == false) you compare values of this object and the primitive false value. Internally, arr.toString() is called, which returns an empty string "".
This is because toString called on Array returns Array.join(), and empty string is one of falsy values in JavaScript.
Regarding the line:
if (arr == false) console.log("It's false!");
Maybe these will help:
console.log(0 == false) // true
console.log([] == 0) // true
console.log([] == "") // true
What I believe is happening is that the boolean false is coerced to 0 for comparison with an object (the left-hand side). The object is coerced to a string (the empty string). Then, the empty string is coerced into a number, as well, namely zero. And so the final comparison is 0 == 0, which is true.
Edit: See this section of the spec for details on exactly how this works.
Here's what's happening, starting at rule #1:
1. If Type(x) is different from Type(y), go to step 14.
The next rule that applies is #19:
19. If Type(y) is Boolean, return the result of the comparison x ==
ToNumber(y).
The result of ToNumber(false) is 0, so we now have:
[] == 0
Again, rule #1 tells us to jump to step #14, but the next step that actually applies is #21:
21. If Type(x) is Object and Type(y) is either String or Number, return the
result of the comparison
ToPrimitive(x)== y.
The result of ToPrimitive([]) is the empty string, so we now have:
"" == 0
Again, rule #1 tells us to jump to step #14, but the next step that actually applies is #17:
17. If Type(x) is String and Type(y) is Number, return the result of the
comparison ToNumber(x)== y.
The result of ToNumber("") is 0, which leaves us with:
0 == 0
Now, both values have the same type, so the steps continue from #1 until #7, which says:
7. If x is the same number value as y, return true.
So, we return true.
In brief:
ToNumber(ToPrimitive([])) == ToNumber(false)
To supplement Wayne's answer and to try to explain why ToPrimitive([]) returns "", it's worth considering two possible types of answers to the 'why' question. The first type of answer is: "because the specification says this is how JavaScript will behave." In the ES5 spec, section 9.1, which describes the result of ToPrimitive as a default value for an Object:
The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType.
Section 8.12.8 describes the [[DefaultValue]] method. This method takes a "hint" as an argument, and the hint can be either String or Number. To simplify the matter by dispensing with some details, if the hint is String, then [[DefaultValue]] returns the value of toString() if it exists and returns a primitive value and otherwise returns the value of valueOf(). If the hint is Number, the priorities of toString() and valueOf() are reversed so that valueOf() is called first and its value returned if it's a primitive. Thus, whether [[DefaultValue]] returns the result of toString() or valueOf() depends on the specified PreferredType for the object and whether or not these functions return primitive values.
The default valueOf() Object method just returns the object itself, which means that unless a class overrides the default method, valueOf() just returns the Object itself. This is the case for Array. [].valueOf() returns the object [] itself. Since an Array object is not a primitive, the [[DefaultValue]] hint is irrelevant: the return value for an array will be the value of toString().
To quote David Flanagan's JavaScript: The Definitive Guide, which, by the way, is a superb book that should be everyone's first place to get answers to these types of questions:
The details of this object-to-number conversion explain why an empty array converts to the number 0 and why an array with a single element may also convert to a number. Arrays inherit the default valueOf() method that returns an object rather than a primitive value, so array-to-number conversion relies on the toString() method. Empty arrays convert to the empty string. And the empty string converts to the number 0. An array with a single element converts to the same string that that one element does. If an array contains a single number, that number is converted to a string, and then back to a number.
The second type of answer to the "why" question, other than "because the spec says", gives some explanation for why the behavior makes sense from the design perspective. On this issue I can only speculate. First, how would one convert an array to a number? The only sensible possibility I can think of would be to convert an empty array to 0 and any non-empty array to 1. But as Wayne's answer revealed, an empty array will get converted to 0 for many types of comparisons anyway. Beyond this, it's hard to think of a sensible primitive return value for Array.valueOf(). So one could argue that it just makes more sense to have Array.valueOf() be the default and return the Array itself, leading toString() to be the result used by ToPrimitive. It just makes more sense to convert an Array to a string, rather than a number.
Moreover, as hinted by the Flanagan quote, this design decision does enable certain types of beneficial behaviors. For instance:
var a = [17], b = 17, c=1;
console.log(a==b); // <= true
console.log(a==c); // <= false
This behavior allows you to compare a single-element array to numbers and get the expected result.
console.log('-- types: undefined, boolean, number, string, object --');
console.log(typeof undefined); // undefined
console.log(typeof null); // object
console.log(typeof NaN); // number
console.log(typeof false); // boolean
console.log(typeof 0); // number
console.log(typeof ""); // string
console.log(typeof []); // object
console.log(typeof {}); // object
console.log('-- Different values: NotExist, Falsy, NaN, [], {} --');
console.log('-- 1. NotExist values: undefined, null have same value --');
console.log(undefined == null); // true
console.log('-- 2. Falsy values: false, 0, "" have same value --');
console.log(false == 0); // true
console.log(false == ""); // true
console.log(0 == ""); // true
console.log('-- 3. !NotExist, !Falsy, and !NaN return true --');
console.log(!undefined); // true
console.log(!null); // true
console.log(!false); // true
console.log(!""); // true
console.log(!0); // true
console.log(!NaN); // true
console.log('-- 4. [] is not falsy, but [] == false because [].toString() returns "" --');
console.log(false == []); // true
console.log([].toString()); // ""
console.log(![]); // false
console.log('-- 5. {} is not falsy, and {} != false, because {}.toString() returns "[object Object]" --');
console.log(false == {}); // false
console.log({}.toString()); // [object Object]
console.log(!{}); // false
console.log('-- Comparing --');
console.log('-- 1. string will be converted to number or NaN when comparing with a number, and "" will be converted to 0 --');
console.log(12 < "2"); // false
console.log("12" < "2"); // true
console.log("" < 2); // true
console.log('-- 2. NaN can not be compared with any value, even if NaN itself, always return false --');
console.log(NaN == NaN); // false
console.log(NaN == null); // false
console.log(NaN == undefined); // false
console.log(0 <= NaN); // false
console.log(0 >= NaN); // false
console.log(undefined <= NaN); // false
console.log(undefined >= NaN); // false
console.log(null <= NaN); // false
console.log(null >= NaN); // false
console.log(2 <= "2a"); // false, since "2a" is converted to NaN
console.log(2 >= "2a"); // false, since "2a" is converted to NaN
console.log('-- 3. undefined can only == null and == undefined, and can not do any other comparing even if <= undefined --');
console.log(undefined == null); // true
console.log(undefined == undefined); // true
console.log(undefined == ""); // false
console.log(undefined == false); // false
console.log(undefined <= undefined); // false
console.log(undefined <= null); // false
console.log(undefined >= null); // false
console.log(0 <= undefined); // false
console.log(0 >= undefined); // false
console.log('-- 4. null will be converted to "" when <, >, <=, >= comparing --');
console.log(12 <= null); // false
console.log(12 >= null); // true
console.log("12" <= null); // false
console.log("12" >= null); // true
console.log(0 == null); // false
console.log("" == null); // false
console.log('-- 5. object, including {}, [], will be call toString() when comparing --');
console.log(12 < {}); // false, since {}.toString() is "[object Object]", and then converted to NaN
console.log(12 > {}); // false, since {}.toString() is "[object Object]", and then converted to NaN
console.log("[a" < {}); // true, since {}.toString() is "[object Object]"
console.log("[a" > {}); // false, since {}.toString() is "[object Object]"
console.log(12 < []); // false, since {}.toString() is "", and then converted to 0
console.log(12 > []); // true, since {}.toString() is "", and then converted to 0
console.log("[a" < []); // false, since {}.toString() is ""
console.log("[a" > []); // true, since {}.toString() is ""
console.log('-- 6. According to 4 and 5, we can get below weird result: --');
console.log(null < []); // false
console.log(null > []); // false
console.log(null == []); // false
console.log(null <= []); // true
console.log(null >= []); // true
In if (arr), it is always evaluated (ToBoolean) to true if arr is an object because all objects in JavaScript are truthy. (null is not an object!)
[] == false is evaluated in iterative approach. At first, if one side of == is primitive and the other is object, it converts object to primitive at first, then converts both sides to Number if both sides are not string (string comparison is used if both sides are strings). So the comparison is iterated like, [] == false -> '' == false -> 0 == 0 -> true.
Example:
const array = []
const boolValueOfArray = !!array // true
It happens because
ToNumber(ToPrimitive([])) == ToNumber(false)
[] is empty Array object → ToPrimitive([]) → "" → ToNumber("") → 0
ToNumber(false) → 0
0 == 0 → true
An array with elements (regardless if 0, false or another empty array), always resolves to true using Abstract Equality Comparison ==.
1. [] == false; // true, because an empty array has nothing to be truthy about
2. [2] == false; // false because it has at least 1 item
3. [false] == false; // also false because false is still an item
4. [[]] == false; // false, empty array is still an item
But using a Strict Equality Comparison ===, you are attempting to evaluate the variable's content as well as its data type that is why:
1. [] === false; // false, because an array (regardless of empty or not) is not strictly comparable to boolean `false`
2. [] === true; // false, same as above, cannot strictly compare [] to boolean `true`
3. [[]] === false; // true, because see #1
It seems no one is talking about why
(arr && arr == false) is true. Just for people who are not sure about the operator precedence, accourding to MDN, == has higher precedence than &&, so it is actually (arr && (arr == false)). After wildcard's answer , it's true && true, so it's true.
var arr = [];
if (arr && arr == false) console.log("...what??");
You can empty a JavaScript Array by referencing it to a new array, using list = [] or deleting the elements of the currently referenced array list.length = 0.
Source: JavaScript Empty Array
None of the above helped me, when trying to use the knockout.js mapping plugin, perhaps since an "empty array" isn't really empty.
I ended up using: data-bind="if: arr().length" which did the trick.
This is specific to knockout, not the OP's question, but maybe it will help someone else browsing here in a similar situation.

How does angular.equals evaluate invalid date objects?

I understand that I shouldn't be using invalid date objects to compare with each other, but for purposes of understanding how and why angular.equal handles something like
angular.equals(new Date(''), new Date('')); //returns false, both objects are null
on the other hand
angular.equals(null, null); //returns true
What am I missing here? JSfiddle if you feel the need
If you are using angular <1.2.x you will see that behavior. Because .equals implementation only checks for equality of p1.getTime() and p2.getTime() which in this case is NaN and NaN is not NaN. But 1.2.x onwards that has been changed as there is a recursive check again on the .equals and there is a condition:
if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
Which you will see the value returning true in that case.
>=1.2.x
else if (isDate(o1)) {
if (!isDate(o2)) return false;
return equals(o1.getTime(), o2.getTime()); //returns false
}
<1.2.x
else if (isDate(o1)) {
return isDate(o2) && o1.getTime() == o2.getTime(); //returns true
}

How can I check if a variable is not null and also a number?

I am using the following:
$scope.option.selectedSubject != null && !isNaN($scope.option.selectedSubject)
Can someone tell me if there is another way to check if a variable is a valid defined number? Is there some way I can do this with just one check or how can I create a function to do this check and then call that ?
maybe this function might help you :
function isANumber(x) {
return ((+x)===x);
}
This might be useful to know: A variable can only be null when somewhere in your script it's being assigned, it will never be null by default.
var foo; // undefined
foo = null;
// null could be returned by a function too, which is the most common use of null
As zzzzBov stated in his comment, "isNaN will check if the numeric representation of the value is NaN. this means that isNaN('500') is false, while isNaN('foo') is true."
As to answer your question, check this table:
!isNaN(undefined); // false
!isNaN(null); // true
!isNaN(); // false
!isNaN(''); // true <= Watch out for this one !
!isNaN('test'); // false
!isNaN('10'); // true
!isNaN(10); // true
If you want to make sure it's a number, you should use typeof, then if this is a string, check if it has a length. Wrapping this all in a function would create something like:
function isNumber (num) {
// Return false if num is null or an empty string
if (num === null || (typeof num === "string" && num.length === 0)) {
return false;
}
return !isNaN(num);
}
isNumber(undefined); // false
isNumber(null); // false
isNumber(); // false
isNumber(''); // false
isNumber('test'); // false
isNumber('10'); // true
isNumber(10); // true
This would do the trick if you care only about numeric presentation.
!isNaN($scope.option.selectedSubject + "")
Notice the + ""

Perk in evaluation of Boolean variables in JavaScript?

I have this slightly peculiar situation, a boolean statement I have is giving me two different evaluations, in the alert and if operator.
var test = new Boolean(homePageNonActive && ((firstTime && homePageHash) || (!firstTime && !homePageHash)));
alert(homePageNonActive && ((firstTime && homePageHash) || (!firstTime && !homePageHash))); // GIVES ME FALSE
alert(test); // GIVES ME TRUE ??? WHY?
if(test){
alert(homePageNonActive); // GIVES ME TRUE
alert(firstTime); // GIVES ME TRUE
alert(homePageHash); // GIVES ME FALSE
}
Everything seems to work just fine as long as you use boolean primitives.
But the issue is that you are mixing Boolean objects (homePageHash) with boolean primitives (homePageNonActive and firstTime). The reason why test is "true" is because a "Boolean object false" is "truthy".
Boolean object is not the same as a boolean primitive.
Any object whose value is not undefined or null, including a Boolean object whose value is false, evaluates to true when passed to a conditional statement.
var x = new Boolean(false),
y = false;
if (x) {/*this code is executed*/}
if (y) {/*this code is NOT executed*/}

Categories

Resources