Angular 测试 - 无法读取未定义的 属性 'clear'

Angular testing - Cannot read property 'clear' of undefined

我有如下组件

   <select #tabSelect (change)="tabLoad($event.target.value)" class="mr-2">
                  <option value="tab1">First tab</option>
                  <option value="tab2">Second tab</option>
                </select>


 <div class="tab-content">
        <div class="tab-pane fade show active">
          <ng-template #tabContent></ng-template>
        </div>
      </div>

有两个选项卡,它们调用 tabLoad() 函数并发送参数点击选项卡。

export class DemoComponent implements OnInit {

  @ViewChild('tabContent', { read: ViewContainerRef }) entry: ViewContainerRef;
  activeTab: any = 'tab1';

  constructor(private resolver: ComponentFactoryResolver) { }

  ngOnInit() {
    this.tabLoad(this.activeTab);
  }

  tabLoad(page) {
    setTimeout(() => {
      this.activeTab = page;
      this.entry.clear();
      if (page == 'tab1') {
        const factory = this.resolver.resolveComponentFactory(Tab1Component);
        console.log(this.entry);
        this.entry.createComponent(factory);
      } else if (page == 'tab2') {
        const factory = this.resolver.resolveComponentFactory(Tab2Component);
        this.entry.createComponent(factory);
      }
    }, 500);
  }

}

在这个 .ts 文件中,我创建了一个名为 entry 的变量,它指向 #tabContent.Tab 内容加载组件取决于哪个页面处于活动状态。

我为此行为编写了一个测试套件,如下所示

fdescribe('DemoComponent', () => {
    let component: DemoComponent;
    let fixture: ComponentFixture<DemoComponent>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [RouterModule.forRoot([]), SharedModule],
            declarations: [Tab1Component, Tab2Component],
        }).compileComponents().then(() => {
            fixture = TestBed.createComponent(DemoComponent);
            component = fixture.componentInstance;
        });
    }));
    it('should set activeTab correctly and clear entry when tabLoad is called', fakeAsync(() => {
        component.tabLoad("tab1");
        flush();
        expect(component.activeTab).toBe('tab1');
    }));
});

此测试失败并在我调用 this.entry.clear() 时显示 Cannot read property 'clear' of undefined; . console.log(this.entry); 也打印未定义。 然后我决定在 .compileComponents().then(() => {}) 范围内添加 fixture.detectChanges() 但在 ng 服务一切正常后我转到页面时仍然在相同的 way.But 中失败。

第一个 fixture.detectChanges() 调用 ngOnInit 并且您需要在 fakeAsync 区域中调用它以使 flush 生效,因为 setTimeout 已创建在 ngOnInit 通话中。本质上,计时器需要在 fakeAsync 区域中创建。因此,请尝试将 fixture.detectChanges() 放入测试中(它块)并将其从 .then.

中删除
beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [RouterModule.forRoot([]), SharedModule],
            declarations: [Tab1Component, Tab2Component],
        }).compileComponents().then(() => {
            fixture = TestBed.createComponent(DemoComponent);
            component = fixture.componentInstance;
            // !! remove fixture.detectChanges() from here
        });
    }));
    it('should set activeTab correctly and clear entry when tabLoad is called', fakeAsync(() => {
        // !! add it here
        fixture.detectChanges();
        component.tabLoad("tab1");
        flush();
        expect(component.activeTab).toBe('tab1');
    }));

就像 Petr 所说的那样,您可以使用 ngAfterViewInit.

而不是 500ms

试试这个:

export class DemoComponent implements OnInit, AfterViewInit { /* add AfterViewInit */

  @ViewChild('tabContent', { read: ViewContainerRef }) entry: ViewContainerRef;
  activeTab: any = 'tab1';

  constructor(private resolver: ComponentFactoryResolver) { }

  ngOnInit() {
  }

  ngAfterViewInit() {
    this.tabLoad(this.activeTab);
  }

  tabLoad(page) {
      this.activeTab = page;
      this.entry.clear();
      if (page == 'tab1') {
        const factory = this.resolver.resolveComponentFactory(Tab1Component);
        console.log(this.entry);
        this.entry.createComponent(factory);
      } else if (page == 'tab2') {
        const factory = this.resolver.resolveComponentFactory(Tab2Component);
        this.entry.createComponent(factory);
      }
  }

}

然后我认为您不需要 fakeAsyncflush