From 7b91f120d22f3221c31b41db43f52b6724387c56 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Fri, 24 Jun 2022 11:48:17 +0300 Subject: [PATCH 1/2] [middleware] add tests for body reading methods --- package.json | 1 + pnpm-lock.yaml | 7 +- .../edge-can-read-request-body/app/.gitignore | 1 + .../app/middleware.js | 49 ++++++++ .../app/package.json | 7 ++ .../app/pages/api/nothing.js | 3 + .../edge-can-read-request-body/index.test.ts | 115 ++++++++++++++++++ 7 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 test/e2e/edge-can-read-request-body/app/.gitignore create mode 100644 test/e2e/edge-can-read-request-body/app/middleware.js create mode 100644 test/e2e/edge-can-read-request-body/app/package.json create mode 100644 test/e2e/edge-can-read-request-body/app/pages/api/nothing.js create mode 100644 test/e2e/edge-can-read-request-body/index.test.ts diff --git a/package.json b/package.json index ff2e619592a7e05..3e7cc5d664ecc65 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@babel/preset-flow": "7.14.5", "@babel/preset-react": "7.14.5", "@edge-runtime/jest-environment": "1.1.0-beta.6", + "@edge-runtime/primitives": "1.1.0-beta.6", "@fullhuman/postcss-purgecss": "1.3.0", "@mdx-js/loader": "0.18.0", "@next/bundle-analyzer": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 965ca3b0ee46afa..e619ace207c2552 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,7 @@ importers: '@babel/preset-flow': 7.14.5 '@babel/preset-react': 7.14.5 '@edge-runtime/jest-environment': 1.1.0-beta.6 + '@edge-runtime/primitives': 1.1.0-beta.6 '@fullhuman/postcss-purgecss': 1.3.0 '@mdx-js/loader': 0.18.0 '@next/bundle-analyzer': workspace:* @@ -170,6 +171,7 @@ importers: '@babel/preset-flow': 7.14.5_@babel+core@7.18.0 '@babel/preset-react': 7.14.5_@babel+core@7.18.0 '@edge-runtime/jest-environment': 1.1.0-beta.6 + '@edge-runtime/primitives': 1.1.0-beta.6 '@fullhuman/postcss-purgecss': 1.3.0 '@mdx-js/loader': 0.18.0_uuaxwgga6hqycsez5ok7v2wg4i '@next/bundle-analyzer': link:packages/next-bundle-analyzer @@ -20644,7 +20646,7 @@ packages: worker-farm: 1.7.0 dev: true - /terser-webpack-plugin/5.2.4: + /terser-webpack-plugin/5.2.4_webpack@5.73.0: resolution: {integrity: sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -20666,6 +20668,7 @@ packages: serialize-javascript: 6.0.0 source-map: 0.6.1 terser: 5.10.0 + webpack: 5.73.0 dev: true /terser/4.8.0: @@ -22085,7 +22088,7 @@ packages: neo-async: 2.6.2 schema-utils: 3.1.1 tapable: 2.2.0 - terser-webpack-plugin: 5.2.4 + terser-webpack-plugin: 5.2.4_webpack@5.73.0 watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: diff --git a/test/e2e/edge-can-read-request-body/app/.gitignore b/test/e2e/edge-can-read-request-body/app/.gitignore new file mode 100644 index 000000000000000..e985853ed84acf1 --- /dev/null +++ b/test/e2e/edge-can-read-request-body/app/.gitignore @@ -0,0 +1 @@ +.vercel diff --git a/test/e2e/edge-can-read-request-body/app/middleware.js b/test/e2e/edge-can-read-request-body/app/middleware.js new file mode 100644 index 000000000000000..bbddddb07ef8aa1 --- /dev/null +++ b/test/e2e/edge-can-read-request-body/app/middleware.js @@ -0,0 +1,49 @@ +// @ts-check + +import { NextResponse } from 'next/server' + +/** + * @param {NextRequest} req + */ +export default async function middleware(req) { + const res = NextResponse.next() + res.headers.set('x-incoming-content-type', req.headers.get('content-type')) + + const handler = + bodyHandlers[req.nextUrl.searchParams.get('middleware-handler')] + const headers = await handler?.(req) + for (const [key, value] of headers ?? []) { + res.headers.set(key, value) + } + + return res +} + +/** + * @typedef {import('next/server').NextRequest} NextRequest + * @typedef {(req: NextRequest) => Promise<[string, string][]>} Handler + * @type {Record} + */ +const bodyHandlers = { + json: async (req) => { + const json = await req.json() + return [ + ['x-req-type', 'json'], + ['x-serialized', JSON.stringify(json)], + ] + }, + text: async (req) => { + const text = await req.text() + return [ + ['x-req-type', 'text'], + ['x-serialized', text], + ] + }, + formData: async (req) => { + const formData = await req.formData() + return [ + ['x-req-type', 'formData'], + ['x-serialized', JSON.stringify(Object.fromEntries(formData))], + ] + }, +} diff --git a/test/e2e/edge-can-read-request-body/app/package.json b/test/e2e/edge-can-read-request-body/app/package.json new file mode 100644 index 000000000000000..8354a6a3f2345ac --- /dev/null +++ b/test/e2e/edge-can-read-request-body/app/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "next": "canary", + "react": "latest", + "react-dom": "latest" + } +} diff --git a/test/e2e/edge-can-read-request-body/app/pages/api/nothing.js b/test/e2e/edge-can-read-request-body/app/pages/api/nothing.js new file mode 100644 index 000000000000000..7c595baecad2be2 --- /dev/null +++ b/test/e2e/edge-can-read-request-body/app/pages/api/nothing.js @@ -0,0 +1,3 @@ +export default (_req, res) => { + res.send('ok') +} diff --git a/test/e2e/edge-can-read-request-body/index.test.ts b/test/e2e/edge-can-read-request-body/index.test.ts new file mode 100644 index 000000000000000..a56ce081ce849f0 --- /dev/null +++ b/test/e2e/edge-can-read-request-body/index.test.ts @@ -0,0 +1,115 @@ +import { createNext, FileRef } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import { renderViaHTTP } from 'next-test-utils' +import path from 'path' +import Primitives from '@edge-runtime/primitives' + +const { FormData, fetch } = Primitives + +describe('Edge can read request body', () => { + let next: NextInstance + + beforeAll(async () => { + next = await createNext({ + files: new FileRef(path.resolve(__dirname, './app')), + dependencies: {}, + }) + }) + afterAll(() => next.destroy()) + + it('renders the static page', async () => { + const html = await renderViaHTTP(next.url, '/api/nothing') + expect(html).toContain('ok') + }) + + describe('middleware', () => { + it('reads a JSON body', async () => { + const response = await fetch( + `${next.url}/api/nothing?middleware-handler=json`, + { + method: 'POST', + body: JSON.stringify({ hello: 'world' }), + } + ) + expect(await serialize(response)).toMatchObject({ + text: expect.stringContaining('ok'), + status: 200, + headers: { + 'x-req-type': 'json', + 'x-serialized': '{"hello":"world"}', + }, + }) + }) + + it('reads a text body', async () => { + const response = await fetch( + `${next.url}/api/nothing?middleware-handler=text`, + { + method: 'POST', + body: JSON.stringify({ hello: 'world' }), + } + ) + expect(await serialize(response)).toMatchObject({ + text: expect.stringContaining('ok'), + status: 200, + headers: { + 'x-req-type': 'text', + 'x-serialized': '{"hello":"world"}', + }, + }) + }) + + it('reads an URL encoded form data', async () => { + const response = await fetch( + `${next.url}/api/nothing?middleware-handler=formData`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ hello: 'world' }).toString(), + } + ) + expect(await serialize(response)).toMatchObject({ + text: expect.stringContaining('ok'), + status: 200, + headers: { + 'x-req-type': 'formData', + 'x-serialized': '{"hello":"world"}', + }, + }) + }) + + /** + * This test is skipped because `undici` does not implement + * form-data body parsing right now. + */ + it.skip('reads a multipart form data', async () => { + const formData = new FormData() + formData.set('hello', 'world') + const response = await fetch( + `${next.url}/api/nothing?middleware-handler=formData`, + { + method: 'POST', + body: formData, + } + ) + expect(await serialize(response)).toMatchObject({ + text: expect.stringContaining('ok'), + status: 200, + headers: { + 'x-req-type': 'formData', + 'x-serialized': '{"hello":"world"}', + }, + }) + }) + }) +}) + +async function serialize(response: Response) { + return { + text: await response.text(), + headers: Object.fromEntries(response.headers), + status: response.status, + } +} From 2b8408b1c90cff8f72cd814af6f27aea74ec2599 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Mon, 17 Oct 2022 16:57:59 +0200 Subject: [PATCH 2/2] fix: linter --- .../e2e/edge-can-read-request-body/index.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/e2e/edge-can-read-request-body/index.test.ts b/test/e2e/edge-can-read-request-body/index.test.ts index a56ce081ce849f0..6358de1d0e6c756 100644 --- a/test/e2e/edge-can-read-request-body/index.test.ts +++ b/test/e2e/edge-can-read-request-body/index.test.ts @@ -6,6 +6,14 @@ import Primitives from '@edge-runtime/primitives' const { FormData, fetch } = Primitives +async function serialize(response: Response) { + return { + text: await response.text(), + headers: Object.fromEntries(response.headers), + status: response.status, + } +} + describe('Edge can read request body', () => { let next: NextInstance @@ -105,11 +113,3 @@ describe('Edge can read request body', () => { }) }) }) - -async function serialize(response: Response) { - return { - text: await response.text(), - headers: Object.fromEntries(response.headers), - status: response.status, - } -}