简体   繁体   中英

Why can't I dispatch an action when a promise resolves inside Redux middleware?

Background

I am writing a piece of Redux middleware that makes an axios request and uses Cheerio to parse the result.

Problem

When the Axios promise resolves and I try to dispatch a fulfilled action the action does not show up in the store's action log in the test.

Middleware

function createMiddleware() {
    return ({ dispatch, getState }) => next => action => {

      if (isCorrectAction(action)===true){

      const pendingAction = {
        type: `${action.type}_PENDING`,
        payload: action.payload
      }

      dispatch(pendingAction)

      axios.get(action.payload.url)
            .then(response => {
              let $ = cheerio.load(response.data)
              let parsedData = action.payload.task($)

              const fulfilledAction = {
                type: `${action.type}_FULFILLED`, 
                payload: { 
                  parsedData 
                }
              }

              dispatch(fulfilledAction) // dispatch that is problematic

            })
            .catch( err => {

            });
       }

        return next(action);
    }
}

Test that fulfilled action is dispatched fails

   it('should dispatch ACTION_FULFILLED once', () => {
       nock("http://www.example.com")
           .filteringPath(function(path) {
               return '/';
           })
           .get("/")
           .reply(200, '<!doctype html><html><body><div>text</div></body></html>');

       const expectedActionTypes = ['TASK', 'TASK_PENDING', 'TASK_FULFILLED']

       // Initialize mockstore with empty state
       const initialState = {}
       const store = mockStore(initialState)
       store.dispatch(defaultAction)

       const actionsTypes = store.getActions().map(e => e.type)
       expect(actionsTypes).has.members(expectedActionTypes);
       expect(actionsTypes.length).equal(3);
   });

Solution - Promise needs to be returned in the mocha test

The solution is to rewrite the mocha test so that the promise is returned. I mistakenly thought that by using nock to intercept the HTTP request that the promise would become synchronous.

The working test looks like:

it('should dispatch ACTION_FULFILLED once', () => {
    nock("http://www.example.com")
        .filteringPath(function(path) {
            return '/';
        })
        .get("/")
        .reply(200, '<!doctype html><html><body><div>text</div></body></html>');

    const store = mockStore();

    return store.dispatch(defaultScrapingAction)
                .then(res => {   

         const actionsTypes = store.getActions().map(e => e.type)
         expect(actionsTypes).has.members(expectedActionTypes);
         expect(actionsTypes.length).equal(3);
    })
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM