question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Request bodies of URLSearchParams can not be read

See original GitHub issue

Prerequisites

Environment check

  • I’m using the latest msw version
  • I’m using Node.js version 14 or higher

Node.js version

v16.13.0

Reproduction repository

https://github.com/markdon/cra-msw

Reproduction steps

clone repo npm i DEBUG=* npm run test -- --watchAll=false

Current behavior

I think this is related to https://github.com/mswjs/msw/issues/1318

When handling a fetch request where the request body is a URLSearchParameters object, the body can not be read in the handler. This was previously available through request.body (v0.27.1). request.body is now deprecated.

I would expect to be able to just use the newer request.text(), however this seems to throw an error parsing the body.

Debug logs. See ERR_INVALID_ARG_TYPE
➜  cra-msw git:(main) DEBUG=* npm run test -- --watchAll=false

cra-msw@0.1.0 test react-scripts test “–watchAll=false”

babel:config:loading:files:plugins Loaded preset ‘/Users/mark/projects/cra-msw/node_modules/babel-preset-react-app/index.js’ from ‘/Users/mark/projects/cra-msw’. +0ms babel:config:loading:files:plugins Loaded preset ‘/Users/mark/projects/cra-msw/node_modules/babel-preset-jest/index.js’ from ‘/Users/mark/projects/cra-msw’. +2ms http constructing the interceptor… +0ms xhr constructing the interceptor… +0ms setup-server constructing the interceptor… +0ms http:on adding “request” event listener: setupServerListener +0ms async-event-emitter:on adding “request” listener… +0ms xhr:on adding “request” event listener: setupServerListener +0ms async-event-emitter:on adding “request” listener… +0ms http:on adding “response” event listener: +0ms async-event-emitter:on adding “response” listener… +0ms xhr:on adding “response” event listener: +0ms async-event-emitter:on adding “response” listener… +0ms setup-server:apply applying the interceptor… +0ms async-event-emitter:activate set state to: ACTIVE +0ms setup-server:apply activated the emiter! ACTIVE +0ms setup-server retrieved global instance: undefined +4ms setup-server:apply no running instance found, setting up a new instance… +1ms setup-server:setup applying all 2 interceptors… +0ms setup-server:setup applying “ClientRequestInterceptor” interceptor… +0ms http:apply applying the interceptor… +0ms async-event-emitter:activate set state to: ACTIVE +0ms http:apply activated the emiter! ACTIVE +0ms http retrieved global instance: undefined +4ms http:apply no running instance found, setting up a new instance… +0ms http:setup native “http” module patched! +0ms http:setup native “https” module patched! +0ms http set global instance! http +0ms setup-server:setup adding interceptor dispose subscription +1ms setup-server:setup applying “XMLHttpRequestInterceptor” interceptor… +0ms xhr:apply applying the interceptor… +0ms async-event-emitter:activate set state to: ACTIVE +0ms xhr:apply activated the emiter! ACTIVE +0ms xhr retrieved global instance: undefined +5ms xhr:apply no running instance found, setting up a new instance… +0ms xhr:setup patching “XMLHttpRequest” module… +0ms xhr:setup native “XMLHttpRequest” module patched! XMLHttpRequestOverride +0ms xhr set global instance! xhr +0ms setup-server:setup adding interceptor dispose subscription +0ms setup-server set global instance! setup-server +1ms xhr:request POST /login open { method: ‘POST’, url: ‘/login’, async: true, user: undefined, password: undefined } +0ms xhr:request POST /login reset +1ms xhr:request POST /login readyState change 0 -> 1 +1ms xhr:request POST /login triggering readystate change… +0ms xhr:request POST /login trigger “readystatechange” (1) +0ms xhr:request POST /login resolve listener for event “readystatechange” +0ms xhr:request POST /login set request header “content-type” to “application/x-www-form-urlencoded;charset=UTF-8” +0ms xhr:request POST /login send POST /login +0ms xhr:request POST /login request headers HeadersPolyfill { [Symbol(normalizedHeaders)]: { ‘content-type’: ‘application/x-www-form-urlencoded;charset=UTF-8’ }, [Symbol(rawHeaderNames)]: Map(1) { ‘content-type’ => ‘content-type’ } } +1ms xhr:request POST /login emitting the “request” event for 1 listener(s)… +0ms async-event-emitter:emit emitting “request” event… +0ms async-event-emitter:openListenerQueue opening “request” listeners queue… +0ms async-event-emitter:openListenerQueue no queue found, creating one… +0ms async-event-emitter:emit appending a one-time cleanup “request” listener… +0ms async-event-emitter:openListenerQueue opening “request” listeners queue… +0ms async-event-emitter:openListenerQueue returning an exising queue: [] +0ms async-event-emitter:on awaiting the “request” listener… +11ms xhr:request POST /login awaiting mocked response… +2ms async-event-emitter:on “TypeError [ERR_INVALID_ARG_TYPE]: The “input” argument must be an instance of ArrayBuffer or ArrayBufferView. Received an instance of URLSearchParams” listener has rejected! +13ms xhr:request POST /login middleware function threw an exception! TypeError: The “input” argument must be an instance of ArrayBuffer or ArrayBufferView. Received an instance of URLSearchParams at new NodeError (node:internal/errors:371:5) at TextDecoder.decode (node:internal/encoding:413:15) at Object.decodeBuffer (/Users/mark/projects/cra-msw/node_modules/@mswjs/interceptors/src/utils/bufferUtils.ts:11:18) at RestRequest.<anonymous> (/Users/mark/projects/cra-msw/node_modules/@mswjs/interceptors/src/IsomorphicRequest.ts:59:12) at step (/Users/mark/projects/cra-msw/node_modules/@mswjs/interceptors/lib/IsomorphicRequest.js:33:23) at Object.next (/Users/mark/projects/cra-msw/node_modules/@mswjs/interceptors/lib/IsomorphicRequest.js:14:53) at /Users/mark/projects/cra-msw/node_modules/@mswjs/interceptors/lib/IsomorphicRequest.js:8:71 at new Promise (<anonymous>) at Object.<anonymous>.__awaiter (/Users/mark/projects/cra-msw/node_modules/@mswjs/interceptors/lib/IsomorphicRequest.js:4:12) at RestRequest.Object.<anonymous>.IsomorphicRequest.text (/Users/mark/projects/cra-msw/node_modules/@mswjs/interceptors/lib/IsomorphicRequest.js:73:16) { code: ‘ERR_INVALID_ARG_TYPE’ } +12ms xhr:request POST /login trigger “error” (1) +8ms xhr:request POST /login resolve listener for event “error” +1ms xhr:request POST /login abort +0ms xhr:request POST /login readyState change 1 -> 0 +0ms xhr:request POST /login trigger “abort” (0) +0ms xhr:request POST /login resolve listener for event “abort” +0ms async-event-emitter:emit cleaned up “request” listeners queue! +27ms setup-server:dispose disposing the interceptor… +0ms setup-server retrieved global instance: BatchInterceptor +49ms setup-server cleared global instance! setup-server +0ms setup-server:dispose global symbol deleted: undefined +0ms setup-server:dispose disposing of 2 subscriptions… +0ms http:dispose disposing the interceptor… +0ms http retrieved global instance: ClientRequestInterceptor +51ms http cleared global instance! http +0ms http:dispose global symbol deleted: undefined +0ms http:dispose disposing of 2 subscriptions… +0ms http:setup native “http” module restored! +51ms http:setup native “https” module restored! +0ms http:dispose disposed of all subscriptions! 0 +0ms async-event-emitter:deactivate removing all listeners… +0ms async-event-emitter:removeAllListeners event: undefined +0ms async-event-emitter:removeAllListeners cleared the listeners queue! Map(0) {} +0ms async-event-emitter:deactivate set state to: DEACTIVATED +0ms http:dispose destroyed the listener! +0ms xhr:dispose disposing the interceptor… +0ms xhr retrieved global instance: XMLHttpRequestInterceptor +50ms xhr cleared global instance! xhr +0ms xhr:dispose global symbol deleted: undefined +0ms xhr:dispose disposing of 1 subscriptions… +0ms xhr:setup native “XMLHttpRequest” module restored! XMLHttpRequest +51ms xhr:dispose disposed of all subscriptions! 0 +1ms async-event-emitter:deactivate removing all listeners… +0ms async-event-emitter:removeAllListeners event: undefined +0ms async-event-emitter:removeAllListeners cleared the listeners queue! Map(0) {} +0ms async-event-emitter:deactivate set state to: DEACTIVATED +0ms xhr:dispose destroyed the listener! +0ms setup-server:dispose disposed of all subscriptions! 0 +2ms async-event-emitter:deactivate removing all listeners… +0ms async-event-emitter:removeAllListeners event: undefined +0ms async-event-emitter:removeAllListeners cleared the listeners queue! Map(0) {} +0ms async-event-emitter:deactivate set state to: DEACTIVATED +0ms setup-server:dispose destroyed the listener! +0ms FAIL src/Login.test.ts fetch ✕ can login (35 ms)

