In my angular project, I have a service, which is used for state management to share some data between components as following:
@Injectable({ providedIn: "root"})
export class NameStateService {
private _filteredNames$: Subject<Name[]> = new Subject();
private _filteredNamesObs$: Observable<Name[]>;
constructor() {
this._filteredNamesObs$ = this._filteredNames$.asObservable();
}
public updateFilteredNames(val: Name[]): void {
this._filteredNames$.next(val);
}
public get filteredNames$(): Observable<BillingAccount[]> {
return this._filteredNamesObs$;
}
}
the state management is based on subject and observable, which is typical usage in rxjs world.
And For the unit test for this service, I want to use the marble testing features suppored by rxjs/testing
module. The solution goes as following:
describe("Name state service ", () => {
let nameStateService: NameStateService;
let scheduler: TestScheduler;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
NameStateService
]
});
nameStateService = TestBed.get(NameStateService);
scheduler = new TestScheduler((actual, expected) => expect(actual).toEqual(expected));
});
it("should be created", () => {
expect(nameStateService).toBeTruthy();
});
it("should return a valid names observables", () => {
scheduler.run(({ cold, hot, expectObservable }) => {
const mockNames: Name[] = [{
title: "title1",
group: "group1"
}];
nameStateService.updateFilteredNames(mockNames);
expectObservable(nameStateService.filteredNames$).toBe("-b", {b: mockNames});
});
});
})
But the second unit test failed with the error: Error: Expected $.length = 0 to equal 1.
So it means that nameStateService.filteredNames$
, this observable has no values in its stream.
What is the issue here?
expectObservable(nameStateService.filteredNames$)
creates a subscription after the subject fires the events, thus it's empty. Try to mock the getter offilteredNames$
and return ahot
observable with appropriate marble diagram. Use Spy class for mocking. – Tal Ohana