Angular Components Unit Test – Common Use Cases
Tags: angular, testing, webdev, typescript
Published: 2021-02-18 22:16:41

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](#text-interpolation)
* [User Input Value Change](#user-input-value-change)
* [Clicking HTML Element] (#clicking-html-element)
* [Access Child (nested) Component] (#access-child-component)
* [Content projection] (#content-projection)
* [Component inputs and outputs] (#component-input-output)
* [Component Dependencies] (#component-dependencies)
 

For this purpose lets assume we have the following simple example component generated using Angular CLI ng g c ExampleComponent:

{% gist https://gist.github.com/NicholaAlkhouri/4cc7cf0536c642ecffb4343df4a324fe.js %}


<p>A very basic component consists of one input <code>header</code> and one property <code>name</code> displayed in the template using a direct interpolation, a form with one input field and a submit button and one output <code>nameChange</code> which will emit an event when the user submits the form.</p>

<p>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 <code>let fixture: ComponentFixture;</code>. If you don't use Angular CLI to generate your component file, you may copy the above file in your project, and replace <code>ExampleComponent</code> with your component class name.</p>

<hr />

##Text interpolation: <a name="text-interpolation"></a>

<p>Here we make sure that our component will bind the correct values in the template. Don't forget to call <code>fixture.detectChanges()</code> which forces the TestBed to perform data binding and update the view.</p>

{% gist https://gist.github.com/NicholaAlkhouri/f43e571eb9a72c8dacddaf4b818528c3.js %}

<hr />
##User Input Value Change: <a name="user-input-value-change"></a>

<p>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.</p>

{% gist https://gist.github.com/NicholaAlkhouri/07f7016ff8c51471102a6438bfcbc771.js %}

<hr />
##Clicking HTML Element: <a name="clicking-html-element">

{% gist https://gist.github.com/NicholaAlkhouri/5849021558d8a6592a2dc8be07c48d59.js %}


<hr />
##Access Child (nested) Component: <a name="access-child-component"></a>

<p>Lets assume that our component contains a nested child component: </p>

<pre class="wp-block-code"><code>&lt;app-nested-component&gt;&lt;/app-nested-component&gt;</code></pre>

<p>You can access the child component and interact it as the following:</p>

{% gist https://gist.github.com/NicholaAlkhouri/7453c8bd1ce49401c76bed849cba9c82.js %}

<hr/>

##Content projection: <a name="content-projection"></a>

<p>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</p>


<pre class="wp-block-code"><code>&lt;div class="projected-content&gt; 
    &lt;ng-content select="&#91;description]"&gt;&lt;/ng-content&gt;
&lt;/div&gt;</code></pre>

<p>And we can test is by adding a wrapper <code>ExampleWrapperComponent</code> as the following:</p>

{% gist https://gist.github.com/NicholaAlkhouri/8f88362e80307c09fa964846ce6c6b1a.js %}

<hr/>
##Component inputs and outputs: <a name="component-input-output"></a>

<p>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.</p>

{% gist https://gist.github.com/NicholaAlkhouri/b1fc3a3aa4eb63df987bbd8621d07819.js %}

<hr/>

##Component Dependencies: <a name="component-dependencies"></a>

<p> 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:</p>

<h3>Dependencies provided in the root injector:</h3>

<p>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:</p>

{% gist https://gist.github.com/NicholaAlkhouri/c301ba395db3db3cda5f049f22f80c46.js %}

<p>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 <code>inject</code> method of the <code>TestBed</code>.</p>

<h3>Dependencies provided in the component injector:</h3>

<p>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.</p>

{% gist https://gist.github.com/NicholaAlkhouri/13ddf1a8c9d96c3b7de9cc524bf9197b.js %}

<hr/>

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 :)