Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow passthrough for undefined routes / graphql interferes with passthrough #234

Closed
ilovett opened this issue Jun 19, 2020 · 16 comments · Fixed by #265
Closed

allow passthrough for undefined routes / graphql interferes with passthrough #234

ilovett opened this issue Jun 19, 2020 · 16 comments · Fixed by #265

Comments

@ilovett
Copy link

ilovett commented Jun 19, 2020

Describe the solution you'd like

I'd like to be able to allow certain matching urls to be passed through and handled normally instead of intercepting and giving 404.

Describe alternatives you've considered

Seems like a lot of work to manually define ctx.fetch for each request I would want to pass through on some wildcard domain / string match.

@ilovett
Copy link
Author

ilovett commented Jun 19, 2020

In particular I'm having trouble with auth0 and jwt token verification... if I mock it the jwt can't be verified... otherwise it seems like I need to setup SSL certificate for my local development to be on HTTPS in order to be able to fetch downstream auth0? An auth0 recipe may be helpful.

@kettanaito
Copy link
Member

kettanaito commented Jun 19, 2020

Hey, @ilovett. Thanks for raising this.

Just to clarify: if your response resolver doesn't return anything, that request will be bypassed, even if it matches a predicate. To illustrate, this should log out each GET request your app makes, while performing them as-is:

rest.get('*', (req, res, ctx) => {
  console.log(req.url.href)
  // Notice no `return res()` statement
})

You can utilize that behavior to conditionally short circuit in a resolver:

res.get('/auth', (req, res, ctx) => {
  if (someCondition) {
    // Return nothing, thus, bypassing this request
    return null
  }

  // Return a mocked response
  return res(...)
})

Also, any request that does not have a corresponding request handler is performed passthrough by default. If I understand correctly, the absence of a request handler is what you mean by "for undefined routes". Did I get it correctly? (It would be very helpful if you included an example of what you are talking about, even if in pseudo-code).

An auth0 recipe may be helpful.

A good point 👍 We may have to list such recipe on the docs. Perhaps, even as an outcome of our discussion here!

@ilovett
Copy link
Author

ilovett commented Jun 19, 2020

