Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marble testing a subject's behavior over time with jasmine-marbles

So I'm trying to test a Subject's behavior and it's not working, and it seems like there some things I'm not understanding correctly. Consider the following test:

it('marble testing subject test', () => {
    const obs$: Subject<number> = new Subject<number>();

    obs$.next(42);
    obs$.next(24);

    expect(obs$.asObservable()).toBeObservable(hot('xy', { x: 42, y: 24 }));
  });

This fails with this error message:

Expected $.length = 0 to equal 2.
Expected $[0] = undefined to equal Object({ frame: 0, notification: Notification({ kind: 'N', value: 42, error: undefined, hasValue: true }) }).
Expected $[1] = undefined to equal Object({ frame: 10, notification: Notification({ kind: 'N', value: 24, error: undefined, hasValue: true }) }).

I think I sort of understand why: the Subject (per documentation) only emits values after the start of the subscription. The toBeObservable() function (I'm assuming) subscribes to the Subject and so my 2 next calls happened before this, so they won't emit.

So my question is, how would I test something like this? i.e. testing a series of emissions from a subject over time? Is this possible to do with marble testing? I can sort of get it to work by changing it out for a ReplaySubject but if I do, the marble diagram has to be (xy) instead of xy.

Thanks.

like image 429
sovemp Avatar asked Nov 07 '22 18:11

sovemp


1 Answers

I have this working in the context of an Angular application

My service, the key part being that I define my things as a getter, giving me a chance to actually spy on asObservable if I just defined things$ as a property then the spy doesn't work:

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  private things = new BehaviorSubject<Array<string>>([]);

  public get things$(): Observable<boolean> {
    return this.things.asObservable().pipe(map((things) => things.length > 0))
  }
}

And then in my test, I guess the key part is that I am spying on the asObservable method on the things BehaviourSubject. Like this:

describe('#things$', () => {

    it('should ', () => {
      const things.   = 'a-b-a';
      const expected =  't-f-t';
      // spy on
      spyOn(service['things'], 'asObservable').and.returnValue(hot(things, {
        a: ['a', 'b'],
        b: []
      }));

      expect(service.things$).toBeObservable(cold(expected, {
        t: true,
        f: false
      }));
    });
  });
like image 158
Ian Jamieson Avatar answered Nov 12 '22 17:11

Ian Jamieson