Home > Mobile >  Testing Angular component extending an abstract class
Testing Angular component extending an abstract class

Time:12-10

I have this setup for a number of components:

@Directive()
export abstract class BaseComponent implements OnInit {

   @Select(PortalState.portal) public portalState: Observable<PortalModel>;
   public portal: PortalModel;
   protected ngUnsubscribe: Subject<void> = new Subject();

   constructor(
     protected someService: SomeService,
     protected route: ActivatedRoute
     ){
   }

   public ngOnInit(): void {
     this.route.params
     .pipe(
        filter(res => !!res),
        tap(res => this.id = res['id']),
        switchMap(() => this.portalState),
        takeUntil(this.ngUnsubscribe)
     )
     .subscribe(res => {
        this.portal = res;
        this.afterInit();
     });
   }

   public ngOnDestroy(): void {
       this.ngUnsubscribe.next();
       this.ngUnsubscribe.complete();
   }

   public abstract afterInit(): void
}

and then in every component which extends this base class:

@Component({...})
export class SomeComponent extends BaseComponent {

   public specificVar: any;

   constructor(
     protected someService: SomeService,
     protected route: ActivatedRoute
   ){
      super(someService, route);
   }

   public afterInit(): void {
     /** do component specific stuff */
     this.specificVar = 'something';
   }

}

Now it works fine, however when testing, the abstract component's ngOnInit seems to be not called at all rendering (in this example) this.specific variable as undefined.

the spec file looks quite traditional

let store: Store; /** Ngxs store */
const mockPortalModel: PortalModel = {id: 1};

beforeEach(async () => {
  TestBed.configureTestingModule(/** providers and usual setup */);
  store = TestBed.inject(Store);
  store.reset({
    portalState: mockPortalModel
  });
  jest.spyOn(store, 'dispatch');
  jest.spyOn(store, 'select');
});

beforeEach(() => {
   fixture = TestBed.createComponent(SomeComponent);
   component = fixture.componentInstance;
   fixture.detectChanges();
});

Any ideas why ngOnInit and subsequently afterInit are not being called?

CodePudding user response:

You have to write below function in your SomeComponent so that it will run your BaseComponent's ngOnInit method after SomeComponent's ngOnInit method.

ngOnInit() {
  super.ngOnInit();
}

CodePudding user response:

The problem was in this.route.params which had to be mocked, so the subscription could fire. So mocking activated route has solved the issue:

const mockActivatedRoute = {
  snapshot: {}, // needs to be there to avoid _lastPathIndex error
  params: of({id: 123})
}

/** ...  */
providers: [
  {provide: ActivatedRoute, useValue: mockActivatedRoute }
]

had ensured that the subscription goes through (see that filter(res => !!res) - it stopped right there).

  • Related