Unit testing Angular 2 components that are using observables and the async pipe
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When an Angular component uses an observable in the template with the async pipe, the test strategy is slightly different from testing manually subscribed code. The async pipe handles subscription and change propagation for you, so the test needs to drive observable emissions and trigger Angular change detection at the right time.
A Simple Component Pattern
Consider a component that exposes an observable directly to the template:
The key detail is that the component itself does not subscribe. The template does.
That means your test should not expect synchronous DOM updates until Angular has run change detection and the observable has emitted.
Testing with a BehaviorSubject
A BehaviorSubject is convenient for tests because you can push new values explicitly:
It also mirrors the way many Angular services expose state, which makes the test setup realistic without making it complicated.
This is the core pattern: emit a value, run change detection, then assert on the DOM.
When fakeAsync and tick Help
If the observable emits asynchronously through timers, promises, or delayed operators, you may need fakeAsync and tick:
Without advancing virtual time, the test may assert too early and fail even though the component logic is fine.
Mock Services Cleanly
A common real-world setup is that the observable comes from a service. In tests, provide a mock service that exposes a controllable subject.
That keeps the observable pipeline realistic while still making the test deterministic.
The component can consume count$ exactly as it would in production, while the test retains full control over emissions. This is usually cleaner than stubbing the observable with a one-off of(...) in every test because you can push several states through the same fixture.
The important principle is to control the source observable, not to bypass the async pipe by rewriting the component under test.
Common Pitfalls
The biggest mistake is asserting on the DOM before running fixture.detectChanges(). The async pipe updates the template through Angular change detection, not by magic.
Another issue is using cold asynchronous observables and forgetting fakeAsync, tick, or another synchronization strategy. Then the test races the emission.
Developers also sometimes subscribe manually in the test and assert on values there, which proves the observable works but not that the template rendered it correctly.
Finally, avoid over-mocking the component. If the template uses the async pipe, let the test exercise that real template behavior.
Summary
- Test async-pipe components by driving observable emissions and running change detection.
- '
BehaviorSubjectis a convenient source for deterministic tests.' - Use
fakeAsyncandtickwhen observable emissions are delayed. - Assert on the rendered DOM, not only on observable values.
- Let the async pipe remain part of the test instead of bypassing it.

