From ee893298dcaab631d700fb9ed0ccdf42ca57ae4b Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 19 Jun 2023 09:26:36 +0000 Subject: [PATCH 1/5] test(e2e): Add test for Next.js middleware --- .../nextjs-app-dir/middleware.ts | 11 +++++++++++ .../pages/api/endpoint-behind-middleware.ts | 9 +++++++++ .../nextjs-app-dir/tests/transactions.test.ts | 15 +++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 packages/e2e-tests/test-applications/nextjs-app-dir/middleware.ts create mode 100644 packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/endpoint-behind-middleware.ts diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/middleware.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/middleware.ts new file mode 100644 index 000000000000..a53f8a0cdca2 --- /dev/null +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/middleware.ts @@ -0,0 +1,11 @@ +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; + +export function middleware() { + return NextResponse.next(); +} + +// See "Matching Paths" below to learn more +export const config = { + matcher: ['/api/endpoint-behind-middleware'], +}; diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/endpoint-behind-middleware.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/endpoint-behind-middleware.ts new file mode 100644 index 000000000000..2ca75a33ba7e --- /dev/null +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/endpoint-behind-middleware.ts @@ -0,0 +1,9 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; + +type Data = { + name: string; +}; + +export default function handler(req: NextApiRequest, res: NextApiResponse) { + res.status(200).json({ name: 'John Doe' }); +} diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/transactions.test.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/transactions.test.ts index 8dac4e58e5ba..1c359928529b 100644 --- a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/transactions.test.ts +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/transactions.test.ts @@ -112,3 +112,18 @@ if (process.env.TEST_ENV === 'production') { expect((await serverComponentTransactionPromise).contexts?.trace?.status).toBe('not_found'); }); } + +test('Should create a transaction for middleware', async ({ request }) => { + const middlewareTransactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => { + return transactionEvent?.transaction === 'middleware'; + }); + + const response = await request.get('/api/endpoint-behind-middleware'); + expect(await response.json()).toStrictEqual({ name: 'John Doe' }); + + const middlewareTransaction = await middlewareTransactionPromise; + + expect(middlewareTransaction.contexts?.trace?.status).toBe('ok'); + expect(middlewareTransaction.contexts?.trace?.op).toBe('middleware.nextjs'); + expect(middlewareTransaction.contexts?.runtime?.name).toBe('edge'); +}); From cd705b758cbf3964764f8dd14ccb5f0fffc1c155 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 19 Jun 2023 09:37:21 +0000 Subject: [PATCH 2/5] . --- .../nextjs-app-dir/middleware.ts | 6 ++++- .../nextjs-app-dir/tests/middleware.test.ts | 27 +++++++++++++++++++ .../nextjs-app-dir/tests/transactions.test.ts | 15 ----------- 3 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/middleware.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/middleware.ts index a53f8a0cdca2..bb9db27b50d7 100644 --- a/packages/e2e-tests/test-applications/nextjs-app-dir/middleware.ts +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/middleware.ts @@ -1,7 +1,11 @@ import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; -export function middleware() { +export function middleware(request: NextRequest) { + if (request.headers.has('x-should-throw')) { + throw new Error('Middleware Error'); + } + return NextResponse.next(); } diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts new file mode 100644 index 000000000000..019b25af9893 --- /dev/null +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts @@ -0,0 +1,27 @@ +import { test, expect } from '@playwright/test'; +import { waitForTransaction, waitForError } from '../../../test-utils/event-proxy-server'; + +test('Should create a transaction for middleware', async ({ request }) => { + const middlewareTransactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => { + return transactionEvent?.transaction === 'middleware'; + }); + + const response = await request.get('/api/endpoint-behind-middleware'); + expect(await response.json()).toStrictEqual({ name: 'John Doe' }); + + const middlewareTransaction = await middlewareTransactionPromise; + + expect(middlewareTransaction.contexts?.trace?.status).toBe('ok'); + expect(middlewareTransaction.contexts?.trace?.op).toBe('middleware.nextjs'); + expect(middlewareTransaction.contexts?.runtime?.name).toBe('edge'); +}); + +test('Records exceptions happening in middleware', async ({ request }) => { + const errorEventPromise = waitForError('nextjs-13-app-dir', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Middleware Error'; + }); + + await request.get('/api/endpoint-behind-middleware', { headers: { 'x-should-throw': '1' } }); + + expect(await errorEventPromise).toBeDefined(); +}); diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/transactions.test.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/transactions.test.ts index 1c359928529b..8dac4e58e5ba 100644 --- a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/transactions.test.ts +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/transactions.test.ts @@ -112,18 +112,3 @@ if (process.env.TEST_ENV === 'production') { expect((await serverComponentTransactionPromise).contexts?.trace?.status).toBe('not_found'); }); } - -test('Should create a transaction for middleware', async ({ request }) => { - const middlewareTransactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => { - return transactionEvent?.transaction === 'middleware'; - }); - - const response = await request.get('/api/endpoint-behind-middleware'); - expect(await response.json()).toStrictEqual({ name: 'John Doe' }); - - const middlewareTransaction = await middlewareTransactionPromise; - - expect(middlewareTransaction.contexts?.trace?.status).toBe('ok'); - expect(middlewareTransaction.contexts?.trace?.op).toBe('middleware.nextjs'); - expect(middlewareTransaction.contexts?.runtime?.name).toBe('edge'); -}); From a5ef5b8d7bfa44c787a5d17df1bdf45aaaa46907 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 19 Jun 2023 09:45:33 +0000 Subject: [PATCH 3/5] . --- .../nextjs-app-dir/tests/middleware.test.ts | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts index 019b25af9893..2cf7d066625b 100644 --- a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts @@ -3,7 +3,7 @@ import { waitForTransaction, waitForError } from '../../../test-utils/event-prox test('Should create a transaction for middleware', async ({ request }) => { const middlewareTransactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => { - return transactionEvent?.transaction === 'middleware'; + return transactionEvent?.transaction === 'middleware' && transactionEvent?.contexts?.trace?.status === 'ok'; }); const response = await request.get('/api/endpoint-behind-middleware'); @@ -16,12 +16,28 @@ test('Should create a transaction for middleware', async ({ request }) => { expect(middlewareTransaction.contexts?.runtime?.name).toBe('edge'); }); +test('Should create a transaction with error status for faulty middleware', async ({ request }) => { + const middlewareTransactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => { + return ( + transactionEvent?.transaction === 'middleware' && transactionEvent?.contexts?.trace?.status === 'internal_error' + ); + }); + + request.get('/api/endpoint-behind-middleware', { headers: { 'x-should-throw': '1' } }); + + const middlewareTransaction = await middlewareTransactionPromise; + + expect(middlewareTransaction.contexts?.trace?.status).toBe('internal_error'); + expect(middlewareTransaction.contexts?.trace?.op).toBe('middleware.nextjs'); + expect(middlewareTransaction.contexts?.runtime?.name).toBe('edge'); +}); + test('Records exceptions happening in middleware', async ({ request }) => { const errorEventPromise = waitForError('nextjs-13-app-dir', errorEvent => { return errorEvent?.exception?.values?.[0]?.value === 'Middleware Error'; }); - await request.get('/api/endpoint-behind-middleware', { headers: { 'x-should-throw': '1' } }); + request.get('/api/endpoint-behind-middleware', { headers: { 'x-should-throw': '1' } }); expect(await errorEventPromise).toBeDefined(); }); From 3f7dc52b86d0c98c45ab171a19342c1bebbabefa Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 19 Jun 2023 10:37:07 +0000 Subject: [PATCH 4/5] . --- .../nextjs-app-dir/tests/middleware.test.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts index 2cf7d066625b..268a55f1f481 100644 --- a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts @@ -2,6 +2,8 @@ import { test, expect } from '@playwright/test'; import { waitForTransaction, waitForError } from '../../../test-utils/event-proxy-server'; test('Should create a transaction for middleware', async ({ request }) => { + test.skip(process.env.TEST_ENV === 'development', "Doesn't work in dev mode."); + const middlewareTransactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => { return transactionEvent?.transaction === 'middleware' && transactionEvent?.contexts?.trace?.status === 'ok'; }); @@ -17,13 +19,17 @@ test('Should create a transaction for middleware', async ({ request }) => { }); test('Should create a transaction with error status for faulty middleware', async ({ request }) => { + test.skip(process.env.TEST_ENV === 'development', "Doesn't work in dev mode."); + const middlewareTransactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => { return ( transactionEvent?.transaction === 'middleware' && transactionEvent?.contexts?.trace?.status === 'internal_error' ); }); - request.get('/api/endpoint-behind-middleware', { headers: { 'x-should-throw': '1' } }); + request.get('/api/endpoint-behind-middleware', { headers: { 'x-should-throw': '1' } }).catch(() => { + // Noop + }); const middlewareTransaction = await middlewareTransactionPromise; @@ -33,11 +39,15 @@ test('Should create a transaction with error status for faulty middleware', asyn }); test('Records exceptions happening in middleware', async ({ request }) => { + test.skip(process.env.TEST_ENV === 'development', "Doesn't work in dev mode."); + const errorEventPromise = waitForError('nextjs-13-app-dir', errorEvent => { return errorEvent?.exception?.values?.[0]?.value === 'Middleware Error'; }); - request.get('/api/endpoint-behind-middleware', { headers: { 'x-should-throw': '1' } }); + request.get('/api/endpoint-behind-middleware', { headers: { 'x-should-throw': '1' } }).catch(() => { + // Noop + }); expect(await errorEventPromise).toBeDefined(); }); From 1e1ef4beca836866c46ec46ab61e1e0cc4f6c715 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 19 Jun 2023 15:48:49 +0200 Subject: [PATCH 5/5] test(e2e): Add tests for Next.js edge routes (#8355) --- .../nextjs-app-dir/pages/api/edge-endpoint.ts | 18 +++++- .../pages/api/error-edge-endpoint.ts | 5 ++ .../nextjs-app-dir/tests/edge-route.test.ts | 56 +++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/error-edge-endpoint.ts create mode 100644 packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge-route.test.ts diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/edge-endpoint.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/edge-endpoint.ts index d8af89f2e9d5..b2b2dfdf4fc3 100644 --- a/packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/edge-endpoint.ts +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/edge-endpoint.ts @@ -1,3 +1,17 @@ -export const config = { runtime: 'edge' }; +export const config = { + runtime: 'edge', +}; -export default () => new Response('Hello world!'); +export default async function handler() { + return new Response( + JSON.stringify({ + name: 'Jim Halpert', + }), + { + status: 200, + headers: { + 'content-type': 'application/json', + }, + }, + ); +} diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/error-edge-endpoint.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/error-edge-endpoint.ts new file mode 100644 index 000000000000..043112494c23 --- /dev/null +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/pages/api/error-edge-endpoint.ts @@ -0,0 +1,5 @@ +export const config = { runtime: 'edge' }; + +export default () => { + throw new Error('Edge Route Error'); +}; diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge-route.test.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge-route.test.ts new file mode 100644 index 000000000000..8f73764a919f --- /dev/null +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/edge-route.test.ts @@ -0,0 +1,56 @@ +import { test, expect } from '@playwright/test'; +import { waitForTransaction, waitForError } from '../../../test-utils/event-proxy-server'; + +test('Should create a transaction for edge routes', async ({ request }) => { + test.skip(process.env.TEST_ENV === 'development', "Doesn't work in dev mode."); + + const edgerouteTransactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => { + return ( + transactionEvent?.transaction === 'GET /api/edge-endpoint' && transactionEvent?.contexts?.trace?.status === 'ok' + ); + }); + + const response = await request.get('/api/edge-endpoint'); + expect(await response.json()).toStrictEqual({ name: 'Jim Halpert' }); + + const edgerouteTransaction = await edgerouteTransactionPromise; + + expect(edgerouteTransaction.contexts?.trace?.status).toBe('ok'); + expect(edgerouteTransaction.contexts?.trace?.op).toBe('http.server'); + expect(edgerouteTransaction.contexts?.runtime?.name).toBe('edge'); +}); + +test('Should create a transaction with error status for faulty edge routes', async ({ request }) => { + test.skip(process.env.TEST_ENV === 'development', "Doesn't work in dev mode."); + + const edgerouteTransactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => { + return ( + transactionEvent?.transaction === 'GET /api/error-edge-endpoint' && + transactionEvent?.contexts?.trace?.status === 'internal_error' + ); + }); + + request.get('/api/error-edge-endpoint').catch(() => { + // Noop + }); + + const edgerouteTransaction = await edgerouteTransactionPromise; + + expect(edgerouteTransaction.contexts?.trace?.status).toBe('internal_error'); + expect(edgerouteTransaction.contexts?.trace?.op).toBe('http.server'); + expect(edgerouteTransaction.contexts?.runtime?.name).toBe('edge'); +}); + +test('Should record exceptions for faulty edge routes', async ({ request }) => { + test.skip(process.env.TEST_ENV === 'development', "Doesn't work in dev mode."); + + const errorEventPromise = waitForError('nextjs-13-app-dir', errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Edge Route Error'; + }); + + request.get('/api/error-edge-endpoint').catch(() => { + // Noop + }); + + expect(await errorEventPromise).toBeDefined(); +});