Msw: Path matching not working as expected in browser environment

Created on 13 Oct 2020  路  5Comments  路  Source: mswjs/msw

Environment

| Name | Version |
| ------- | ------- |
| msw | 0.21.2 |
| browser | Firefox 82.0b7 |
| OS | MacOS 10.15.6 |

Issue

Hello! This might be more of a documentation issue (but would love to see it becoming a feature request as well). I recently started using MSW in a CRA application to mock Axios calls.

Specifying only the paths (not the complete URL) to MSW handlers doesn't work.
Example:

 rest.get("/people/3/", (_req, res, ctx) => {
  ...
}

This could be a trip up on my behalf since I found the Path with parameters section example under the Path section (and coming from using axios-mock-adapter, which lets me specify paths to intercept requests). Writing up this repro + issue report has clarified the behaviour a bit, but took me a couple of hours of scratching my head to get here.

If you can confirm that the behavior below is as expected, would love to see the documentation updated to use consistent examples in the Path section (i.e. just API paths or complete URLs with params, rather than both, since the notation is new for people like me coming from a non-Node/Express background). Or to have the feature supported as well (#406 might solve for this, I guess). I can raise a PR for the former if needed, based on your confirmation.

For now, I work around this issue in my project by specifying the path in my matcher as (I maintain all endpoints in one file, hence the variable):

rest.get(`*${endpoints.FETCH_C3PO}`, (_req, res, ctx) => {
  ...
}

I created a quick, dummy example with the issue: ghostwriternr/msw-pathmatch-example

Request handlers

Endpoints:

const FETCH_C3PO = `/people/2/`;
const FETCH_R2D2 = `/people/3/`;

export const endpoints = {
  FETCH_C3PO,
  FETCH_R2D2,
};

Handlers:

export const handlers = [
  rest.get(endpoints.FETCH_C3PO, (_req, res, ctx) => {
    return res(ctx.status(200), ctx.json(mockedResponses.c3poData));
  }),
  rest.get("https://swapi.dev/api/people/3/", (_req, res, ctx) => {
    return res(ctx.status(200), ctx.json(mockedResponses.r2d2Data));
  }),
];

Actual request

const starWarsAxiosInstance = Axios.create({
  baseURL: "https://swapi.dev/api",
});

const fetchBot = (bot: "c3po" | "r2d2") => {
  return starWarsAxiosInstance.get<BotData>(
    bot === "c3po" ? endpoints.FETCH_C3PO : endpoints.FETCH_R2D2
  );
};

Current behavior

Only /people/3/ endpoint, whose handler specifies the whole URL instead of just the path, is mocked by MSW.

Expected behavior

Both endpoints to be mocked by MSW.

Screenshots

Screenshot 2020-10-13 at 5 01 51 AM

Credits

I have recently started using MSW and can't thank the maintainers enough for how brilliant and simultaneously easy this is to use. Definitely loved the step-by-step getting started documentation as well. Thanks a ton!

docs potentially solved question browser

All 5 comments

Hey, @ghostwriternr. Thanks for reaching out and for the kind words.

I think it's a matter of familiarity towards how path matching usually works with JavaScript server frameworks. Sorry if the docs don't reflect that fully, that's a chance to improve on the library's side for sure.

Speaking of path's relativity, this is what you should expect:

  • /user matches against the current location. For example, if your website is on https://mysite.com, then /user transforms into https://mysite.com/user (this includes subdomains and ports).
  • https://api.github.com (absolute URL) always stays absolute, no matter what host your website is on.
  • */user matches both relative and absolute URL ending with /user. Be careful about this option, as you almost never want to match different origin URL that end on the same path. For example, */user would match both ${window.location}/user and https://api.github.com/user, and even https://anything.really/foo/bar/user.

Let me know if this makes things more clear.

Note that there's a Path matching REPL in our docs where you can test out request handler URL and your actual request URL.

If you put there /api/people/3 in the first input (request handler URL) and https://swapi.dev/api/people/3 in the second input (actual request URL) you will see there's no match, and that's expected.

I took this issue as an opportunity to improve the "Path matching" page in the docs.

It will guide you through how the matching works for REST and GraphQL requests, as well as mention some previously omitted nuances in the library's behavior. I hope the page is much more useful now.

@kettanaito that was super fast! Thank you so much for your patience and detailed explanations. The documentation update is super helpful, along with the REPL, and I'm able to understand & write the MSW handlers in our project properly. Your help is much much appreciated :grin: :tada:

My pleasure, @ghostwriternr! Documentation is something we constantly iterate on as people share their struggle and ask questions. I'm super happy to get a chance to improve that page. Don't hesitate to reach out with questions. Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

abrudin picture abrudin  路  3Comments

danielstreit picture danielstreit  路  3Comments

dashed picture dashed  路  3Comments

Afsoon picture Afsoon  路  3Comments

hauptrolle picture hauptrolle  路  4Comments