0

I am trying to write the test with spec file, butting an error as:

TypeError: Cannot read property 'loading' of undefined - not able to understand either fix it out.

any one help me here?

here is my spec.ts file:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { provideMockStore, MockStore } from '@ngrx/store/testing';
import { ShellHomeComponent } from './shell-home.component';
import { StoreOne } from './../../models';
import { Store, select } from '@ngrx/store';
import { cold } from 'jasmine-marbles';
import { StoreModule } from '@ngrx/store';
import { reducer } from './../../state/reducer/reducer-storeOne';

describe('ShellHomeComponent', () => {

    let fixture: ComponentFixture<ShellHomeComponent>;
    let mockStore: MockStore<StoreOne>;
    let component: ShellHomeComponent;

    const loadingState = {
        loading: true,
        items: [{ name: '1' }]
    } as StoreOne;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [ ShellHomeComponent ],
            providers: [provideMockStore({ initialState: loadingState })]
        })
        .compileComponents();

        mockStore = TestBed.get(Store);

    }));

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


    it('should display loading as true', () => {
        const expected = cold('a', { a: true });
        expect(component.loading).toBeObservable(expected);
    });

});

error I am getting:

expect(received).toEqual(expected) // deep equality

    - Expected
    + Received

      Array [
        Object {
          "frame": 0,
          "notification": Notification {
    -       "error": undefined,
    -       "hasValue": true,
    -       "kind": "N",
    -       "value": true,
    +       "error": [TypeError: Cannot read property 'loading' of undefined],
    +       "hasValue": false,
    +       "kind": "E",
    +       "value": undefined,
          },
        },
      ]

      44 |     it('should display loading as true', () => {
      45 |         const expected = cold('a', { a: true });
    > 46 |         expect(component.loading).toBeObservable(expected);
         |                                   ^
      47 |     });
      48 |
      49 | });

      at compare (node_modules/jasmine-marbles/bundles/jasmine-marbles.umd.js:379:33)
      at src/app/module1/shell/shell-home/shell-home.component.spec.ts:46:35

  console.warn node_modules/@ngrx/store/bundles/store.umd.js:608
    The feature name "storeOne" does not exist in the state, therefore createFeatureSelector cannot access it.  Be sure it is imported in a loaded module using StoreModule.forRoot('storeOne', ...) or StoreModule.forFeature('storeOne', ...).  If the default state is intended to be undefined, as is the case with router state, this development-only warning message can be ignored.

my componet.ts file:

import { Component, OnInit, OnChanges } from '@angular/core';
import { StoreOne, Item } from './../../models';
import { Observable } from 'rxjs';
import { Store, select } from '@ngrx/store';
import * as slices from './../../state';
import * as actions from './../../state/actions';

@Component({
    selector: 'app-shell-home',
    templateUrl: './shell-home.component.html',
    styleUrls: ['./shell-home.component.scss']
})
export class ShellHomeComponent implements OnInit {

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

    items: Observable<Item[]>;
    loading: Observable<boolean>;

    ngOnInit() {

        this.store.dispatch(actions.Items());
        this.items = this.store.pipe(select(slices.getItems));
        this.loading = this.store.pipe(select(slices.getLoad));

        this.store.subscribe(state => console.log(state));
       //{ "storeOne": { "loading": true, "items": [ {"name": "1" }, { "name": "2"} ] }}

    }


}

UPDATE

my loading state updated to like the follow:

const loadingState = { storeOne: { loading: true, items: [{ name: 1 }] } } as StoreOne;

but getting an error as:

TypeScript diagnostics (customize using `[jest-config].globals.ts-jest.diagnostics` option):
    src/app/module1/shell/shell-home/shell-home.component.spec.ts:16:26 - error TS2352: Conversion of type '{ storeOne: { loading: boolean; items: { name: number; }[]; }; }' to type 'StoreOne' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
      Type '{ storeOne: { loading: boolean; items: { name: number; }[]; }; }' is missing the following properties from type 'StoreOne': loading, items

    16     const loadingState = { storeOne: { loading: true, items: [{ name: 1 }] } } as StoreOne;
                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3gwebtrain
  • 14,640
  • 25
  • 121
  • 247

2 Answers2

3

In my case the problem was the structure of the imports. I had imported a Module with

StoreModule.forFeature('name', nameReducer)

inside a module with:

StoreModule.forFeature('name2', name2Reducer)

The code works fine, but when i test it fails.

The solution was import what a need from the module inside the test declarations insted of the module.

2

Your code unnecessarily uses techniques for both a unit test and an integration test. The correct solution depends on the goal for your test:

  • If your goal is to write an integration test (testing your component with it's live dependencies), import forRoot:
TestBed.configureTestingModule({
  declarations: [ ShellHomeComponent ],
  imports: [StoreModule.forRoot({ storeOne: reducer })]
  // no need to use mock store for an integration test, import your reducer using `forRoot`
})
  • If your goal is to write a unit test (mocked store), which I believe it is, provide the MockStore:
TestBed.configureTestingModule({
  declarations: [ ShellHomeComponent ],
  providers: [provideMockStore({ initialState: loadingState 
  // no need to import the `StoreModule` in a unit test, `provideMockStore` will do all the setup
})

At AngularUP, I gave a talk on unit test vs integration tests, as well as MockStore.

  • I just following your advice from the video. please check my updated spec file with the error i am getting. By the way very thanks to you. I need to close this issue within today. looking for further help. – 3gwebtrain Oct 02 '19 at 16:07
  • What does your state object look like? Error looks like it may be not have a loading state. If when running your app, in your component you did `this.store.subscribe(state => console.log(state))`, what is your state object? – John Crowson Oct 02 '19 at 16:52
  • I do this works for me: `ngOnInit() { this.store.dispatch(actions.Items()); this.items = this.store.pipe(select(slices.getItems)); this.loading = this.store.pipe(select(slices.getLoad)); } ` – 3gwebtrain Oct 02 '19 at 16:54
  • here is my state object : `{ "storeOne": { "loading": true, "items": [ { "name": "1" }, { "name": "2" } ] } }` – 3gwebtrain Oct 02 '19 at 16:57
  • if possible can you share me a success full working app for unite test? – 3gwebtrain Oct 02 '19 at 17:18
  • I believe you're missing the storeOne key in your loadingState property in your test. Take a look at the example-app over at NgRx, but it uses mock selectors: https://github.com/ngrx/platform/tree/master/projects/example-app Also, the documentation on mockstore: https://ngrx.io/guide/store/testing – John Crowson Oct 02 '19 at 17:25
  • can you please look my update part? I tried by updating my `loadingState` - but getting error.. – 3gwebtrain Oct 03 '19 at 01:38
  • Can you upload the project? There's a lot of setup I'd need to understand. – John Crowson Oct 03 '19 at 19:25
  • now the project added here: https://github.com/3gwebtrain/jest-test please go ahead. here is the spec file in project: https://github.com/3gwebtrain/jest-test/blob/master/src/app/module1/shell/shell-home/shell-home.component.spec.ts – 3gwebtrain Oct 04 '19 at 02:03
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/200373/discussion-between-3gwebtrain-and-john-crowson). – 3gwebtrain Oct 04 '19 at 04:49
  • chat link doesn't work for me, possibly due to VPN restrictions. I'll take a look at the test later tonight. – John Crowson Oct 04 '19 at 19:32
  • Thank you so much, for your valuable time. – 3gwebtrain Oct 05 '19 at 02:18
  • hi John, wondering if I have many different dependent stores, can I write an integrate tests but with 1-2 mocked stores? can we use both in the same spec? – Huy Vu May 06 '20 at 13:40