From 49772ab70171a036eaa3e4a1e1fc5c655ef3e023 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 30 Sep 2024 08:59:26 +0000 Subject: [PATCH 1/7] test(nextjs): Make tests work with new async APIs --- .../client-component/parameter/[...parameters]/page.tsx | 8 ++++++-- .../app/client-component/parameter/[parameter]/page.tsx | 8 ++++++-- .../server-component/parameter/[...parameters]/page.tsx | 8 ++++++-- .../app/server-component/parameter/[parameter]/page.tsx | 8 ++++++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx index 31fa4ee21be5..a06adb6a5cd1 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx @@ -1,10 +1,14 @@ +import { use } from 'react'; import { ClientErrorDebugTools } from '../../../../components/client-error-debug-tools'; -export default function Page({ params }: { params: Record }) { +export default function Page({ params }: { params: { parameters: string[] } | Promise<{ parameters: string[] }> }) { + // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests + const normalizedParams = 'then' in params ? use(params) : params; + return (

Page (/client-component/[...parameters])

-

Params: {JSON.stringify(params['parameters'])}

+

Params: {JSON.stringify(normalizedParams['parameters'])}

); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[parameter]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[parameter]/page.tsx index 2b9c28b922ac..c19157f0567e 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[parameter]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[parameter]/page.tsx @@ -1,10 +1,14 @@ +import { use } from 'react'; import { ClientErrorDebugTools } from '../../../../components/client-error-debug-tools'; -export default function Page({ params }: { params: Record }) { +export default function Page({ params }: { params: { parameter: string } | Promise<{ parameter: string }> }) { + // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests + const normalizedParams = 'then' in params ? use(params) : params; + return (

Page (/client-component/[parameter])

-

Parameter: {JSON.stringify(params['parameter'])}

+

Parameter: {JSON.stringify(normalizedParams['parameter'])}

); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[...parameters]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[...parameters]/page.tsx index 5d9d6c8262c5..136176d944d7 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[...parameters]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[...parameters]/page.tsx @@ -1,12 +1,16 @@ +import { use } from 'react'; import { ClientErrorDebugTools } from '../../../../components/client-error-debug-tools'; export const dynamic = 'force-dynamic'; -export default async function Page({ params }: { params: Record }) { +export default function Page({ params }: { params: { parameters: string[] } | Promise<{ parameters: string[] }> }) { + // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests + const normalizedParams = 'then' in params ? use(params) : params; + return (

Page (/server-component/[...parameters])

-

Params: {JSON.stringify(params['parameters'])}

+

Params: {JSON.stringify(normalizedParams['parameters'])}

); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[parameter]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[parameter]/page.tsx index f88fe1cd4a06..bccbf1930426 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[parameter]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[parameter]/page.tsx @@ -1,12 +1,16 @@ +import { use } from 'react'; import { ClientErrorDebugTools } from '../../../../components/client-error-debug-tools'; export const dynamic = 'force-dynamic'; -export default async function Page({ params }: { params: Record }) { +export default function Page({ params }: { params: { parameter: string } | Promise<{ parameter: string }> }) { + // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests + const normalizedParams = 'then' in params ? use(params) : params; + return (

Page (/server-component/[parameter])

-

Parameter: {JSON.stringify(params['parameter'])}

+

Parameter: {JSON.stringify(normalizedParams['parameter'])}

); From f86431e032b40aa8e9aaa4f333d82609928612c5 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 30 Sep 2024 09:03:25 +0000 Subject: [PATCH 2/7] next-14 --- .../app/generation-functions/page.tsx | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx index 92bee1dbac4b..cebb7e2a6df6 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx @@ -10,30 +10,40 @@ export default function Page() { export async function generateMetadata({ searchParams, }: { - searchParams: { [key: string]: string | string[] | undefined }; + searchParams: + | { shouldThrowInGenerateMetadata?: string; metadataTitle?: string } + | Promise<{ shouldThrowInGenerateMetadata?: string; metadataTitle?: string }>; }) { + // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests + const normalizedSearchParams = await searchParams; + Sentry.setTag('my-isolated-tag', true); Sentry.setTag('my-global-scope-isolated-tag', getDefaultIsolationScope().getScopeData().tags['my-isolated-tag']); // We set this tag to be able to assert that the previously set tag has not leaked into the global isolation scope - if (searchParams['shouldThrowInGenerateMetadata']) { + if (normalizedSearchParams['shouldThrowInGenerateMetadata']) { throw new Error('generateMetadata Error'); } return { - title: searchParams['metadataTitle'] ?? 'not set', + title: normalizedSearchParams['metadataTitle'] ?? 'not set', }; } -export function generateViewport({ +export async function generateViewport({ searchParams, }: { - searchParams: { [key: string]: string | undefined }; + searchParams: + | { viewportThemeColor?: string; shouldThrowInGenerateViewport?: string } + | Promise<{ viewportThemeColor?: string; shouldThrowInGenerateViewport?: string }>; }) { - if (searchParams['shouldThrowInGenerateViewport']) { + // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests + const normalizedSearchParams = await searchParams; + + if (normalizedSearchParams['shouldThrowInGenerateViewport']) { throw new Error('generateViewport Error'); } return { - themeColor: searchParams['viewportThemeColor'] ?? 'black', + themeColor: normalizedSearchParams['viewportThemeColor'] ?? 'black', }; } From 4f48a6961ca64cf444ab91a7e50923ec53d9e2bb Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 30 Sep 2024 09:04:40 +0000 Subject: [PATCH 3/7] next-15 --- .../nextjs-15/app/ppr-error/[param]/page.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15/app/ppr-error/[param]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-15/app/ppr-error/[param]/page.tsx index ec2b2b1232c7..676a3fa3052d 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15/app/ppr-error/[param]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-15/app/ppr-error/[param]/page.tsx @@ -3,10 +3,13 @@ import * as Sentry from '@sentry/nextjs'; export default async function Page({ searchParams, }: { - searchParams: { id?: string }; + searchParams: { id?: string } | Promise<{ id?: string }>; }) { + // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests + const normalizedSearchParams = await searchParams; + try { - console.log(searchParams.id); // Accessing a field on searchParams will throw the PPR error + console.log(normalizedSearchParams.id); // Accessing a field on searchParams will throw the PPR error } catch (e) { Sentry.captureException(e); // This error should not be reported await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for any async event processors to run From f91e586100d384f68736ad2667e9b8ba53a23057 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 30 Sep 2024 09:22:28 +0000 Subject: [PATCH 4/7] any --- .../nextjs-14/app/generation-functions/page.tsx | 4 +--- .../nextjs-15/app/ppr-error/[param]/page.tsx | 2 +- .../app/client-component/parameter/[...parameters]/page.tsx | 2 +- .../app/client-component/parameter/[parameter]/page.tsx | 2 +- .../app/server-component/parameter/[...parameters]/page.tsx | 2 +- .../app/server-component/parameter/[parameter]/page.tsx | 2 +- 6 files changed, 6 insertions(+), 8 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx index cebb7e2a6df6..99cf2d9a4256 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx @@ -10,9 +10,7 @@ export default function Page() { export async function generateMetadata({ searchParams, }: { - searchParams: - | { shouldThrowInGenerateMetadata?: string; metadataTitle?: string } - | Promise<{ shouldThrowInGenerateMetadata?: string; metadataTitle?: string }>; + searchParams: any; }) { // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests const normalizedSearchParams = await searchParams; diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15/app/ppr-error/[param]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-15/app/ppr-error/[param]/page.tsx index 676a3fa3052d..c67513e0e4fd 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15/app/ppr-error/[param]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-15/app/ppr-error/[param]/page.tsx @@ -3,7 +3,7 @@ import * as Sentry from '@sentry/nextjs'; export default async function Page({ searchParams, }: { - searchParams: { id?: string } | Promise<{ id?: string }>; + searchParams: any; }) { // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests const normalizedSearchParams = await searchParams; diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx index a06adb6a5cd1..050f1df38d2d 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx @@ -1,7 +1,7 @@ import { use } from 'react'; import { ClientErrorDebugTools } from '../../../../components/client-error-debug-tools'; -export default function Page({ params }: { params: { parameters: string[] } | Promise<{ parameters: string[] }> }) { +export default function Page({ params }: any }) { // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests const normalizedParams = 'then' in params ? use(params) : params; diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[parameter]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[parameter]/page.tsx index c19157f0567e..514a0833c998 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[parameter]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[parameter]/page.tsx @@ -1,7 +1,7 @@ import { use } from 'react'; import { ClientErrorDebugTools } from '../../../../components/client-error-debug-tools'; -export default function Page({ params }: { params: { parameter: string } | Promise<{ parameter: string }> }) { +export default function Page({ params }: any) { // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests const normalizedParams = 'then' in params ? use(params) : params; diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[...parameters]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[...parameters]/page.tsx index 136176d944d7..63d0e7b53f0b 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[...parameters]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[...parameters]/page.tsx @@ -3,7 +3,7 @@ import { ClientErrorDebugTools } from '../../../../components/client-error-debug export const dynamic = 'force-dynamic'; -export default function Page({ params }: { params: { parameters: string[] } | Promise<{ parameters: string[] }> }) { +export default function Page({ params }: any) { // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests const normalizedParams = 'then' in params ? use(params) : params; diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[parameter]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[parameter]/page.tsx index bccbf1930426..98ecb7352ad2 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[parameter]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/server-component/parameter/[parameter]/page.tsx @@ -3,7 +3,7 @@ import { ClientErrorDebugTools } from '../../../../components/client-error-debug export const dynamic = 'force-dynamic'; -export default function Page({ params }: { params: { parameter: string } | Promise<{ parameter: string }> }) { +export default function Page({ params }: any) { // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests const normalizedParams = 'then' in params ? use(params) : params; From ef86a42c003c210350732c6c2961872796098840 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 30 Sep 2024 09:41:12 +0000 Subject: [PATCH 5/7] typos and missed --- .../nextjs-14/app/generation-functions/page.tsx | 14 ++------------ .../parameter/[...parameters]/page.tsx | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx index 99cf2d9a4256..0d8f1841ea9d 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-14/app/generation-functions/page.tsx @@ -7,11 +7,7 @@ export default function Page() { return

Hello World!

; } -export async function generateMetadata({ - searchParams, -}: { - searchParams: any; -}) { +export async function generateMetadata({ searchParams }: { searchParams: any }) { // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests const normalizedSearchParams = await searchParams; @@ -27,13 +23,7 @@ export async function generateMetadata({ }; } -export async function generateViewport({ - searchParams, -}: { - searchParams: - | { viewportThemeColor?: string; shouldThrowInGenerateViewport?: string } - | Promise<{ viewportThemeColor?: string; shouldThrowInGenerateViewport?: string }>; -}) { +export async function generateViewport({ searchParams }: { searchParams: any }) { // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests const normalizedSearchParams = await searchParams; diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx index 050f1df38d2d..f09f06875c3a 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/app/client-component/parameter/[...parameters]/page.tsx @@ -1,7 +1,7 @@ import { use } from 'react'; import { ClientErrorDebugTools } from '../../../../components/client-error-debug-tools'; -export default function Page({ params }: any }) { +export default function Page({ params }: any) { // We need to dynamically check for this because Next.js made the API async for Next.js 15 and we use this test in canary tests const normalizedParams = 'then' in params ? use(params) : params; From 376482fa99daf5278bcd5bbe7060930cd7b5ce04 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 30 Sep 2024 10:09:12 +0000 Subject: [PATCH 6/7] Adjust withServerActionInstrumentation --- .../common/withServerActionInstrumentation.ts | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/nextjs/src/common/withServerActionInstrumentation.ts b/packages/nextjs/src/common/withServerActionInstrumentation.ts index 14c701638ee5..c1633d8fab1b 100644 --- a/packages/nextjs/src/common/withServerActionInstrumentation.ts +++ b/packages/nextjs/src/common/withServerActionInstrumentation.ts @@ -15,7 +15,18 @@ import { vercelWaitUntil } from './utils/vercelWaitUntil'; interface Options { formData?: FormData; - headers?: Headers; + + /** + * Headers as returned from `headers()`. + * + * Currently accepts both a plain `Headers` object and `Promise` to be compatible with async APIs introduced in Next.js 15: https://github.com/vercel/next.js/pull/68812 + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + headers?: Headers | Promise; + + /** + * Whether the server action response should be included in any events captured within the server action. + */ recordResponse?: boolean; } @@ -55,16 +66,17 @@ async function withServerActionInstrumentationImplementation> { return escapeNextjsTracing(() => { - return withIsolationScope(isolationScope => { + return withIsolationScope(async isolationScope => { const sendDefaultPii = getClient()?.getOptions().sendDefaultPii; let sentryTraceHeader; let baggageHeader; const fullHeadersObject: Record = {}; try { - sentryTraceHeader = options.headers?.get('sentry-trace') ?? undefined; - baggageHeader = options.headers?.get('baggage'); - options.headers?.forEach((value, key) => { + const awaitedHeaders: Headers = await options.headers; + sentryTraceHeader = awaitedHeaders?.get('sentry-trace') ?? undefined; + baggageHeader = awaitedHeaders?.get('baggage'); + awaitedHeaders?.forEach((value, key) => { fullHeadersObject[key] = value; }); } catch (e) { From 850ecef97ac24448a0adcabb98d3ab103f210d37 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 30 Sep 2024 10:17:05 +0000 Subject: [PATCH 7/7] more fixing --- .../test-applications/nextjs-14/app/propagation/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-14/app/propagation/utils.ts b/dev-packages/e2e-tests/test-applications/nextjs-14/app/propagation/utils.ts index a065c53ee4c9..249efabe58f3 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-14/app/propagation/utils.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-14/app/propagation/utils.ts @@ -26,8 +26,8 @@ export function makeHttpRequest(url: string) { }); } -export function checkHandler() { - const headerList = headers(); +export async function checkHandler() { + const headerList = await headers(); const headerObj: Record = {}; headerList.forEach((value, key) => {