jefflau / jest-fetch-mock

Jest mock for fetch
MIT License
881 stars 116 forks source link

Please support all acceptable types for the Response constructor #218

Open andreasg123 opened 2 years ago

andreasg123 commented 2 years ago

In addition to string, the Response constructor supports several other types. That is important for mocking an arrayBuffer response.

Unfortunately, the typing for MockResponseInitFunction only supports string. The following works but requires an ugly cast:

const buffer = new Float32Array(10).buffer;
fetchMock.mockResponse(req => Promise.resolve({ body: buffer as unknown as string }));

As a bonus, it would be nice if these other types could be checked in addition to string to allow for the shorter form that doesn't require an object with a body property.

andreasg123 commented 2 years ago

Alternatively, you could allow for Promise<Response> to be returned by MockResponseInitFunction.

alexkolson commented 2 years ago

Hi @andreasg123! I went ahead and tried my hand at supporting this in #223. What do you think?

ptim commented 2 years ago

Agh, took me a while to find this issue - this issue is nuking my tests in a cloudflare workers environment, where I'm attempting to test the result of new HTMLRewriter().transform(response), which throws:

TypeError: body.pipeTo is not a function

Also, I've found that if I make any calls in a given test file to fetchMock, then any test calling HTMLRewriter.transform in that file fails as above, even when no fetch calls occur!! This holds true even when the only fetchMock.enable(); fetchMock.mockResponseOnce() calls are in a skipped test, and even when I call disable and reset in beforeEach, afterEach, etc... Had to move all tests using fetchMock into a different file to stay sane!

I tried your fork @alexkolson (thanks!) but didn't manage to get it working for my case:

let response = new Response(
  createMinimalHtml(),
  { headers: { 'content-type': 'text/html' } }
)

fetchMock.enableMocks()
fetchMock.mockResponseOnce(response)

// (in the functional tests, fetch is called deep in another handler)
response = await fetch('/')
response = rewriteHtmlResponse(response, ctx)

Tried various combinations of fudging types and passing responseInit per @andreasg123 suggestions, but no dice yet.

fetchMock.mockResponseOnce(
    (_req) =>
      Promise.resolve({
        body: response.body as unknown as string, // text/plain, no body.pipeTo
      }),

    // if using [Pull Request #223 · jefflau/jest-fetch-mock](https://github.com/jefflau/jest-fetch-mock/pull/223)
    // response as unknown as string, // text/plain
    // (req) => Promise.resolve(response) as unknown as string, // text/html, but no body.pipeTo
  )