简体   繁体   English

测试 Angular 组件扩展抽象 class

[英]Testing Angular component extending an abstract class

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:然后在扩展此基础 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.现在它工作正常,但是在测试时,似乎根本没有调用抽象组件的 ngOnInit 渲染(在本例中) this.specific变量为未定义。

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?有什么想法为什么不调用ngOnInit和随后的afterInit吗?

You have to write below function in your SomeComponent so that it will run your BaseComponent 's ngOnInit method after SomeComponent 's ngOnInit method.您必须在 SomeComponent 的SomeComponent ,以便它在SomeComponentngOnInit方法之后运行您的BaseComponentngOnInit方法。

ngOnInit() {
  super.ngOnInit();
}

The problem was in this.route.params which had to be mocked, so the subscription could fire.问题出在必须模拟的this.route.params中,因此订阅可能会触发。 So mocking activated route has solved the issue:所以mocking激活路由解决了这个问题:

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).已确保订阅通过(请参阅filter(res => !!res) - 它就停在那里)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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