Simplified version of the component implementation can be summarized as injecting of the NgRx Store and subscribing for state updates to be able to display the todos list.

Using TestStore

Once we have TestStore available in our project we can use it to write component unit tests.

First we have to provide it in our testing module in place of original NgRx Store. We can do that by overriding Store provider with { provide: Store, useClass: TestStore } .

From now on, injecting Store will actually give us instance of the TestStore. Store can be in theory injected in every test individually but it is much more convenient to inject it only once in the beforeEach block and save it in a variable for further use.

TestStore support generics so we can specify type (or interface) of our TestStore (eg TestStore<TodosState> ). This way we can be sure that we’re writing correct test code and that editor can help use with advanced code completion.

Example of how to provide our new TestStore instead of default NgRx Store in the test setup, feel free to check out final test implementation

In the previous code example we imported the TestStore from curiously looking "@testing/utils" module. Even though it looks like a scoped external npm dependency from the node_modules folder, it is in fact application code and the import is enabled by creating alias in the main tsconfig.json file.

Setting up aliases that enable us to import application code as if it came from node_modules instead of using long error prone relative paths (@testing/utils vs ../../../../testing/utils)

You can always import the TestStore using a relative import based on a particular location of your TestStore file and the test file (eg "../../testing/utils" ).

Follow me on Twitter to get notified about the newest blog posts and interesting frontend stuff

Testing of the component UI

Testing UI components is about making sure that they display correct UI elements in appropriate states based on the underlying data.

This seemingly simple idea can become quite hard to implement when we want to test components that are subscribed to state from NgRx Store. Initializing state then means that we have to emit appropriate and often quite specific actions before the actual testing.

We don’t want to know or care about implementation details of the reducers or actions just to initialize tests data

For these reasons TestStore comes with a store.setState() method that enables us to initialize any possible state whenever necessary. With the correct test state, all that is left to do is to check debug and native elements for the desired results…

Example of initialization of a test state using TestStore setState() method

Resulting tests are decoupled from the implementation details of how the specific state comes into existence.

In theory, this approach also enables us to swap our state management library without much effort as long as it has a store to which components subscribe for state updates.

Testing of Actions

Using NgRx to develop our applications means we often inject Store into our components so that they can subscribe to the updates of the relevant slice of the application state.

Another reason for injecting Store is to be able to dispatch NgRx actions. Actions are the only way to change (mutate) state in our Store.

From the testing perspective, we want to be able to verify that the component dispatched expected actions as a result of a specific UI interaction like clicking on a button.

In our example, the todos component contains a menu that enables us to select how we want to filter displayed todo items.

Clicking on any of the provided values will dispatch action which sets new filter value in the store.

The simplified implementation of such functionality can look something like this…

Again, we only want to test the component and NOT if NgRx handles actions correctly or if reducer produces a correct new state. This means we’re only interested in the fact that component dispatched correct action with correct payload as a result of user UI interaction.