Msw: req.params empty when req.query param is present

Created on 5 May 2020  路  3Comments  路  Source: mswjs/msw

Describe the bug

When mocking a path with a param and requesting with a query param the req.param object is empty.

Environment

  • msw: 0.15.5
  • nodejs: 12.15.0
  • npm: 6.13.4

Please also provide your browser version.

To Reproduce

Steps to reproduce the behavior:

  1. Define a mock with a param in the path '/api/v3/registries/:registryId/reg_items'
  2. Request that path with a query param '/api/v3/registries/123/reg_items?hello=true'
  3. req.param is empty in body of the mocked endpoint.

Expected behavior

req.param should have registryId with the value of 123 and req.query.get('hello') should be true.

Screenshots

import { composeMocks, rest } from 'msw'
import faker from 'faker'

import { recommendedProduct } from './responders'

const RESPONSE_STATUS = {
  SERVER_ERROR: 500,
}

/**
 * Patterns for returning different error responses.
 */
const resourceErrorStatus = id => {
  switch (id) {
    case '!!!':
      return RESPONSE_STATUS.SERVER_ERROR
    default:
      return null
  }
}

// Configure mocking routes
const { start } = composeMocks(
  rest.post('/api/v3/registries/:registryId/reg_items', (req, res, ctx) => {
    // Access request's params
    const { registryId } = req.params // 鈿狅笍 is undefined when ?include_recommendation present
    const {
      reg_item: { product_id },
    } = req.body
    const includeAddNext = req.query.get('include_recommendation')

    const errStatus = resourceErrorStatus(registryId)
    if (errStatus) {
      return res(ctx.status(errStatus), ctx.json({ error: 'Whoops' }))
    }

    const resJson = {
      regItem: {
        ...(includeAddNext && {
          addNextRecommendation: {
            metadata: {
              modelVersion: faker.random.uuid(),
              registryId: Number(registryId),
              sourceProductId: product_id,
            },
            recommendedProducts: [
              recommendedProduct(),
              recommendedProduct(),
              recommendedProduct(),
            ],
          },
        }),
      },
    }

    return res(
      // Set custom status
      ctx.status(200),

      // Set headers
      ctx.set({ 'X-Header': 'Mocked value' }),

      // Delay the response
      ctx.delay(1000),

      // send JSON response body
      ctx.json(resJson)
    )
  })
)

/* Start the Service Worker */
start()
bug

Most helpful comment

Thanks for the speedy fix and thorough walkthrough!

All 3 comments

Hey, @derekr. Thanks for reporting this. Looks like something is wrong with applying the mask to request's URL. That's where MSW gets the parameters. URL query should not be taken into account during this process.

I'll double check and update here.

The issue is fixed and will be released in the next patch release 0.15.6.

Insights

I've discovered that query parameters were not stripped off when passing the actual URL to the path matching function. This resulted into broken matching.

To properly fix it, I strip request URL query parameters and hashes in both predicate for each request, and within the path matching function:

https://github.com/mswjs/msw/blob/0011e9972305cf4a0c869f5eb01ac617d340c401/src/handleRequestWith.ts#L62-L66

The match function we use from node-match-path always performs a strict matching when given a URL string. So in our case we need to pass the "clean" URL for the matching to be precise.

Trailing path parameters

During the debugging I've discovered that when a query parameter follows a trailing path parameter, its being matches as a part of a path parameter. Consider:

match('/user/:userId', '/user/abc-123?hello=true')
// { params: { userId: 'abc-123?hello=true' } }

I've treated this as an issue originally, but when compared to how path-to-regexp (used by Express) works, it also captures that trailing query as a part of a path parameter:

Screen Shot 2020-05-06 at 09 46 02

I'd love to maintain a compatibility with Express path matching to grant the best experience for users who are already familiar with Express. I will live this trailing query behavior as-is for now.

Thanks for the speedy fix and thorough walkthrough!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

balavishnuvj picture balavishnuvj  路  4Comments

kettanaito picture kettanaito  路  3Comments

danielstreit picture danielstreit  路  3Comments

Afsoon picture Afsoon  路  3Comments

baker-travis picture baker-travis  路  3Comments