2

I have a component, inside ngOninit, I am dispatching an action which is being handled by ngrx/effect to get some data from service API. I am writing unit tests and want to mock the service call in ngOninit so that the original API is not called. But still the original API is being called, maybe because it was handled from effects. How should I handle this so that I stop actual API call and call mocked service API instead?

Component Code:

ngOnInit() {
   this.sectionId$ = this.store.select(reducers.getSectionIDFromAppState).subscribe((sectionID) => {
   if (sectionID) {
     this.store.dispatch(new layoutActions.GetLogFormatListAction(sectionID));
  }
}

Action Code:

export class GetLogFormatListAction implements Action {
type = ActionTypes.GET_LOG_FORMAT_LIST;
constructor(public payload?: any) {
    this.payload = payload;
}

}

Effects Code:

@Effect()
getLogFormatList$: Observable<Action> = this.actions$
    .ofType(layoutActions.ActionTypes.GET_LOG_FORMAT_LIST)
    .mergeMap((action: any) => {
        return this.layoutService.getLogFormatList(action.payload)
            .map(logFormatList => new layoutActions.GetLogFormatListSuccessAction(logFormatList))
            .catch(error => Observable.of(new layoutActions.GetLogFormatListFailureAction(error)));
    });

Layout.service.ts

getLogFormatList(sectionId): Observable<any> {
const requestData = {
  endpoint: environment.endpoints.GET_LOG_FORMAT_LIST.endpoint + sectionId,
  params: {
  }
};
return this.httpRequestWrapperService.fetchData(requestData);  }

My Spec code:

beforeEach(async(() => {
TestBed.configureTestingModule({
  declarations: [
    LogviewerWidgetConfigComponent,
    MockComponent({ selector: 'app-logviewer-config-template', inputs: ['logformatList', 'widgetConfig' , 'index'] }),
    MockComponent({ selector: 'app-widget-config-header', inputs: ['model'], outputs: ['closeWidgetConfig'] }),
  ],
  imports: [FormsModule, StoreModule.forRoot(reducers)],
  providers: [{ provide: LayoutService, useClass: MockLayoutService }]
}).compileComponents();  }));

beforeEach(() => {
store = TestBed.get(Store);
spyOn(store, 'dispatch').and.callThrough();
fixture = TestBed.createComponent(LogviewerWidgetConfigComponent);
component = fixture.componentInstance;
fixture.detectChanges();  });

Mocked service:

class MockLayoutService {
  getLogFormatList(param: any): Observable<any> {
   return Observable.of(null);
  }
}
Niranjan
  • 77
  • 9

1 Answers1

0

You didn't mock your API call, you mocked another service.

If you want to mock your API call, make this mock :

const storeMock = {
  select: () => Observable.of(null),
  dispatch: () => null
};

And provide it in your test bed :

providers: [
  { provide: LayoutService, useClass: MockLayoutService },
  { provide: Store, useValue: storeMock }
]

(I don't know the dependency you're using, but I think you may have to remove the StoreModule from your imports if you mock its service).

Once done, your call will no longer hit the API, but hit the mock.

  • Thank for your answer. The main issue here is not with the store but the effects considering the original service instead of the mocked one – Niranjan Jun 14 '18 at 10:32
  • From where is your effect being called ? –  Jun 14 '18 at 10:35