简体   繁体   中英

Check if a function was called in testing mode

I have this javascript code that make a get request. It works fine.

 export const getReq = () => { fetch( 'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits', ).then((response) => { let status = null; if (response.status === 200) { status = response.status; } else { status = 'error'; } if (status === 200) { alert('success'); } else { alert('Error'); } return response.json(); }).then((commits) => { return commits.map(({sha}) => sha)[0]; }); };

I want to test if my function that fetch was called:

 import { getReq } from './getReq'; jest.mock('./getReq', () => ({ getReq: () => 123 })); describe('success', () => { test('check if was caled', async () => { const sha = await getReq(); expect(sha).toHaveBeenCalled(); }); });

Doing this test i get the next error: Matcher error: received value must be a mock or spy function
How to test if my function that make a get request was called?

From your test, it's not entirely clear whether you know what getReq is supposed to do. You mock it out* to return 123 , but assuming the implementation is mostly correct it would actually return a promise of an array of strings where each string is the first character of a sha (actually it returns undefined, because you don't return the promise chain, and maybe you actually wanted it to return the complete sha of the first commit rather than the first character of the sha for every commit?)

Similarly in your previous attempt your mock for fetch didn't make sense:

global.fetch = jest.fn(() => {
  return Promise.resolve(123);
});

Your code certainly doesn't expect fetch to return a promise of 123 , it expects it to return a promise of a response object with a status prop and a json method that returns a promise of an array of objects with sha props. Your test doubles need to have the same interface as the thing they're replacing, or they're pointless.

Broadly, I would expect a test for this function to look like:

import { getReq } from "./getReq";

it("works", async () => {
  global.alert = jest.fn();  // otherwise 'Error: Not implemented: window.alert'
  global.fetch = jest.fn().mockResolvedValueOnce({
    json: () => Promise.resolve([
      /* from https://developer.github.com/v3/repos/commits/#list-commits */
      { sha: "6dcb09b5b57875f334f61aebed695e2e4193db5e" },
      { sha: "f103561f390825e76f196ce952a982542861fef3" },
    ]),
    status: 200
  });

  const result = await getReq();

  expect(global.alert).toHaveBeenCalledWith("success");
  expect(global.fetch).toHaveBeenCalledWith(
    "https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits"
  );
  expect(result).toEqual(["6", "f"]); // or maybe "6dcb09b5b57875f334f61aebed695e2e4193db5e"?
});

This will currently fail on the last expectation for the reason I hint at above.

Alternatively you could split that up into three tests: makes the right request, sends the right alert, returns the right result. There should also be tests for the unhappy paths, eg if the request returns non-200 (should you still be assuming the response.json() will be fine in that case?)

You could also look into MSW for an approach to testing that's less tightly coupled to the fetch API (we shouldn't really be mocking what we don't own).

* Your test is of a mock, there's no production code involved. Don't mock the thing you're supposed to be testing.

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