jefflau / jest-fetch-mock

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

Adds mockMatchingResponses #102

Closed eatspaint closed 4 years ago

eatspaint commented 5 years ago

Proposal to add mockMatchingResponses function that will allow similar functionality to mockResponses, but with the added specification of patterns to match on the fetch URI.

Inspired by my own needs with jest-mock-fetch at work, as well at #95

jefflau commented 5 years ago

Thanks for having a go at this! I'm wondering how someone might use this in conjunction with mockResponseOnce or mockResponses.

I'm thinking something like. You have 5 requests. Two are conditional requests that will come back first (both will resolve before the next 3, let's say in a Promise.all and then 3 in order. Would all 3 have to be done through mockMatchingResponses or would you have an API with a combination of mockMatchingResponses and also once.

eatspaint commented 5 years ago

Would all 3 have to be done through mockMatchingResponses or would you have an API with a combination of mockMatchingResponses and also once.

My initial thought would be that if you were using mockMatchingResponses, it would be responsible for all mocking (for a given scope), and would be used as an alternative to once, rather than in conjunction with it.

jefflau commented 5 years ago

I think it makes a lot of sense. I was thinking maybe we want to be able to support a chained version without an array.

fetch
  .mockMatchingResponse(/apple/, JSON.stringify({ name: 'apple' })
  .mockMatchingResponse(/twitter/, JSON.stringify({ name: 'apple' })

or possibly what @ivan-kleshnin suggested:

  fetch.on("/blog/").mockResponseOnce(...)
       .on("/blog/post/").mockResponseOnce(...)

Also, we would also need a way of supporting rejects in the same syntax I think. The question is, would we have a separate method for that such as mockMatchingReject, or use mockMatchingResponses and allow them to pass an option.

yinzara commented 5 years ago

I feel like this is covered by just allowing the function you can pass to mockResponse to take in the arguments to fetch and allow returning a string as the response (I've added #123 that covers these conditions plus adds special handling to unmock conditionally).

fetch.mockResponse(async (input) => {
    const url = typeof input === 'string' ? input : input.url
    if (/apple/.exec(url)) {
        return JSON.stringify({ name: 'apple' })
    } else if (/twitter/.exec(url)) {
        return JSON.stringify({name: 'twitter'})
    } else {
        throw new Error("Invalid url")
    }
})

This also allows much more dynamic variations in the responses based on the request and supports all the special case functions like fetch.mockResponses without adding or changing the API to the library except the types supported by the functions (in a backwards compatible way)

yinzara commented 4 years ago

Closing in favor of syntax suggested above incorporated into PR #128