I'm using NGRX, and use Effects to send HTTP requests. If a user sends another request, any previous request should be cancelled. It is working fine when I test manually, but I want to be able to unit test this. To test this, I'm mocking the service that sends the HTTP request and send a response after a certain delay. Then, I've got a Marble hot observable that triggers 4 requests. I expect that my Effect is only triggered once. However, it is not triggered at all.
The unit test:
it('should only do one request at a time', fakeAsync(() => {
// Arrange
const data = createTestData();
const dataServiceSpy = TestBed.get(DataService);
dataServiceSpy.getData = jest.fn(
(query: DataQuery) => {
const waitTime = 1000 * + query.index;
return of(assets).pipe(delay(waitTime));
}
);
// Act
actions = hot('-abcd-|', {
a: new SearchData({ index: '6' }),
b: new SearchData({ index: '5' }),
c: new SearchData({ index: '4' }),
d: new SearchData({ index: '1' })
});
tick(10000);
// Assert
expect(effects.loadData$).toBeObservable(
hot('-a-|', { a: new SearchDataComplete(assets) })
);
}));
So, I'm sending 4 search requests; the first one should return data after 6 seconds, second one after 5, and so on. However, my unit test is failing that loadData$ is an empty observable while it expects to have one item.
If I remove the delay in the spy, it works as expected and loadData$ contains 4 results.
My Effect is using NX DataPersistence which takes care of the cancellation if you supply the id function; it will cancel the initial request if a new action comes in with the same id. It is similar to use this.actions$.pipe(switchMap(...))
@Effect()
loadData$ = this.dataPersistence.fetch(ActionTypes.SearchData, {
id: (action, state) => {
return action.type
},
run: (action, state) => {
return this.dataService
.searchData(action.payload)
.pipe(
map(data => new SearchDataComplete(data))
);
},
getData
and your effect hassearchData
- electrichead