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.

FormData body is parsed as "[object FormData]" string

See original GitHub issue

Describe the bug

When sending a POST request with a FormData body, the req.body contains a string "[object FormData]" and I can’t get the data that was sent.

Environment

  • msw: 0.26.2
  • nodejs: 14.15.4
  • npm: 6.14.11

Browser version is not relevant as I’m using msw in Jest tests context. Jest version is 26.6.3.

To Reproduce

  1. Send a request from the application with POST method and a FormData object as the body
const form = document.querySelector(".my-form")

fetch("http://localhost/user/register", {
  method: "POST",
  body: new FormData(form)
})
  1. Implement a POST handler in msw and log req.body:
import { rest } from "msw"

export const handlers = [
    rest.post("/user/register", (req, res, ctx) => {
    console.log(req.body, typeof req.body)

    return res(ctx.status(200))
  }),
]
  1. See that you get [object FormData] string as the console.log result

Expected behavior

I expected req.body to be an object like it is in the browser.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

4reactions
kettanaitocommented, Feb 16, 2021

Coming back to you with my findings.

FormData in a browser

As mentioned previously, I’ve got a basic in-browser test working well with constructing FormData and passing it as a request’s body. MSW provides you the request body as serialized FormData (done by fetch), so you could access it in req.body[fieldName].

FormData in DOM-like environment

In a DOM-like environment (i.e. JSDOM), you need to use a FormData polyfill. Jest comes with one, but bear in mind that FormData polyfills are not always compatible with fetch polyfills you decide to use. For instance, this is invalid:

import fetch from 'node-fetch'

fetch('/user', {
  method: 'POST',
  // Types of `BodyInit` of `node-fetch` and Jest's `FormData` polyfill are incompatible. 
  body: new FormData(document.getElementById('user-form')
})

It is when you use an incompatible polyfill for your request client you get the [object FormData] text as your request body. MSW receives whichever request body your client produces, there’s no parsing logic whatsoever (one of the benefits of Service Workers in a browser and native modules monkey-patching in NodeJS).

FormData in NodeJS

Unless you use a polyfill (i.e. form-data-node), there is no FormData in NodeJS. This makes sense, as you don’t have DOM and thus forms to construct that data. Polyfills use a Map-like API to allow you to append/set form fields on the polyfilled FormData instance.

How to get the proper data in the request?

If you use the right FormData polyfill for your request issuing library you’ll get the serialized form data in the request body:

import fetch from 'node-fetch'
import FormDataPolyfill from 'form-data'

const formData = new FormDataPolyfill()
formData.append('username', 'john.maverick')
formData.append('password', 'secret123')

fetch('/user', {
  method: 'POST',
  body: formData
})

I understand this is not ideal, as you’re detaching your test from DOM/JSDOM to act as the source for data. I’d also suggest experimenting with fetch/FormData polyfills to find a suitable combination. Alternatively, consider moving such a test to an actual browser as that would give you the most confidence and you wouldn’t have to deal with polyfills. You can use tools like Cypress for that, or in case you feel like it’s an overkill to pull in a new testing framework you may consider tiny utilities like page-with that still run in an actual browser.

1reaction
drazikcommented, Feb 15, 2021

Thanks @kettanaito for investigating this.

The only difference I see is that you are using setupWorker, so it means you are in a browser context if I’m not mistaken. In my case, I use setupServer because I am in a Jest tests (so node js) context.

The tests I did in the browser showed that it works well in this environment. But in node environement req.body is a string.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using FormData Objects - Web APIs | MDN
The FormData object lets you compile a set of key/value pairs to send using XMLHttpRequest . It is primarily intended for use in...
Read more >
Parse FormData object in nest controller - json - Stack Overflow
This will allow for the parsing of multipart/form-data requests. In your axios call, remove the brackets around bodyContent so it becomes data: ...
Read more >
FormData - The Modern JavaScript Tutorial
The special thing about FormData is that network methods, such as fetch , can accept a FormData object as a body. It's encoded...
Read more >
Using FormData Objects Effectively - YouTube
This video explains how you can use a FormData object to quickly and easily grab all the data from any form and send...
Read more >
Convert Form Data to JavaScript Object - Stack Abuse
Even though it may seem like we've created an empty object, that is not the case. That FormData object has a key-value pair...
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