Search code examples
reactjsjestjsaxiosmoxios

catch is not invoked on moxios reject


I am trying to test the rejection of one of my axios request call using moxios and jest. The method invoke (calling axios.get) throws error but catch block is not invoked.

My test code snippet is shown below,

it('should call errorHandler method when request is rejected', done => {
        const errorResp = {
            status: 400,
            response: {message: 'invalid data'}
        };
        let mockFunction = jest.fn();
        Axios.getRaw('/test').then(mockFunction);
        moxios.wait(async () => {
            let req = moxios.requests.mostRecent();
            try {
                let rejection = await req.reject(errorResp);
                console.log('rejection', rejection);// rejection is undefined
                done();
            } catch (e) {
                console.log(e);
                // test assertions
                done(e);
            }

        })
    });

getRaw method,

const API_WRAPPER = TryCatchHandler.genericTryCatch;

export default {
  getRaw: path => API_WRAPPER(axios.get(`${SERVER_DOMAIN}${path}`)),
}

API_WRAPPER method,

export default {
    genericTryCatch: async (executionMethod) => {
        try {
            const response = await executionMethod;
            return response;
        } catch (error) {
            return ApiError.errorHandler(error);
        }
    }
}

errorHandler method,

export default {
    errorHandler: error => {
        const {status} = error;
        switch (status) {
            case 400:
            case 401:
            case 403:
            case 404:
            case 409:
            case 417:
            case 500:
            case 502:
                console.log("Error Handler says:", error);
                return error.response.data;
            default:
                console.log("Error Handler says:", error);
                let errorObj = {
                    errorMsg: error.message,
                    stack: error.stack
                };
                return errorObj;
        }
    }
}

As the catch block is not invoked I am not able to assert my test cases. How do I get the catch invoked?


Solution

  • There are two things that should be pointed out about the code you provided.

    In the first place, you should take into account that all the requests made with Axios.getRaw are being wrapped with API_WRAPPER. In the case the request results in an error the API_WRAPPER is returning the result of processing the error (through the errorHandler method). Therefore, calling Axios.getRaw will never execute any catch statement present in the call:

    Axios.getRaw('/test').then(function() {
        // The code inside this method will always be executed, even when the request fails.
    }).catch(function() {
        // The code inside this method will never be executed.
    });
    

    In the case of a 400 error (the error you are testing in your test), the errorHandler method is returning the value of error.response.data. But in your test, the error you are creating does not have the data attribute:

    const errorResp = {
        status: 400,
        response: {message: 'invalid data'}
    };
    

    So, in order to get some meaningful data in your test, you should add the data attribute with some value.

    In the second place, I think you are not properly using the moxios library. You are obtaining the most recent request and then you are awaiting for the result of the rejection:

    let rejection = await req.reject(errorResp);
    console.log('rejection', rejection);// rejection is undefined
    

    But calling req.reject does not return a promise (in fact, it does not return anything, that's why you are seeing an undefined in your console.log statement). You should wait for your original Axios.getRaw promise to resolve.

    Having that in mind you can rewrite your test like this:

    it('should call errorHandler method when request is rejected', function(done) {
        const errorResp = {
            status: 400,
            response: { message: 'invalid data', data: 'invalid data' }
        };
    
        // Store the promise so that we can wait for it to finish once we call the moxios reject method.
        const promise = Axios.getRaw('/test');
    
        moxios.wait(async function() {
            let req = moxios.requests.mostRecent();
            req.reject(errorResp);
    
            // As your code does not generate an error in a 400 failed request, we use the then method.
            promise.then(function(err) {
                // In a 400 error, the err.response.data is returned as the response.
                expect(err).toBe('invalid data');
                done();
            });
        });
    });
    

    Hope this helps!