0

I have a common api class that i use for handling api calls in React Native. It will make the call and get the json/ error and return it. See the code below.

// General api to acces data from web
import ApiConstants from './ApiConstants';
export default function api(path,params,method, sssid){

    let options;
        options = Object.assign({headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        }},{ method: method }, params ? { body: JSON.stringify(params) } : null );


    return fetch(ApiConstants.BASE_URL+path, options).then( resp => {
        let json = resp.json();
        if (resp.ok) {
            return json;
        }
        return json.then(err => {
            throw err;
        }).then( json => json );
    });
}

But when i write the jest test to mock the api as folllows in tests folder.

test('Should login',() => {
    global.fetch = jest.fn(() => new Promise((resolve) => {
        resolve( { status: 201, json: () => (mock_data_login) });
    }));

    return Api(ApiConstants.LOGIN,{'un':'test1','pwd':'1234'},'post', null).then((data1)=>{

        expect(data1).toBeDefined();
        expect(data1.success).toEqual(true);
        expect(data1.message).toEqual('Login Success');
    });

});

it fails with:

TypeError: json.then is not a function

When I change the fetch return to this, the test passes:

 return fetch(ApiConstants.BASE_URL+path, options).then( resp => {
            let json = resp.json();
            return json
        });
    }

Why is this type error error popping up? I can't change the API module, because that will my redux saga code to change. What should I do?

Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
Victor
  • 4,171
  • 1
  • 29
  • 37

3 Answers3

1

In your code, json is just an Object and not a Promise, so then is undefined. That's the complain you are getting because you are trying to use undefined as a function. The problem is not in the test but in your code that ha san error. Try the following instead.

return fetch(ApiConstants.BASE_URL+path, options)
        .then(resp => resp.json())
        .then( json => json)
        .catch((error) => error);
    });
Carlos C
  • 637
  • 3
  • 17
  • But the api call works fine. I will try your answer and if i find it useful I'll mark this as accepted – Victor Aug 21 '17 at 06:56
  • On successful responses that probably is not hit because it returns before it happens. Your mock response probably does not have an "ok" property, so it keeps going until it hits the problem. – Carlos C Aug 21 '17 at 07:26
1

Edit: oh, just read you can't make changes to the component where the error occurs?

Try converting your fetch like this:

return fetch(ApiConstants.BASE_URL+path, options)
.then(resp => {
  let json = resp.json();
  if (resp.ok) {
    return json;
  } else {
    throw Error(resp.error) // assuming you have some kind of error from endpoint?
  }
})
.then(/*handle your ok response*/)
.catch(/*handle your error response*/);
Samuli Hakoniemi
  • 18,740
  • 1
  • 61
  • 74
1

I faced the same issue, The problem is that you are mocking only response.json as function but it should be a Promise, Like this,

 global.fetch = jest.fn(() => new Promise((resolve) => {
    resolve( { status: 201, json: () => {
         return Promise.resolve(mock_data_login);
       } 
    });
}));

This will return a Promise for you json function.

Hope this fix your problem.

Vipul Panth
  • 5,221
  • 4
  • 16
  • 27