In this article, I will provide a collection of some important statements used to unit test angular components. You can use any of the following examples directly in your project, or you may prefer to extract some of them into separate helper functions and reuse them all over your project. This article covers testing the following scenarios:
- Text interpolation
- User Input Value Change
- Clicking HTML Element
- Access Child (nested) Component
- Content projection
- Component inputs and outputs
- Component Dependencies
For this purpose lets assume we have the following simple example component generated using Angular CLI ng g c ExampleComponent:
A very basic component consists of one input
header and one property
name displayed in the template using a direct interpolation, a form with one input field and a submit button and one output
nameChange which will emit an event when the user submits the form.
When you create the above component using Angular CLI you will get automatically a unit test file in the same directory as your component. All the next sections in this article are based on this file, especially the fixture object
let fixture: ComponentFixture;. If you don't use Angular CLI to generate your component file, you may copy the above file in your project, and replace
ExampleComponent with your component class name.
Here we make sure that our component will bind the correct values in the template. Don't forget to call
fixture.detectChanges() which forces the TestBed to perform data binding and update the view.
Here we test that the user interaction with the text input is reflected correctly into our component class. Notice here the use of fakeAsync and tick, because the forms binding involves some asynchronous execution.
Lets assume that our component contains a nested child component:
You can access the child component and interact it as the following:
Testing content projection is not straightforward, to do so we need to add a wrapper component around the component being tested and use this wrapper component to pass content through projection. Let's add the following projected content to the view of our component
<div class="projected-content> <ng-content select="[description]"></ng-content> </div>
And we can test is by adding a wrapper
ExampleWrapperComponent as the following:
You can test component input similar to any normal component property. on the other hand the outputs can be spied on and check if it emits the correct value.
Components usually have dependencies (services) that help the component to function correctly, and the component needs to interact with these dependencies. When testing a component we need to provide our tests with those dependencies in order to run correctly. Here we need to distinguish between two way of providing a dependency:
Dependencies provided in the root injector:
When the component has a dependency on a service that is provided in the root injector, you need to provide this service to the TestBed configuration to be available to the component while running the tests:
Notice that we are using a mock service here since it is easier and safer to interact with. After that, you will be able to access that service in your tests by calling the
inject method of the
Dependencies provided in the component injector:
When you have a dependency provided in your component, you can not access it using the TestBed, since it will be available only on the component level of the injection tree. In this case, we need to override the component providers to provide this dependency, and then you can use the component injector to access it.
Do you have or need a specific testing scenario that is not covered by this article? Feel free add it in the comments sections and we will add a use case for you :)