1

I am trying to update item, I wrote a function which gets the items from the store and update with new item based on user's selection with this.name and this.price but the same item.id that is intended for update.

   public updateItemData(){
    return this.store.select(itemSelector).subscribe(item => {
        this.updatedItem = {
            id: item.id,
            name: this.name,
            price: this.price
        }
    })
    }

This works perfectly without any issue but in a unit test.

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

It marked green but with displayed error.

TypeError: Cannot read properties of undefined (reading 'id')

When I ran the project, I didn't get any error concerning the "undefined property" or whatever. I started writing the test

Please help to resolve this. I will appreciate.

Curtis Lanz
  • 405
  • 2
  • 16

3 Answers3

1

Add a spyOn for the store service select. Either inside test or beforeEach

spyOn(store, 'select').and.returnValue(YOUR_VALUE);

make sure to declare store and asiign value inside beforeEach

let store: Store;
store = TestBed.inject(Store); // inside beforeEach
Sachila Ranawaka
  • 39,756
  • 7
  • 56
  • 80
1

You could use the provideMockStore provided from ngrx like this:

yourcomponent.component.spec.ts

import { provideMockStore } from '@ngrx/store/testing';

describe('...', () => {
 ...  
 ...
 const myMockItemSelectorValue = {...};

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [...],
      imports: [...],
      providers: [
       { 
         initialState: { items: {...}, users: {...} }, // an initial mock Store
         selectors: [{ selector: itemSelector, value: myMockItemSelectorValue }]
       }
      ]
    })
  })
});

Or create a mock of the store using jasmine like the following:

const mockStore = jasmine.createSpyObj<Store>('Store', ['select']);


beforeEach(() => mockStore.select.and.retunValue(of(TheDesiredMockValue))

beforeEach(() => {
  TestBed.configureTestingModule({
     providers: [{ provide: Store, useValue: mockStore }]
  })
})

Personally, I prefer the first option since I can specify multiple selectors with the respective mock values with an initial mock state.

Andres2142
  • 2,622
  • 2
  • 14
  • 19
0

All I had to do is to

  if(this.item === undefined) 
        {
            return
        }

So in my component.ts

  public updateItemData(){
    return this.store.select(itemSelector).subscribe(item => {
     if(this.item === undefined) 
        {
            return
        }
        this.updatedItem = {
            id: item.id,
            name: this.name,
            price: this.price
        }
    })
    }

All error disappeared and mocking using overrideSelector was successful.

Curtis Lanz
  • 405
  • 2
  • 16
  • What is "this.item"? Looks like you're mixing class members and locale variables here. And beyond that, an emty return is pretty bad style. Make the condition `if (item !== undefined)` instead, then you can save yourself this pointless return. Check your test, if it really tests something. – hmartini Oct 26 '22 at 22:10
  • Thanks... i have adjusted it. – Curtis Lanz Oct 26 '22 at 22:41