ngrx测试:未捕获的TypeError:无法读取未定义抛出的属性'xxxx'

时间:2019-06-28 14:43:18

标签: unit-testing karma-jasmine ngrx

afterEach(()=> {     Fixture.destroy();   });我目前正在尝试为基于ngrx的angular 7应用程序编写测试。问题是我的测试失败,并显示错误Uncaught TypeError: Cannot read property 'xxxx' of undefined thrown。这是我的测试文件的样子。

explore-products.component.spec.ts

import { async, ComponentFixture, TestBed } from "@angular/core/testing";

import { ExploreProductsComponent } from "./explore-products.component";
import { provideMockStore, MockStore } from "@ngrx/store/testing";
import { IAppState } from "src/app/store/state/app.state";
import { Store, StoreModule } from "@ngrx/store";
import { appReducers } from "src/app/store/reducers/app.reducer";

describe("ExploreProductsComponent", () => {
  let component: ExploreProductsComponent;
  let fixture: ComponentFixture<ExploreProductsComponent>;
  let store: MockStore<IAppState>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [ExploreProductsComponent],
      providers: [provideMockStore()],
      imports: [StoreModule.forRoot(appReducers)]
    });

    store = TestBed.get(Store);
  });

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

  it("should create", () => {
    expect(component).toBeTruthy();
  });
});

唯一的should create测试引发错误。错误由selector引发,这意味着xxxx属性未初始化,但是我不确定如何解决。这是我的组件的样子。

explore-products.component.ts

import { Component, OnInit, OnDestroy } from "@angular/core";
import { IProduct } from "src/app/models/product";
import { environment } from "src/environments/environment";
import { selectProducts } from "../../store/selectors/product";
import { Store, select } from "@ngrx/store";
import { IAppState } from "src/app/store/state/app.state";
import { Subscription } from "rxjs";

@Component({
  selector: "app-explore-products",
  templateUrl: "./explore-products.component.html",
  styleUrls: ["./explore-products.component.css"]
})
export class ExploreProductsComponent implements OnInit, OnDestroy {
  public productsLoading = true;
  public endpoint = environment.apiEndpoint;

  private productsSelector = this.store.pipe(select(selectProducts));

  public products: IProduct[];
  private subscriptionsArr: Subscription[] = [];

  constructor(private store: Store<IAppState>) {}

  ngOnInit() {
    this.subscriptions();
  }
  subscriptions() {
    const subcriberProduct = this.productsSelector.subscribe(products => {
      this.products = products;
      if (this.products !== null) {
        this.toggleLoadingSign(false);
      }
    });
    this.subscriptionsArr.push(subcriberProduct);
  }
  toggleLoadingSign(toggleOption: boolean) {
    this.productsLoading = toggleOption;
  }
  ngOnDestroy() {
    for (const subscriber of this.subscriptionsArr) {
      subscriber.unsubscribe();
    }
  }
}

请告知我是否可以提供其他信息。

更新

问题出在AppState上。由于未初始化状态而导致错误发生,即state.xxxx未定义,因此引发该错误。该错误有时不会随机发生。我不确定如何解决此问题。

here也提到了相同的问题。但是没有解决办法

3 个答案:

答案 0 :(得分:4)

对我来说补充:

  afterEach(() => {
     fixture.destroy();
  });

解决了组件的每个规范文件

答案 1 :(得分:3)

对于我来说,在所有注入afterEach(() => { fixture.destroy(); });的规范文件中添加此行代码provideMockStore()可以解决此问题间歇触发的问题。

describe('Component', () => {
  let component: Component;
  let fixture: ComponentFixture<Component>;

  beforeEach(async(() => {
    const state = { featureKey: { property: value } }; // The state of your feature snippet
    TestBed.configureTestingModule({
      providers: [
        provideMockStore({ initialState: state }),
      ]
    }).compileComponents();
  }));

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

  afterEach(() => { fixture.destroy(); });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

答案 2 :(得分:0)

您可以尝试类似的方法。 看看我如何创建并使用了模拟存储。在代码更新的任何地方添加了单行注释(带有************):

import { async, ComponentFixture, TestBed } from "@angular/core/testing";

import { ExploreProductsComponent } from "./explore-products.component";
import { provideMockStore, MockStore } from "@ngrx/store/testing";
import { IAppState } from "src/app/store/state/app.state";
import { Store, StoreModule } from "@ngrx/store";
import { appReducers } from "src/app/store/reducers/app.reducer";

describe("ExploreProductsComponent", () => {
  let component: ExploreProductsComponent;
  let fixture: ComponentFixture<ExploreProductsComponent>;
  //Update the store def.************
  let store: MockStore<any>;

  beforeEach( async(() => { //*****************UPDATE
    TestBed.configureTestingModule({
      declarations: [ExploreProductsComponent],
      providers: [provideMockStore()],
      //Change to imports************
      imports: [StoreModule.forRoot({})]
    }).compileComponents();//*****************UPDATE
    //Removed this
    //store = TestBed.get(Store);************

  }));//*****************UPDATE

  beforeEach(() => {
    fixture = TestBed.createComponent(ExploreProductsComponent);
    //Get store instance************
    store = fixture.debugElement.injector.get(Store);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it("should create", () => {
    //Spy on store actions************
    const spy = spyOn(store, 'dispatch');
   //Test is store is called properly************
   expect(spy).toHaveBeenCalledWith(Your params)
    expect(component).toBeTruthy();
  });
});