Ruben Marcus
Ruben Marcus

Reputation: 338

Testing Mocked Fetch Api in Jest returns undefined

I have a generic FetchService in React/TS like this:

/* Generic Fetch Service */


const FetchService = {
  call: async (url:string) => {
    try {
      return await fetch(url)
        .then((res) => res.json())
        .then((data) => { data.response});
    } catch (e) {
      throw Error(e);
    }
   }
}

export default FetchService

and a test written like this:

import FetchService from "../../services/Fetch.service";


it("should call Fetch Service", async () => {
  const val = { json: async () => [{ data: { response: "aaa" } }] };

  window.fetch = jest.fn().mockImplementationOnce((url) => {
    if (url === "localhost") {
         return Promise.resolve(val);
    }
  });

  const data = await FetchService.call("localhost");
  expect(data).toBe(undefined);
});

It does succeed to cover the success , but it returns 'undefined', not the data I mocked at response on my test. If I put a console.log in my service, at the data.response, it will log the 'aaa', from the test.

What Im doing wrong?

I´ve tried all the answers here in StackOverflow, as also some tutorials and nothing worked.

Using Jest Docs also didn't helped much.

Anyone could help me out?

Thanks.

Edit:

Solved thanks to the two answers here

/* Generic Fetch Service */

const FetchService = {
  call: async (url: string) => {
    try {
      const response = await fetch(url);
      const data = await response.json();

      console.log(data.response, "data111");
      return data.response;
    } catch (err) {
      throw err;
    }
  },
};
export default FetchService;

and at the test:

const val = {
 json: async () => {
   return { response: "aaa" };
 },
};

it("should call Fetch Service", async () => {
 window.fetch = jest.fn().mockImplementationOnce((url) => {
   if (url === "localhost") {
     return val;
   }
 });

 const data = await FetchService.call("localhost");

 expect(data).toBe("aaa");
});

Upvotes: 1

Views: 2108

Answers (2)

YMH
YMH

Reputation: 189

You're attempting to use "async" while promise chaining, which is not good practice. You have two ways you can handle this.

// with async await
const FetchService = {
    call: async (url:string) => {
      try {
        const response = await fetch(url);
        const data = await response.json();
        return data.response;

      } catch (err) {
        throw err;
      }
     }
  }

//without async await (Promise chaining method)
const FetchService = {
  call: (url:string) => {
    
    return fetch(url)
      .then((res) => res.json())
      .then((data) => data.response)
      .catch(err => {
        throw err
      })
  }
}
  
  export default FetchService

Upvotes: 1

A_A
A_A

Reputation: 1932

You are returning [{ data: { response: "aaa" } }] in your mock and then getting [{ data: { response: "aaa" } }].response in your FetchService (which is undefined).

Depending on what you want, you could modify the expected data in the FetchService, or provide a different sample data in your mock:

const FetchService = {
  call: (url:string) => {
    return fetch(url)
      .then((res) => res.json())
      .then((obj) => { obj[0].data.response});
  }
}

Upvotes: 2

Related Questions