Why Object not true? [duplicate] - javascript

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

Related

shortcut to check if variable is null || undefined||empty string||false

I am looking for check, if my variable is one of : null || undefined || empty string || false
Right now its look messy and long:
const userHasPhoneNumber = user.phone === undefined ||
user.phone === "" ||
user.phone === false ||
user.phone === null ? false : true;
Is there shortcut?
You can shortcut x === undefined || x === null to x == null. For the others, there is no shortcut as there are some falsy number values as well. You could however do
const userHasPhoneNumber = typeof user.phone == "number" || !!user.phone
If you coerce that string to a boolean then it should check all your conditions, which is pretty much checking if user.phone is truthy.
It depends how you want to use it. If you wanted to use it in a condition, i.e. if(userHasPhoneNumber) ... then you can use the string directly : if(user.phone) as it will coerce to a boolean.
If you really need to have a boolean variable then need to cast it to a boolean explicitely:
Either through
const userHasPhoneNumber = Boolean(user.phone);
or
const userHasPhoneNumber = !!user.phone;
Note, as #Bergi commented, that there are more values that are coerced to a false value (falsy values), for example NaN or the number 0 (the string "0" will coerce to true), so it depends what your input is. If it's never a number but either a string/boolean/null/undefined, it should be fine. Here is the list of all falsy values for reference : https://developer.mozilla.org/en-US/docs/Glossary/Falsy
Use JavaScript's !!, witch will become false for null, "", undefined and false:
const user = {
phone_1: null,
phone_2: "",
phone_3: undefined,
phone_4: false
};
console.log(!!user.phone_1); // false
console.log(!!user.phone_2); // false
console.log(!!user.phone_3); // false
console.log(!!user.phone_4); // false
Note Use this with caution as some results may be different then expected, this answer shows a complete list.

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.

Trying to delete a false property from an object

I'm trying to delete the object properties that don't evaluate to true. What am I doing wrong?
var object = {
obj1: NaN,
obj2: false,
obj3: "Don't delete",
obj4: "Please don't delete"
};
var onlyTruthy = function(object) {
for (var key in object) {
if (object[key] === false) {
delete object[key];
}
}
return(object)
};
For deleting all falsy properties, you could use just a check of the value.
if (!object[key]) {
delete object[key];
}
With your check object[key] === false, you perform a strict comparison with false. This means, the value is checked against the type (Boolean) and the same value. But you need - kind of - less. Just a check for a not truthy value.
Please keep in mind, that properties with value 0 are deleted too.
Working code:
var object = { obj1: NaN, obj2: false, obj3: "Don't delete", obj4: "Please don't delete" },
onlyTruthy = function (object) {
for (var key in object) {
if (!object[key]) {
delete object[key];
}
}
return object;
};
onlyTruthy(object);
console.log(object);
Just use if(!object[key]) for truth values without comparison with exact falsy values.
I'm trying to delete the object properties that don't evaluate to true. What am I doing wrong?
The problem is that you're using the "identity" or "strict equality" operator: === instead of the normal "equality" operator: ==. You aren't allowing the program to do any sort of finagling when you ask it "are these two things the same?".
Here's some examples:
1 == 1 // true
"1" == 1 // true
1 == '1' // true
0 == false // true
0 == null // false
0 == undefined // false
null == undefined // true
vs:
3 === 3 // true
3 === '3' // false!
When you write ... === false, the only time that will "evaluate to true" is when the variable is actually equal to false. It won't "evaluate to true" if the variable was null or undefined.
See this question for even more detail on the problem:
Which equals operator (== vs ===) should be used in JavaScript comparisons?
Just changing the === operator to == isn't going to solve things, either. You're going to have to more closely match the problem definition, and check if things don't evaluate to true.
This "evaluates to true" concept is so common in JS that they built it straight into their flow control statements, like if and while:
if (... something that evaluates to true ...) {
// ... do something
}
while (... something that evaluates to true ...) {
// ... do something
}
If you combine this with the logical not operator, then you can use this same "evaluates to true" check to find things that don't evaluate to true:
if (!object[key]) {
delete object[key];
}
This is the "right" way to do things in Javascript (or at least the most "canonical").
Due to discussions over delete performance, if just want to filter unwanted properties and don't mind to use a new variable this would be a good answer:
var object = { obj1: NaN, obj2: false, obj3: "Don't delete", obj4: "Please don't delete" },
result = {};
Object.keys(object).forEach(k => object[k] && (result[k] = object[k]));
console.log(result);

Logical NOT on Boolean Object always return false in Javascript [duplicate]

