Testing ngrx store’s subscription with appState, action, and selector

之前我研究了一下使用SpyObject来测试NGRX,但这种方法有一个缺点:

You need to mock everything of the spyObject like pipe(), select(), etc. But actually, we may want to test with the real implementation of store, appState, action and selector.

Assuming we have

export const appReducers: ActionReducerMap<AppState, any> = {

    feature1: feature1Reducer,

    feature2: feature2Reducer

};



export class ChangeExpandedState implements Action {

  readonly type = Feature1ActionTypes.CHANGE_EXPANDED_STATE;  // action enum used in reducer,this is old, use https://ngrx.io/api/store/createReducer instead

  constructor(

    public payload: { section: string; subSection?: string; id?: string | null }

  ) {}

}



export function feature1Reducer (state = initialFeature1State, action: Feature1Actions): feature1State {

  switch (action.type) {

    case Feature1ActionTypes. Feature1_LIST_CHANGE:

      return {

        ...state,

        feature1List: action.payload.updatedFeature1List

      };

    ……

    case Feature1ActionTypes. CHANGE_EXPANDED_STATE:

                 const expandBuilder = state.expandState;

   // do something to flipflop based on action.payload.section

  return {

    ...state,

    expandState: expandBuilder

                };

   }

}

In test spec file’s async beforeEach:

TestBed.configureTestingModule({

            imports: [

                StoreModule.forRoot(appReducers),

             …]

         …..

}).compileComponents();

testStore = TestBed.get(Store);

测试用例:

it('should subscribe to someActionState change, () => {

    expect(component.isSomeActionEnabled).toBeFalsy();

    component.isActionSuccess = true; // showing the action response

    testStore.dispatch(new ChangeExpandedState({ section: "someAction" }));

   expect(component.someFeatureEnabled).toBeTruthy();

    expect(component.isActionSuccess).toBeFalsy(); // clear last time response

    testStore.dispatch(new ChangeExpandedState({ section: "someAction" }));

    expect(component.isSomeActionEnabled).toBeFalsy();

});