256

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();
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • 4
    i thinks `.toBe(true)`==`.toBeTrue()`. toBeTruthy() can be true not only upon _true_, but upon _123_, "dfgdfg", [1,2,3], etc... basically `if(x==true)` are truthy, while `if(x===true)` are true true. – dandavis Sep 16 '15 at 18:14
  • 3
    That will depend on what the value you are testing is. Use `toBeTruthy` if you are unsure of the type it is the same as `== true` while I suspect `.toBe(true)` is the same as `=== true` Mind you its a little overboard to call a function to test for true. Word of advice,. Forget `==` and `!=` exists in Javascript and never use it again. Truthy is not needed and a trap for beginers. Use `===` and `!==` instead. – Blindman67 Sep 16 '15 at 18:20
  • @Blindman67 thanks for the advice, it makes perfect sense. We even have `eslint` reporting us if `==` or `!=` are used suggesting to change it to `===` and `!==`. – alecxe Sep 23 '15 at 12:33

5 Answers5

326

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.

Community
  • 1
  • 1
Louis
  • 146,715
  • 28
  • 274
  • 320
40

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.

Ismael Miguel
  • 4,185
  • 1
  • 31
  • 42
  • An empty array is falsey. – micah Sep 16 '15 at 18:18
  • @MicahWilliamson Thanks! Fixed the answer – Ismael Miguel Sep 16 '15 at 18:19
  • 3
    empty arrays are 100% truthy in JS `alert(!![])` – dandavis Sep 16 '15 at 18:20
  • @dandavis `[] == true` in your console produces `false`. `[] == false` in you console produces `true` – micah Sep 16 '15 at 18:21
  • @MicahWilliamson: that's because your'e comparing the string version of the array (empty string) to true. it can be confusing... – dandavis Sep 16 '15 at 18:23
  • @dandavis The results would be the same – micah Sep 16 '15 at 18:25
  • Fixed the answer now. – Ismael Miguel Sep 16 '15 at 18:28
  • @IsmaelMiguel Not sure what you mean by the note in your asterisk. `true (true)`, `!true (false)`, `!!true (true)`. I don't think it's a different implementation- it follows the same rules. – micah Sep 16 '15 at 18:31
  • @MicahWilliamson What I'm saying is that `(!![]) === ([] == false)`. – Ismael Miguel Sep 16 '15 at 18:32
  • @Downvoters - Please, explain **why!?** the downvotes so I can fix my answer accordingly. – Ismael Miguel Oct 05 '15 at 14:03
  • @kjhughes You are almost 5 years late. The answer will stay untouched. – Ismael Miguel Feb 06 '20 at 15:43
  • 1
    Your [comment asked](https://stackoverflow.com/questions/32615713/tobetrue-vs-tobetruthy-vs-tobetrue#comment53725821_32615835) why you were being downvoted. Thought you might still appreciate an explanation (don't post "wild guesses"). Anyway, at this point, keep in mind that answers are arguably more for future readers than for original askers, so it's never too late to improve your answer from "just a wild guess" to a definitive answer. – kjhughes Feb 06 '20 at 15:52
28

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.

micah
  • 7,596
  • 10
  • 49
  • 90
  • 2
    `[] == false;` is not correct, the statement itself is false because objects are always truthy – dandavis Sep 16 '15 at 18:21
  • @dandavis Not true. Objects aren't always truthy. But that statement `[] == false;` is `true` – micah Sep 16 '15 at 18:24
  • ok, you got me, let me correct myself. built-in object besides _null_ are always truthy... `[]` is truthy though. – dandavis Sep 16 '15 at 18:26
  • @dandavis Yes. Not sure why arrays are treated differently- perhaps it's the string explanation you made. Either way it's pretty useful – micah Sep 16 '15 at 18:27
  • 2
    no, it's not useful, just the opposite in fact: it's a noob gotcha... consider `[""]==false` or `[0]== false`; not empty, not falsey, just deceptive... – dandavis Sep 16 '15 at 18:29
  • Interesting. Probably should stick to `if(users.length)` then – micah Sep 16 '15 at 18:32
  • 3
    Using `x == true` as you have in your examples is a misleading and, as the above comments show, incorrect way to illustrate the concept of truthiness in JavaScript. The real test of truthiness in JavaScript is how a value behaves in an `if` statement or as an operand in a boolean expression. We know `1` is truthy because `if (1)` will cause the next statement to be evaluated. Likewise `[]` is truthy for the same reason: Even though `[] == true` evaluates to `false`, `if ([])` will still cause the next statement to be evaluated, so we know `[]` is truthy. – Jordan Running Sep 28 '15 at 03:16
  • You should use === to compare, not ==, so I don't believe your example to be trustworthy. – Sanjay Mar 26 '21 at 03:22
8

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
Sergey Pleshakov
  • 7,964
  • 2
  • 17
  • 40
3

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.

giri-sh
  • 6,934
  • 2
  • 25
  • 50
  • Nice! I remember `reduce()`-ing the array of booleans into a single value and then applying the `toBe(true)` check. This is much simpler, thank you. – alecxe Jan 06 '16 at 13:26