Thanks @kettanaito ! Yes looks like I was also searching for "passthrough" and not "bypass" :(

returning nothing definitely works! -- although I did not understand this from the docs, and also I get type errors using your solution -- I got around it by:

  (rest as any).post('https://my.auth0.com/oauth/token', () => {
    return;
  }),

Here's the type error with using any

 Type 'void' is not assignable to type 'MockedResponse | Promise<MockedResponse>'.ts(2345)

A couple things about the docs:

  • some how I ended up on https://redd.gitbook.io/msw/api/compose-mocks thinking that was the official docs? it does have search functionality which is nice

  • after finding mswjs.io/docs -- I think bypass and (as I was searching "passthrough") could be more prevalent.

I might also make it a default option on .start({ bypassUnmocked: true }) or something to that effect.

Returning nothing to bypass was not clear to me -- I thought I needed to return ctx.fetch(req) as per https://redd.gitbook.io/msw/recipes/query-parameters#conditional-mocking

To answer your Q:

If I understand correctly, the absence of a request handler is what you mean by "for undefined routes".

Yes, undefined routes might automatically be allowed passthrough based on that config setting. Similar to axios-mock-adapter has the passthrough option.

IE if absent handlers, then allow the original request to go through

@kettanaito
Copy link
Member

kettanaito commented Jun 20, 2020

Docs at https://redd.gitbook.io/msw is the previous version. I highly recommend to use https://mswjs.io, as it's the latest (and the only) maintained docs now. It's also been largely rewritten and contains up-to-date information.

I get type errors using your solution.

My bad, try using return null instead of return. Refrain from X as any, that way you lose any types suggestions.

At this point I'm confused what's the difference between bypassing and passthrough. Don't they both mean "perform request as-is and do not mock"?

As I've said, all requests that don't have associated handlers are performed as-is. In fact, as of now there's no way to fail a request that's not mocked (a feature described in #191).

Note that having a handler like this is redundant:

rest.get('/path', (req, res, ctx) => {
  return
})

It's absolutely the same as not having that handler at all (remove it and see what happens).

What I'm trying to say, is that if you don't have any rest.post() handler for POST https://my.auth0.com/oauth/token, that request must always be performed as-is.

Sorry, I think I still don't fully understand the problem. Could you elaborate more, what exactly is the current setup, the problem (behavior/errors/etc.), and what's the expected behavior?

@ilovett
Copy link
Author

ilovett commented Jun 22, 2020

At this point I'm confused what's the difference between bypassing and passthrough. Don't they both mean "perform request as-is and do not mock"?

Yes

My bad, try using return null instead of return. Refrain from X as any, that way you lose any types suggestions.

No problem, but we would need to add | void | null to the response handler type... something like:

=> Promise<MockedResponse> | MockedResponse | void | null;

It's absolutely the same as not having that handler at all (remove it and see what happens).

When I comment out the handlers I get 500 errors on my auth0 and sentry... (but work as expected with void handlers)

mockServiceWorker.js:150 [MSW] Request handler function for "POST https://my.auth0.com/oauth/token" has thrown the following exception:

Error: Must provide Source. Received: undefined.
(see more detailed error stack trace in the mocked response body)

This exception has been gracefully handled as a 500 response, however, it's strongly recommended to resolve this error.
If you wish to mock an error response, please refer to this guide: https://redd.gitbook.io/msw/recipes/mocking-error-responses  

Here's my config:

import { setupWorker, rest } from 'msw';

const worker = setupWorker(

  // works / "perform as is"
  (rest as any).post('https://my.auth0.com/oauth/token', () => undefined),
  (rest as any).post('https://sentry.io/*', () => undefined),

  // throws 500 without being defined
  // (rest as any).post('https://my.auth0.com/oauth/token', () => undefined),
  // (rest as any).post('https://sentry.io/*', () => undefined),

  rest.get('/users', (req, res, ctx) => {
    return res(
      ctx.status(200),
      ctx.json([
        { firstName: 'John', lastName: 'Maverick' },
        { firstName: 'Cathaline', lastName: 'McCoy' },
      ])
    );
  }),

);

worker.start();

I am on [email protected]

@stevecaldwell77
Copy link

I'm running into a similar issue - I've enabled a GraphQL handler, and I'm now getting errors trying to do POSTS to my authentication server (using REST). I'm getting this error:

[MSW] Request handler function for "POST https://xxxxx" has thrown the following exception:

Error: Must provide Source. Received: undefined.
(see more detailed error stack trace in the mocked response body)

which looks like it's coming from the graphql package. It appears that when you enable a GraphQL handler it traps all POST requests? Is there no way to mock GraphQL requests but let other POSTS go through without mocking?

@marcosvega91
Copy link
Member

Hy guys I understand your problem.

Requests without a specific handler throw that error.

At the moment you cannot pass through a request without defining an handler for that request.

For me it can be considered a bug, I think is not correct to return that error in this case, maybe a warning should be better.

What do you think @kettanaito ?

@kettanaito
Copy link
Member

Since a GraphQL request is still a regular HTTP request (GET/POST with a certain query/body according to the GraphQL specification), one cannot distinguish the two, unless a more narrow match is performed.

The issue you are experiencing is most likely when a graphql handler attempts to parse a regular POST REST API request, it encounters an exception and propagates it to you via that error message you've posted. That is definitely an issue, as GraphQL operations matching must not throw when given a REST API request (should figure out it's not a GraphQL request, and bypass).

What interests me, is that POST https://my.auth0.com/oauth/token throws the same exception: Error: Must provide Source. Received: undefined.. The relevant example doesn't seem to use any graphql handlers, so the reason for the issue may lie elsewhere than that request handler type.

@ilovett
Copy link
Author

ilovett commented Jun 28, 2020

OK I think I figured it out. Sorry, in my snippet I did not include my graphql queries as I thought it was irrelevant for simplicity.

But yes, I did have some graphql queries defined.

I think if any graphql queries are defined, then that interferes with the "not defined" pass through because it must be listening to "every (other) request" and so in that case, not defining won't work.

@ilovett ilovett changed the title allow passthrough for undefined routes allow passthrough for undefined routes / graphql interferes with passthrough Jun 28, 2020
@benmonro
Copy link
Contributor

@kettanaito I could use this feature as well for testcafe support. testcafe has some internal posts it makes back to it's proxy server, and we can't add headers to those requests. I noticed that if i just add resolve(getOriginalResponse()); to the INTERNAL_ERROR handler in mockServiceWorker.js it works, but that felt wrong to do.

@kettanaito
Copy link
Member

Please, could you update on the latest state of this issue? Is it still reproducible? If yes, please, could you set up a reproduction repository for us to look? Thank you.

@kettanaito
Copy link
Member

I believe this issue is caused by the request handler lookup mechanism internally. We are tackling it as a part of #258.

@kettanaito
Copy link
Member

@ilovett, hi. Could you please update to [email protected] and let us know if this issue is resolved? Thanks.

@ilovett
Copy link
Author

ilovett commented Aug 7, 2020

@kettanaito Unfortunately I can't use [email protected] in browser with auth0 or sentry, with or without the following handlers:

  (rest as any).post('https://my.auth0.com/*', () => undefined),
  (rest as any).post('https://sentry.io/*', () => undefined),

I get these errors:

"{"errorType":"Error","message":"Must provide Source. Received: undefined.","location":"Error: Must provide Source. Received: undefined.\n    at devAssert (http://localhost:3000/static/js/1.chunk.js:153124:11)\n    at new Parser (http://localhost:3000/static/js/1.chunk.js:154692:36)\n    at parse (http://localhost:3000/static/js/1.chunk.js:154685:16)\n    at parseQuery (http://localhost:3000/static/js/1.chunk.js:156187:15)\n    at Object.parse (http://localhost:3000/static/js/1.chunk.js:156235:19)\n    at http://localhost:3000/static/js/1.chunk.js:156647:65\n    at Array.map (<anonymous>)\n    at http://localhost:3000/static/js/1.chunk.js:156643:6\n    at Generator.next (<anonymous>)\n    at http://localhost:3000/static/js/1.chunk.js:156429:67\n    at new Promise (<anonymous>)\n    at __awaiter (http://localhost:3000/static/js/1.chunk.js:156408:10)\n    at getResponse (http://localhost:3000/static/js/1.chunk.js:156639:40)\n    at http://localhost:3000/static/js/1.chunk.js:156837:17\n    at Generator.next (<anonymous>)\n    at http://localhost:3000/static/js/1.chunk.js:156429:67\n    at new Promise (<anonymous>)\n    at __awaiter (http://localhost:3000/static/js/1.chunk.js:156408:10)\n    at ServiceWorkerContainer.<anonymous> (http://localhost:3000/static/js/1.chunk.js:156795:19)"}"

I was able to get 0.20.2 working -- restarting the dev server and a new incognito session in between versions

@kettanaito
Copy link
Member

@ilovett, I believe that the "Must provide Source" issue has been triaged and PR has been issued (#329).

@ilovett
Copy link
Author

ilovett commented Aug 18, 2020

thanks @kettanaito , just upgraded to 0.20.5 and it works without the empty handlers!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants