Search code examples
javascripttestingjasmineprotractorjasmine-matchers

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();

Solution

  • 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.