What is the difference between expect().toBe(true), expect().toBeTruthy() and expect().toBeTrue()?

To understand better the difference between these three Jasmine matchers – toBe(true) vs toBeTruthy() vs toBeTrue() – we have to check the source code, to see how they are implemented.

Let’s take them one by one, by showing you the definition and some basic examples.

expect.toBe()

Jasmin implementation for this matcher is:

getJasmineRequireObj().toBe = function () {
  function toBe() {
    return {
      compare: function (actual, expected) {
        return {
          pass: actual === expected
        };
      }
    };
  } return toBe;
};

The condition to pass the test is done with the non-converting comparison operator ===, which means that no conversion occurs. When the operands are of different types, the operator returns false, and only compares the values when they share the same type.

In this case expect(foo).toBe(true) passes only if foo has the value true.

Some examples using expect().toBe():

expect(true).toBe(true)      → PASS 
expect(false).toBeTrue()     → FAIL 
expect(‘true’).toBe(true)    → FAIL 
expect({true}).toBe(true)    → FAIL

expect().toBeTruthy()

Jasmin implementation for this matcher is:

getJasmineRequireObj().toBeTruthy = function () {
  function toBeTruthy() {
    return {
      compare: function (actual) {
        return {
          pass: !!actual
        };
      }
    };
  } return toBeTruthy;
};

The double exclamation !! operator is used (also known as not not operator, double negation, or double bang) which performs type coercion. It is important first to understand what this means so I will try to explain it shortly and give you some examples.

In JavaScript type coercion is the process of converting a value from one type to another ( string to number, object to boolean, etc). Here you can read more about basic JavaScript Type Conversion and JavaScript Expressions and Operators.

The not not operator converts a value to a boolean. A value will be truthy if the coercion of the value will return true. Everything that is not 0, “”, null, undefined, NaN or false is truthy.

"Foo"           → "foo"
!"foo"          → false
!!"foo"         → true
 
!!0             → false
!!""            → false
!!null          → false
!!undefined     → false
!!NaN           → false
!!false         → false
 
!!'false'       → true
!![1,2,3]       → true
!![]            → true
!!13            → true

expect().toBeTrue()

Is a custom matcher introduced in Jasmine-Matchers defined as:

function toBeTrue(actual) {
    return actual === true ||
        is(actual, 'Boolean') &&
        actual.valueOf();
}

It is similar with expect.toBe(true) with the difference that expect().toBeTrue() also tests if it’s dealing with a Boolean object, not only primitive values.

expect(new Boolean(true)).toBeTrue() → PASS
expect(new Boolean(true)).toBe(true) → FAIL

This happens because:

new Boolean(true)               → {true}
new Boolean(false)              → {false}
 
new Boolean(true) == true       → true
new Boolean(false) == true      → false
new Boolean(true) == false      → false
new Boolean(false) == false     → true
 
new Boolean(true) === true      → false
new Boolean(false) === true     → false
new Boolean(true) === false     → false
new Boolean(false) === false    → false
 
!!new Boolean(true)             → true

Conclusion

Do not confuse the primitive Boolean values true and false with the true and false values of the Boolean object. If you are dealing with Boolean objects then use expect().toBeTrue() custom matcher in your tests, otherwise stick with the plain old expect.toBe(true) matcher.

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *