I'm trying to do a pretty simple test in Angular with RxJs Observables, but I'm coming up short. This is what I'm basically trying to test:
// We're inside some Angular component here...
let testMe = 0;
function somethingOrOther(): void {
this.someService.methodReturningObservable()
.subscribe(
(nextValue: number): void => {
testMe += nextValue;
}
)
}
How do I test that testMe
gets updated properly when the observable behind methodReturningObservable
emits a value?
I attempted it with this:
it(`works 'cuz I want it to`, fakeAsync(() => {
spyOn(this.someService, 'methodReturningObservable').and.returnValue(cold('a', {a: 10}));
tick();
expect(component.testMe).toBe(10);
}));
So, tick()
doesn't seem to do anything here. Nothing gets my cold
value to ever emit on my spy.
I tried getTestScheduler.flush()
instead as shown at https://netbasal.com/testing-observables-in-angular-a2dbbfaf5329 under the marbles section.
Can I use marbles like this to emit a value on an observable? This was very easy in AngularJS by just triggering a digest, but I can't seem to get Anguar to let me in the next callback for an observable.
I put together a simple Stackblitz to show you how I would approach testing that simple component method you describe.
Here is the spec from that Stackblitz:
it(`works with "of" 'cuz I want it to`, () => {
spyOn(someService, 'methodReturningObservable').and.returnValue(of(10));
component.somethingOrOther();
expect(component.testMe).toBe(10);
});
Some of the changes I made to your code:
cold()
function is from the marble testing library, but that is way overkill for such a simple function. rxjs
has the of
Observable creation method available which can create a cold synchronous observable that can be subscribed to (but more below if you really want to test it this way).fakeAsync()
, as it will complete immediately.component.somethingOrOther()
.As you can see in the Stackblitz, this test passes just fine.
Now, if you want to use marble testing even for this simple case, I set up another spec in the Stackblitz for that. It is as follows:
it(`works with "cold" 'cuz I want it to`, () => {
spyOn(someService, 'methodReturningObservable').and.returnValue(cold('a', { a: 10 }));
component.somethingOrOther();
getTestScheduler().flush(); // flush the observables
expect(component.testMe).toBe(10);
});
Both tests are now passing in the Stackblitz.
Official docs for marble testing in Angular are here.
I hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With