● fetch › can login

expect(received).resolves.toBeInstanceOf()

Received promise rejected instead of resolved
Rejected to value: [TypeError: Network request failed]

  2 | describe('fetch', ()=>{
  3 |   it('can login', async ()=>{
> 4 |     await expect(fetch('/login', {
    |           ^
  5 |       method: 'POST',
  6 |       body: new URLSearchParams('username=admin&password=admin')
  7 |     })).resolves.toBeInstanceOf(Response);

  at expect (node_modules/expect/build/index.js:178:15)
  at Object.<anonymous> (src/Login.test.ts:4:11)
  at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
  at runJest (node_modules/@jest/core/build/runJest.js:404:19)
  at _run10000 (node_modules/@jest/core/build/cli/index.js:320:7)
  at runCLI (node_modules/@jest/core/build/cli/index.js:173:3)

Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 0 total Time: 0.834 s, estimated 1 s Ran all test suites.

Expected behavior

A request body of type URLSearchParameters should be able to be read in a handler. I suggest via request.text(), which would return the value of URLSearchParameters.toString().

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:1
  • Comments:12 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
ddolcimascolocommented, Sep 9, 2022

Same issue as mine in #1327 but with FormData bodies. msw just plain broke reading request bodies in v0.44.0.

New features keep getting added in the 0.x line so that it’s totally OK to break stuff from a semver perspective. And bugs are not fixed.

#sadness

1reaction
markdoncommented, Nov 28, 2022

I will check back later!

It looks like a lot of progress has been made towards the Fetch API update that replaces the related code and fixes this issue. There’s a beta available to try.

I had a quick look at making a fix for the current release of msw but @mswjs/interceptors has already moved on from the related IsomorphicRequest class and the Fetch API update looks pretty close to done anyway.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Can't properly send Request Body on the node.js version of ...
Received an instance of FormData Same message with URLSearchParams, except it received an instance of URLSearchParams */ var data = 'client_id=' ...
Read more >
Easy URL manipulation with URLSearchParams
Chrome 49 implements URLSearchParams from the URL spec, an API which is useful for fiddling around with URL query parameters.
Read more >
Request · Cloudflare Workers docs
All properties of an incoming Request object (that is, event.request ) are read only. To modify a request, create a new Request object...
Read more >
URLSearchParams.toString() - Web APIs | MDN
The toString() method of the URLSearchParams interface returns a query string suitable for use in a URL.
Read more >
URL-Encoding Bodies | Axios Docs
To send data in the application/x-www-form-urlencoded format instead, you can use one of ... Note that URLSearchParams is not supported by all browsers...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found