For primitive types (e.g. numbers, booleans, strings, etc.), there is no difference between toBe
and toEqual
; either one will work for 5
, true
, or "the cake is a lie"
.
To understand the difference between toBe
and toEqual
, let's imagine three objects.
var a = { bar: 'baz' },
b = { foo: a },
c = { foo: a };
Using a strict comparison (===
), some things are "the same":
> b.foo.bar === c.foo.bar
true
> b.foo.bar === a.bar
true
> c.foo === b.foo
true
But some things, even though they are "equal", are not "the same", since they represent objects that live in different locations in memory.
> b === c
false
Jasmine's toBe
matcher is nothing more than a wrapper for a strict equality comparison
expect(c.foo).toBe(b.foo)
is the same thing as
expect(c.foo === b.foo).toBe(true)
Don't just take my word for it; see the source code for toBe.
But b
and c
represent functionally equivalent objects; they both look like
{ foo: { bar: 'baz' } }
Wouldn't it be great if we could say that b
and c
are "equal" even if they don't represent the same object?
Enter toEqual
, which checks "deep equality" (i.e. does a recursive search through the objects to determine whether the values for their keys are equivalent). Both of the following tests will pass:
expect(b).not.toBe(c);
expect(b).toEqual(c);
Hope that helps clarify some things.
You are on the good road to understand all of it.
- Ng test (Jasmine + Angular Testing Utilities tests launched through Karma):
You are using the jasmine framework to write your tests and define them as suites and expect results that you can test, but the main thing is that you are actually using the karma launcher to execute tests directly on the browser. This is normaly configured in the angular app.
This means there is one server running the tests and that's it. You test with your own values and check that your components are working correctly.
The aim is to check for single components (unit test) or several modules / components (integration tests) that a single function / small workflow is working correctly as intended without side effects.
- Ng E2E (Jasmine + Protractor) :
Protractor is an end-to-end test framework for Angular and AngularJS
applications. Protractor runs tests against your application running
in a real browser, interacting with it as a user would.
Here, the tests you have written will act as a user. This means there is your application running in your browser, and another program will run the tests against your application, simulating a user interaction.
This is very important, because that means two things :
- Unit tests and Integration tests are using static, mock data to run the tests.
- Protractor tests are using real data, and doing the HTTP (or whatever you are using) calls to fetch the data and consume/test it.
The aim with protractor is to validate a full operationnal workflow in your application. For example, I'll write my unit test for my login component, write an unit test for my login service, write an integration test for my whole module and whatever behavior I need to test that depends on several components / services. Once this is done, I'll write later a full end-to-end test that will validate my whole authentication process in my application.
Bear in mind, there is a ratio that is important about testing which is very logical :
- Unit tests should represent 70% of your tests.
- Integration tests should represent 20% of your tests.
- E2E tests should represent 10% of your tests.
Why is that ? Because if you did unit test correctly a lot of your components, you won't need to test that again in your End-to-End tests.
Conclusion :
- They operate differently and their aim is to test different things (unit function / full workflow).
- They are complementary, which means that if you only realize Unit / Integration tests, you will never have the guarantee that a workflow will work from A to Z; as well as if you only write E2E tests you will never be able to confirm that there are no side-effects in your workflow.
N.B. : Be also aware of those points :
- Jasmine, Karma, and Protractor can be customized at will, so you can make them output in an XML file that could be processed by a Jenkins job instead of a command line which is not practical.
- Yes, you can write the same code for both and effectively test the same thing, but bear in mind that what you want is to be efficient and write maintanable test code. The ratios I talked about are very important.
Hope this helps.
Best Answer
What I do when I wonder something like the question asked here is go to the source.
toBe()
expect().toBe()
is defined as:It performs its test with
===
which means that when used asexpect(foo).toBe(true)
, it will pass only iffoo
actually has the valuetrue
. Truthy values won't make the test pass.toBeTruthy()
expect().toBeTruthy()
is defined as: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 toexpect
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 likeWhereas using
!!
yields:(Yes, empty or not, an array is truthy.)
toBeTrue()
expect().toBeTrue()
is part of Jasmine-Matchers (which is registered on npm asjasmine-expect
after a later project registeredjasmine-matchers
first).expect().toBeTrue()
is defined as:The difference with
expect().toBeTrue()
andexpect().toBe(true)
is thatexpect().toBeTrue()
tests whether it is dealing with aBoolean
object.expect(new Boolean(true)).toBe(true)
would fail whereasexpect(new Boolean(true)).toBeTrue()
would pass. This is because of this funny thing:At least it is truthy:
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 aboolean
. 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.