This question already has answers here:
Why does !new Boolean(false) equals false in JavaScript?
(2 answers)
Closed 6 years ago.
Why logical not operator in javascript returns different result between Boolean value and Boolean object? Consider the following example.
!true // false
!false // true
!(new Boolean(true)) // false
!(new Boolean(false)) // false
From the spec, it says that the value being evaluated converted ToBoolean. ToBoolean will return true if the argument is an Object, and return as is if the argument is a Boolean.
Digging further, ToBoolean also being used in other places like if statement and conditional operator, consider the following example:
var a = (new Boolean(false)) ? "unexpected" : "expected";
console.log(a); // unexpected
The question: is Boolean object an Object, or a Boolean? Should we not evaluate Boolean object as a Boolean?
UPDATE
My question was marked as duplicate question with this. That question doesn't have a satisfactory answers because none answers my question, Is Boolean object an Object, or a Boolean? Should we not evaluate Boolean object as a Boolean?
Simply knowing Boolean object is an object is not enough, why does it even exists and what is the proper way of dealing and/or designing objects with Boolean object still left unanswered.
An object, no matter if it has properties or not, never defaults to false...
new Boolean(true) will return an object not Boolean and !{} is always going to be false as {} is a truthy value (Boolean({}) will be evaluated as true)
While dealing with Boolean factory function, do not create new instance using new (as it will create new instance of Boolean and will return an object)
Boolean(INPUT) will return primitive-Boolean value of the specified expression which could be used for comparison
From docs, The Boolean object is an object wrapper for a boolean value()
Description: The value passed as the first parameter is converted to a boolean value, if necessary. If 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 or the string "false", create an object with an initial value of true.
Do not confuse the primitive Boolean values true and false with the true and false values of the Boolean object.
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."[Reference]
For example, the condition in the following if statement evaluates to true
var x = new Boolean("false");
if (x) {
console.log('x is true');
}
var y = new Boolean(false);
if (y) {
console.log('y is true');
}
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
Boolean is a function. Depending on the invocation type, it has different behavior in terms of truthy and falsy.
1. Invoking as a simple function
When calling Boolean(value) as a simple function, it verifies if the argument is a falsy (false, null, undefined, '', 0,Nan) or truthy (all other values: object instances, 1, true, etc). This type of invocation returns a boolean primitive type.
It works as expected:
Boolean(null) // prints false
Boolean(0) // prints false
Boolean({}) // prints true
Boolean(-1) // prints true
2. Invoking as a constructor
Like any function in JavaScript, Boolean can be invoked as a constructor: var b = new Boolean(value). This invocation type returns a boolean object instance.
This introduces confusing because JavaScript treats object instances as truthy value.
var b = new Boolean(null);
!!b // prints true, because b is an object instance
if (b) { // b evaluates to true
//executed code
}
2.1 Why invoking as a constructor is possible
JavaScript allows this constructor invocation to give developer a mechanism to preserve properties creation for a boolean. A primitive boolean type doesn't save properties assigned to it.
var booleanObject = new Boolean(null);
booleanObject.foo = 'bar'; // create a property
booleanObject.foo // prints 'bar'
var booleanPrimitive = false;
booleanPrimitive.foo = 'bar'; // create a property
booleanPrimitive.foo // prints undefined
2.2 How to make the Boolean object work
Nevertheless, new Boolean(value) has a mechanism to do comparison. Like any JavaScript object, it has a method valueOf(), which returns the transformation of the value to a boolean primitive type (true for truthy and false for falsy):
var falsyBoolean = new Boolean(null);
falsyBoolean.valueOf() // prints false, because null is falsy
var truthyBoolean = new Boolean(1);
truthyBoolean.valueOf() // prints true, because 1 is truthy
To make this work in conditionals, it is necessary to avoid any transformations of the boolean object instance into a truthy value. To make this happen, use comparison operator == directly:
var falsyBoolean = new Boolean(null);
falsyBoolean == false ? 'falsy' : 'truthy' // prints expected 'falsy'
if (falsyBoolean == false) {
//executed code
}
If an operand in == operator is an object and other a primitive type, JavaScript transforms it into a primitive type, which actually consists in calling the valueOf() method on the boolean object. See more details in this article.
3. How not to get confused
The best rule is to avoid using Boolean as object instances at all. Boolean(value) or !!value is enough to verify the variable truthy state.
From MDN's entry on Boolean:
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.
For example, the condition in the following if statement evaluates to true:
var x = new Boolean("false");
if (x) {
// this code is executed
}
var y = new Boolean(false);
if (y) {
// this code is also executed
}
You will get same result for true and false parameters when using new Boolean(...)
Object-Oriented JavaScript Book, Stoyan Stefanov:
You can convert any value to its Boolean equivalent using a double negation.
Understanding how any value converts to a Boolean is important. Most values
convert to true with the exception of the following, which convert to false
"" null undefined 0 NaN false
So !!{}, !!new Boolean(true), !!new Boolean(false) return always true
This condition (without double negation):
if (new Boolean(true) === true) {
console.log('this string will never be printed');
}
returns false, because there are different types:
typeof new Boolean(true); // "object"
typeof true; // "boolean"
You have to compare them only by value to get an expected result:
if (new Boolean(true) == true) {
console.log('Yay!');
}
new Boolean(true) == true; // true
new Boolean(true) === true; // false
Another example:
if (new Boolean(true) === new Boolean(true)) {
console.log('this string will never be printed')
}
In this case you are trying to compare objects. You will get the same result both with == and === compare operators.
Object-Oriented JavaScript Book, Stoyan Stefanov: When you compare objects, you'll get true only if you compare two
references to the same object. Comparing two distinct objects that
happen to have the exact same methods and properties returns false.
Do not use a Boolean object new Boolean(...) in place of a Boolean primitive.
Just tried out the folliwng:
alert(typeof true); //alerts boolean
alert(typeof new Boolean(true)); //alert object
alert(typeof !(new Boolean(true))); //alerts boolean
alert(!(new Boolean(true))); //alerts false
Both Rayon and Mukul are right, you just need to use !Boolean(false) //returns true as a boolean value.

toBe(true) vs toBeTruthy() vs toBeTrue()

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.

Categories

Resources