Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ngrx testing: Uncaught TypeError: Cannot read property 'xxxx' of undefined thrown

afterEach(() => { fixture.destroy(); });I am currently trying to write tests for my ngrx based angular 7 application. The problem is that my test fails with the error Uncaught TypeError: Cannot read property 'xxxx' of undefined thrown. Here's how my test file looks like.

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();
  });
});

The only should create test is throwing the error. The error is being throwing by the selector somehow, which means the xxxx property is not initialized but I am not sure how to resolve it. Here's what my component looks like.

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();
    }
  }
}

Please let me know if I can provide any other information.

Update

The problem is with AppState. The error is thrown since the state is not initialized which causes the error to occur i.e state.xxxx is undefined. The error sometimes randomly doesn't occur. I am not sure how to fix this.

The same problem is also mentioned here. But no solution

like image 701
Mj1992 Avatar asked Jun 28 '19 14:06

Mj1992


1 Answers

For me adding this line of code afterEach(() => { fixture.destroy(); }); in all my spec files injecting provideMockStore() fixed this issue intermittently triggering.

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();
  });
});
like image 171
art_man202 Avatar answered Oct 24 '22 22:10

art_man202