From 4f85d57b709479da4f70000a8c938c6d7f0ff2b2 Mon Sep 17 00:00:00 2001 From: c0per <60544162+c0per@users.noreply.github.com> Date: Sat, 30 Dec 2023 15:10:25 +0800 Subject: [PATCH 1/5] fix: pass raw body to Request --- src/middleware.ts | 11 +++-------- src/server.ts | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/middleware.ts b/src/middleware.ts index 957dce3..8921419 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -7,7 +7,6 @@ import { Emitter } from 'strict-event-emitter' import type { RequestHandler as ExpressMiddleware } from 'express' import type { LifeCycleEventsMap, RequestHandler } from 'msw' -const encoder = new TextEncoder() const emitter = new Emitter() export function createMiddleware( @@ -18,10 +17,8 @@ export function createMiddleware( const method = req.method || 'GET' // Ensure the request body input passed to the MockedRequest - // is always a string. Custom middleware like "express.json()" - // may coerce "req.body" to be an Object. - const requestBody = - typeof req.body === 'string' ? req.body : JSON.stringify(req.body) + // is always the raw body from express req. + // "express.raw({ type: '*/*' })" must be used to get "req.body". const mockedRequest = new Request( // Treat all relative URLs as the ones coming from the server. @@ -31,9 +28,7 @@ export function createMiddleware( headers: new Headers(req.headers as HeadersInit), credentials: 'omit', // Request with GET/HEAD method cannot have body. - body: ['GET', 'HEAD'].includes(method) - ? undefined - : encoder.encode(requestBody), + body: ['GET', 'HEAD'].includes(method) ? undefined : req.body, }, ) diff --git a/src/server.ts b/src/server.ts index d51c8f5..afcb3f9 100644 --- a/src/server.ts +++ b/src/server.ts @@ -5,7 +5,7 @@ import { createMiddleware } from './middleware' export function createServer(...handlers: Array): express.Express { const app = express() - app.use(express.json()) + app.use(express.raw({ type: '*/*' })) app.use(createMiddleware(...handlers)) app.use((_req, res) => { res.status(404).json({ From 46c6bd53f6f0ab36547c87073ac06e9d5ddac68f Mon Sep 17 00:00:00 2001 From: c0per <60544162+c0per@users.noreply.github.com> Date: Sat, 30 Dec 2023 16:42:03 +0800 Subject: [PATCH 2/5] test: with-express-json Use Express.js instead of HttpServer from open-draft since open-draft will automatically convert json request body to Object. With Express.js and express.raw(), everything works fine. --- test/with-express-json.test.ts | 66 +++++++++++++++++----------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/test/with-express-json.test.ts b/test/with-express-json.test.ts index 27ea8cd..6f18762 100644 --- a/test/with-express-json.test.ts +++ b/test/with-express-json.test.ts @@ -3,50 +3,52 @@ */ import fetch from 'node-fetch' import express from 'express' -import { HttpServer } from '@open-draft/test-server/http' import { HttpResponse, http } from 'msw' import { createMiddleware } from '../src' -const httpServer = new HttpServer((app) => { - // Apply a request body JSON middleware. - app.use(express.json()) - - app.use( - createMiddleware( - http.post('/user', async ({ request }) => { - const { firstName } = await request.json() - - return HttpResponse.json( - { firstName }, - { - headers: { - 'x-my-header': 'value', - }, +import httpModule from 'http' +import { AddressInfo } from 'net' + +const app = express() + +app.use(express.raw({ type: '*/*' })) + +app.use( + createMiddleware( + http.post('/user', async ({ request }) => { + const { firstName } = await request.json() + + return HttpResponse.json( + { firstName }, + { + headers: { + 'x-my-header': 'value', }, - ) - }), - ), - ) - - app.use((_req, res) => { - res.status(404).json({ - error: 'Mock not found', - }) + }, + ) + }), + ), +) + +app.use((_req, res) => { + res.status(404).json({ + error: 'Mock not found', }) - - return app }) -beforeAll(async () => { - await httpServer.listen() +const httpServer = httpModule.createServer(app) + +beforeAll(() => { + httpServer.listen({ port: 0 }) }) afterAll(async () => { - await httpServer.close() + httpServer.close() }) -it('supports usage alongside with the "express.json()" middleware', async () => { - const res = await fetch(httpServer.http.url('/user'), { +it('supports usage with json payload', async () => { + const { port } = httpServer.address() as AddressInfo + const res = await fetch(`http://localhost:${port}/user`, { method: 'POST', headers: { 'Content-Type': 'application/json', From 768987cb3a4f7fc6885e59db45564558c3946a56 Mon Sep 17 00:00:00 2001 From: c0per <60544162+c0per@users.noreply.github.com> Date: Sat, 30 Dec 2023 16:56:53 +0800 Subject: [PATCH 3/5] test: multipart/form-data with Express.js --- test/with-express-multipart-form.test.ts | 69 ++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 test/with-express-multipart-form.test.ts diff --git a/test/with-express-multipart-form.test.ts b/test/with-express-multipart-form.test.ts new file mode 100644 index 0000000..3b2d482 --- /dev/null +++ b/test/with-express-multipart-form.test.ts @@ -0,0 +1,69 @@ +/** + * @jest-environment node + */ +import express from 'express' +import { HttpResponse, http } from 'msw' +import { createMiddleware } from '../src' + +import httpModule from 'http' +import { AddressInfo } from 'net' + +const app = express() + +app.use(express.raw({ type: '*/*' })) + +app.use( + createMiddleware( + http.post('/user', async ({ request }) => { + const form = await request.formData() + + const field1 = form.get('field1') + const field2 = form.get('field2') + + if (!field1 || typeof field1 !== 'string') return HttpResponse.error() + if (!field2 || typeof field2 !== 'string') return HttpResponse.error() + + return HttpResponse.json( + { field1, field2 }, + { + headers: { + 'x-my-header': 'value', + }, + }, + ) + }), + ), +) + +app.use((_req, res) => { + res.status(404).json({ + error: 'Mock not found', + }) +}) + +const httpServer = httpModule.createServer(app) + +beforeAll(() => { + httpServer.listen({ port: 0 }) +}) + +afterAll(async () => { + httpServer.close() +}) + +it('supports usage with multipart/form-data payload', async () => { + const form = new FormData() + + form.append('field1', 'value1') + form.append('field2', 'value2') + + const { port } = httpServer.address() as AddressInfo + const res = await fetch(`http://localhost:${port}/user`, { + method: 'POST', + body: form, + }) + + expect(res.status).toBe(200) + expect(res.headers.get('x-my-header')).toBe('value') + expect(await res.json()).toEqual({ field1: 'value1', field2: 'value2' }) +}) From c1e6578c6c0ce49d4d8b1659d89de33a318fa064 Mon Sep 17 00:00:00 2001 From: c0per <60544162+c0per@users.noreply.github.com> Date: Wed, 27 Mar 2024 09:38:45 +0800 Subject: [PATCH 4/5] feat: raise default body size limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: BenoƮt Burgener --- src/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.ts b/src/server.ts index afcb3f9..682e848 100644 --- a/src/server.ts +++ b/src/server.ts @@ -5,7 +5,7 @@ import { createMiddleware } from './middleware' export function createServer(...handlers: Array): express.Express { const app = express() - app.use(express.raw({ type: '*/*' })) + app.use(express.raw({ type: '*/*', limit: '20mb' })) app.use(createMiddleware(...handlers)) app.use((_req, res) => { res.status(404).json({ From fdf0767c3ba58b191e6078bd973c7fce578b1888 Mon Sep 17 00:00:00 2001 From: c0per <60544162+c0per@users.noreply.github.com> Date: Wed, 27 Mar 2024 09:42:20 +0800 Subject: [PATCH 5/5] feat: custom bodyParser options in `createServer` --- src/server.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/server.ts b/src/server.ts index 682e848..bcc403b 100644 --- a/src/server.ts +++ b/src/server.ts @@ -2,10 +2,15 @@ import express from 'express' import { HttpHandler } from 'msw' import { createMiddleware } from './middleware' -export function createServer(...handlers: Array): express.Express { +type ParserOptions = Parameters[0] + +export function createServer( + parserOptions?: ParserOptions, + ...handlers: Array +): express.Express { const app = express() - app.use(express.raw({ type: '*/*', limit: '20mb' })) + app.use(express.raw({ type: '*/*', limit: '20mb', ...parserOptions })) app.use(createMiddleware(...handlers)) app.use((_req, res) => { res.status(404).json({