简体   繁体   中英

Jasmine Wait for Observable Subscription

I have the following class:

@Injectable()
export class MyService {
  private subscriptions: { [key: string]: Subscription } = {};

  constructor(private otherService: OtherService) {
  }

  public launchTimer(order: any): void {
    this.subscriptions[order.id] = timer(500, 300000).subscribe(
      () => {
        this.otherService.notify();
      },
    );
  }
}

I would like to write a unit test which asserts that when launchTimer() is called, the notify method of OtherService is called. The tricky thing about this is that the subscription to the timer observable is done directly in the method which means I can't do the subscription directly in the unit test to do the assertion.
What I came up with so far is the following test which is failing because the assertion is done before the subscription is made:

class OtherServiceMock {
  public notify(): void {}
}

describe('MyService', () => {
  let otherService: OtherServiceMock;
  let myService: MyService;
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        { provide: OtherService, useClass: OtherServiceMock },
      ],
    });
    otherService = TestBed.get(OtherService);
    myService = TestBed.get(MyService);
  });

  it('launchTimer should call notify', () => {
    spyOn(otherService, 'notify');
    myService.launchTimer();
    expect(otherService.notify).toHaveBeenCalled();
  });
});

I tried to wrap the function with async and I also used fakeAsync with tick but nothing seems to work. Any ideas how I can wait for the subscription before making the assertion?

Testing observables with interval and timer can be tricky but try this, if this doesn't work, I can maybe do it a different way as well.

class OtherServiceMock {
  public notify(): void {}
}

describe('MyService', () => {
  let otherService: OtherServiceMock;
  let myService: MyService;
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        { provide: OtherService, useClass: OtherServiceMock },
      ],
    });
    otherService = TestBed.get(OtherService);
    myService = TestBed.get(MyService);
  });

  it('launchTimer should call notify', fakeAsync(() => {
    // you're going to have to make `subscriptions` public for this to work !!
    spyOn(otherService, 'notify'); // don't need to callThrough to see if it was called or not
    myService.launchTimer({id: 1});
    tick(501);
    expect(otherService.notify).toHaveBeenCalled();
    myService.subscriptions['1'].unsubscribe(); // kill the timer subscription
  }));
});

===================== Edit ===================================

You are either going to have to make subscriptions public or provide a public way to unsubscribe from a subscription in that object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM