subscribe-on-init.decorator.spec.ts 3.73 KiB
import { OnDestroy, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { MarbleTestScheduler } from '../testing/marbles';
import { SubscribeOnInit } from './subscribe-on-init.decorator';
describe('@SubscribeOnInit', () => {
  const VALUES = { a: 'a' };
  let scheduler: MarbleTestScheduler<string>;
  class PropertyTestClass<T extends Observable<any>> implements OnInit, OnDestroy {
    @SubscribeOnInit()
    public readonly obs$: T;
    public constructor(
      obs$: T,
      private readonly initSpy = (): void => undefined,
      private readonly destroySpy = (): void => undefined
    ) {
      this.obs$ = obs$;
    public ngOnInit(): void {
      this.initSpy();
    public ngOnDestroy(): void {
      this.destroySpy();
  beforeEach(() => {
    scheduler = MarbleTestScheduler.create(VALUES);
  });
  it('should subscribe on init and unsubscribe on destroy', () =>
    scheduler.run(({ cold, expectSubscriptions }) => {
      const obj = new PropertyTestClass(cold('a'));
      obj.ngOnInit();
      scheduler.schedule(() => obj.ngOnDestroy(), scheduler.createTime('---|'));
      expectSubscriptions(obj.obs$.subscriptions).toBe('^!');
    }));
  it('should be tied only to object instances', () =>
    scheduler.run(({ cold, expectSubscriptions }) => {
      const obj1 = new PropertyTestClass(cold('a'));
      const obj2 = new PropertyTestClass(cold('a'));
      obj1.ngOnInit();
      obj2.ngOnInit();
      scheduler.schedule(() => obj1.ngOnDestroy(), scheduler.createTime('--|'));
      scheduler.schedule(() => obj2.ngOnDestroy(), scheduler.createTime('----|'));
      expectSubscriptions(obj1.obs$.subscriptions).toBe('^--!');
      expectSubscriptions(obj2.obs$.subscriptions).toBe('^----!');
    }));
  it('should call original ngOnInit', () =>
    scheduler.run(({ cold }) => {
      const obs$ = cold('a');
      const initSpy = jasmine.createSpy('ngOnInit');
      const obj = new PropertyTestClass(obs$, initSpy);
      obj.ngOnInit();
      expect(initSpy).toHaveBeenCalled();
    }));
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
it('should call original ngOnDestroy', () => scheduler.run(({ cold }) => { const obs$ = cold('a'); const destroySpy = jasmine.createSpy('ngOnDestroy'); const obj = new PropertyTestClass(obs$, undefined, destroySpy); obj.ngOnInit(); obj.ngOnDestroy(); expect(destroySpy).toHaveBeenCalled(); })); it('can be used on more than one property', () => scheduler.run(({ cold, expectSubscriptions }) => { class TwoPropertyTestClass implements OnInit, OnDestroy { @SubscribeOnInit() public readonly obs1$ = cold('a'); @SubscribeOnInit() public readonly obs2$ = cold('a'); public ngOnDestroy(): void {} public ngOnInit(): void {} } const obj = new TwoPropertyTestClass(); obj.ngOnInit(); scheduler.schedule(() => obj.ngOnDestroy(), scheduler.createTime('---|')); expectSubscriptions(obj.obs1$.subscriptions).toBe('^---!'); expectSubscriptions(obj.obs2$.subscriptions).toBe('^---!'); })); it('should be inherited', () => scheduler.run(({ cold, expectSubscriptions }) => { class ParentClass implements OnInit, OnDestroy { @SubscribeOnInit() public readonly obs1$ = cold('a'); public ngOnDestroy(): void {} public ngOnInit(): void {} } class ChildrenClass extends ParentClass { @SubscribeOnInit() public readonly obs2$ = cold('a'); } const obj = new ChildrenClass(); obj.ngOnInit(); scheduler.schedule(() => obj.ngOnDestroy(), scheduler.createTime('---|')); expectSubscriptions(obj.obs1$.subscriptions).toBe('^---!'); expectSubscriptions(obj.obs2$.subscriptions).toBe('^---!'); })); });