erin
erin

Reputation: 665

Unit testing that items get filtered out of Observable (Jasmine/RxJS)

I'm doing unit testing with Jasmine/Karma against an Angular service. I'd like to confirm that my service properly filters items.

For example, if I have a service to get people over a certain age, it

  1. should return people over the minimum age (positive case)
  2. should NOT return people under a the minimum age (negative case)

It's #2 that I'm struggling to test.

The service:

    getPeople(minAge: number): Observable<string> {
        const source = Observable.from([
            { name: 'Joe', age: 30 },
            { name: 'Frank', age: 20 },
            { name: 'Ryan', age: 50 }
        ]);
        return source
            .filter(person => person.age >= minAge)
            .map(person => person.name);
    }

The Positive unit test

    it('should return people over 30', () => {
        const service = new MyService();
        const minAge = 30;
        service.getPeople(minAge).subscribe(people => {
            expect(people.length).toBeGreaterThan(0);
        });
    });

And the Negative unit test

it('should not return people over 55', () => {
        const service = new MyService();
        const minAge = 55;
        service.getPeople(minAge).subscribe(people => {
            expect(people.length).toBe(0); // WE NEVER GET HERE!
        });
    });

In the negative case, the Observable never returns anything, and rightly so. But, how do I write a unit test to confirm this?

Upvotes: 4

Views: 3796

Answers (2)

JB Nizet
JB Nizet

Reputation: 691755

Your first test is wrong. It tests that the length of each string being emitted is greater than 0. That shouldn't be what you test: the test would pass even if your code emitted 'Frank'. What you should test is that the emitted person names are 'Joe' and 'Ryan':

const result: Array<string> = [];
service.getPeople(minAge).subscribe(people => {
  result.push(people);
});
expect(result).toEqual(['Joe', 'Ryan']); 

Your second test isn't really necessary, since your first test checks that the filtering results the correct names, and doesn't return the incorrect ones. But if you really want to keep it, then you should fail the test if the subscribe callback is called, since it should not be called:

service.getPeople(minAge).subscribe(people => {
  fail('should not be called');
});

Upvotes: 6

Leandro Lima
Leandro Lima

Reputation: 1164

Your observable is a stream of values, you may do something like:

Positive:

let invoked = 0;
service.getPerson(30).subscribe(() => {
   invoked++;
})
expect(invoked).toEqual(2);

Negative:

let invoked = 0;
service.getPerson(55).subscribe(() => {
   invoked++;
})
expect(invoked).toEqual(0);

Upvotes: 4

Related Questions