Angular Testing - A Simple Strategy
Published: 2022-01-15 23:22:53

In this post I share a unit and integration testing strategy that makes it simple writing test cases for Angular SPAs. Conventionally, unit testing an Angular SPA involves unit testing all the components, services, etc. In the suggested strategy the navigation flow of the various view states of an SPA is considered as a set of state transitions where each transition has one action method. If all the business rules for a given transition is encapsulated in this one action method then unit testing involves testing just one method for a given transition. Each state transition is unit and integration tested. So in this strategy we achieve "Transitions Coverage" instead of "Code Coverage".

Consider a UI requirement like - when a route `/products` is accessed the application should display a list of products for the signed in user who has the eligible role to view the list of products. 

Conventionally, Angular code for the above requirements is distributed in several Angular Typescript artifacts like: 

1. A `ProductsComponent` calls a `ProductsService` and displays the list of products.
2. An `AuthenticationGuard` ensures that the user is signed in and
3. A `RoleGuard` ensures that the user has the required role to view the list of products.

So writing unit tests to cover these multiple components to assert the requirements gets involved and time consuming. 

The simple strategy suggests first writing the requirements as a set of state transitions.

The state transition for the requirements stated above can be written like:

`HOME > products > processPoducts() > productsSuccess > PRODUCTS`

where HOME and PRODUCTS are the initial and final states of the application, products and productsSuccess are the pre and post events and `processPoducts()` is the action that performs the transition. If we encapsulate all the business rules like getting the products list from the service, checking whether the user is signed in etc. in this one function - `processProducts()` then this function can then be unit tested easily. In this approach the `ProductsComponent` just receives the data and displays it which can then be easily tested in the e2e integration testing. Interestingly, it turns out that, in this strategy when all the transitions are written up for an SPA, unit testing all the process functions boils down to unit testing just one function called `doTransition()` with various input data for each transition! This feature enables writing unit tests fairly quickly.

The implementation details of the above technique for a small SPA with three views can be found in [GitHub](https://github.com/mapteb/framework-for-angular-development/tree/starter-example). Unit tests for all the state transitions are in just one file [`test-state-transitions.spec.ts`](https://github.com/mapteb/framework-for-angular-development/blob/starter-example/src/app/test/test-state-transitions.spec.ts) (Note that the only method tested is `doTransition()` in all the test cases for the whole SPA).

Running `ng test` for the above SPA gives an output like:

![Unit Test Results](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69mrnji3zrfmjehul1qw.PNG)

The command `ng e2e` can be run to test whether the Angular components like `HomeComponent`, `ProductsComponent` etc. display the right data. The e2e script can be found in [`cypress-integration-tests.spec.ts`](https://github.com/mapteb/framework-for-angular-development/blob/starter-example/cypress/integration/cypress-integration-tests.spec.ts). Running `ng e2e` gives:

![Integration Test Results](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9eneh7expmqugg9ngmfq.png)

The above screenshots show that the state transitions provide clear guidelines to writing both unit and integration test cases.

Error conditions are not discussed in the above example but can be easily included by adding additional transitions like:

`HOME > products > processPoducts() > productsError > PRODUCTSERROR`

## Conclusions:
The suggested strategy for unit testing Angular SPAs is shown to have the following benefits:
1. Simpler to understand and implement test cases compared to the conventional approach. 
2. Faster to implement test scripts compared to that in the conventional approach.