Florian Ludewig
Florian Ludewig

Reputation: 6002

NgRx 8 Test provideMockStore - setState for State Slice

I have a smart component test for my NgRx implementation that looks something like this:

describe( 'Component', () => {
  let store: MockStore<State>;

  beforeEach( async( () => {
    TestBed.configureTestingModule( {
        /* ... */
        providers: [
            provideMockStore( { initialState: fromReducer.initialState } )
        ]
    } ).compileComponents();
    store = TestBed.get<Store<State>>( Store );
  } ) );

  it( 'should load items in #ngOnInit', () => {
    store.setState( {
        item: {
          ...fromReducer.initialState,
          entities: { [item.id]: item },
        },
        otherFeature: null,
        otherFeature: null,
        otherFeature: null
    } );
    component.items$.subscribe( items =>
        store.select( ItemStoreSelectors.selectItems ).subscribe( fromStore => expect( items ).toEqual( fromStore ) )
    );
  } );
});

I use provideMockStore and setState to mock my NgRx state. Everything works fine this way, but I really don't like this part of it:

store.setState( {
    item: {
      ...fromReducer.initialState,
      entities: { [item.id]: item },
    },
    otherFeature: null,
    otherFeature: null,
    otherFeature: null
} );

I have to add every other feature slice of my state to the setState function. Otherwise Typescript will throw Errors.


So preferably I don't want to set the root state, but rather a specific feature slice like this:

store.setState( {
  ...fromReducer.initialState,
  entities: { [item.id]: item },
} );

I couldn't find any documentation on how to use provideMockStore for specific slices of the state here.

Upvotes: 4

Views: 12849

Answers (2)

timdeschryver
timdeschryver

Reputation: 15505

As xander mentioned you can use mockSelectors. The reason why TS is complaining is because how you typed it.

MockStore<State> is probably your whole state tree, for just a feature slice, use MockStore<FeatureState>

Upvotes: 1

xandermonkey
xandermonkey

Reputation: 4412

I would recommend taking a different approach here. What you should do instead is unit test your selector and component independently.

NgRx 8 allows for mock selectors. Use that in your component to verify the component's logic is correct.

Then, unit test your selector independently to verify that your selector is working as intended.

This way the tests are independent, not brittle, and truly unit tests.

Edit: The docs I linked are official, but an alternative way to mock your selectors is:

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        provideMockStore({
          selectors: [
            {
              selector: yourSelectorNameHere,
              value: someMockValueHere
            }
          ]
        })
      ]
    });

Upvotes: 8

Related Questions