Unit and Integration tests for Angular components. Part 1 out of 3.
As application grows we ask ourselves how to structure the code so that it’s easier to understand and maintain. Unit tests sometimes also become the hell on Earth if you don’t define the clear vision on how they should be written.
Technological stack of our team is pretty usual I guess: Karma + Jasmine.
Both Karma and Jasmine are cool and nice to use, but there is one tool in our daily life that makes my heart melt — wallaby (https://wallabyjs.com/). You can read more about it on their website but shortly wallaby is an integrated test runner which provides instant feedback on your tests, so TDD in JavaScript has never been so easy. Another benefit of using wallaby is having constant feedback on the test coverage.
Wallaby updates the report instantly and gives you the detailed information on each file. Wonderful tool, definitely recommend!
There are 2 types of tests that developers normally write:
- unit tests: testing one thing at a time, tests should not care about the points of interaction between different units of the application
- integration tests: checking that multiples units are interacting with each other correctly
Unit tests for Angular components can be split into 2 categories:
- isolated tests: when we just test component functions.
- shallow unit tests: testing components template without rendering its children. It may be achieved by simply not registering child components inside of the TestBed function.
Now let’s talk about these types of tests in a little bit more details.
Isolated unit tests
Let’s assume we have following function in folder.component.ts
Its unit test where we are checking if the selectedFolder is set correctly will look smth like that:
In this case we don’t touch the template at all and concentrate only on the inner functionality of the component.
Shallow unit tests
Template shallow tests allow us to test Input() and Output() properties of child components.
testing input properties
Let’s assume we have the following simple folder-name.component.html that has a child <custom-inline-edit/> component in it.
Let’s test if the input property text is set correctly in the HTML template.
So we’ve inspected the child element to have special Angular attribute populated with the expected value.
testing output events
As we remember in the HTML of the folder-name.component.html we’ve had the Output() event (editConfirmed)
And here is the code of this event in folder-name.component.ts
To test the correct binding of the event and inner functionality we’ll use triggerEventHandler and pass there Output() property name:
When using this technique we’ll be able to proper unit test child bindings in the parent component.
Integration tests
Let’s test same functionality of populating <custom-inline-edit/> with one value and changing it into another withing one integration test.
Here we’ve accessed the input field inside of the child input component, changed its value and trigger Enter keyboard event so that Output() event (editConfirmed) was triggered.
That’s the difference for me between isolated unit tests, shallow unit tests and integration tests. Let’s see what is the proposed structure of tests by Angular team:
- component-name
- component-name.component.html
- component-name.component.ts
- component-name.component.spec.ts
So we have to fit into one single spec file:
- isolated unit tests
- shallow unit tests
- integration tests
Well, actually for components I would not write isolated tests at all. Imagine HTML template to be public method and the component to be inner private implementation. So we should write just shallow and integrations tests.
I personally don’t like big files so I would rather split integration and shallow tests into 2 different files with a shared configuration (we’ll talk about it later).
The questions that are still open for me:
- how deep integration tests should be?
- how to write tests DRY if keeping integration and unit tests separate?
To be continued…
Links that were helpful for me during this investigation:
Nice lecture by Julie Ralph: https://www.youtube.com/watch?v=f493Xf0F2yU
with the repository mentioned in the video: https://github.com/juliemr/angularconnect-2016/blob/master/src/app/game.spec.ts
Some of coding guidelines for testing of our team can be found here: https://github.com/advorkina/guide-to-javascript-unit-tests/blob/master/README.md