diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15/app/redirect/destination/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-15/app/redirect/destination/page.tsx new file mode 100644 index 000000000000..5583d36b04b0 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nextjs-15/app/redirect/destination/page.tsx @@ -0,0 +1,7 @@ +export default function RedirectDestinationPage() { + return ( +
+

Redirect Destination

+
+ ); +} diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15/app/redirect/origin/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-15/app/redirect/origin/page.tsx new file mode 100644 index 000000000000..52615e0a054b --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nextjs-15/app/redirect/origin/page.tsx @@ -0,0 +1,18 @@ +import { redirect } from 'next/navigation'; + +async function redirectAction() { + 'use server'; + + redirect('/redirect/destination'); +} + +export default function RedirectOriginPage() { + return ( + <> + {/* @ts-ignore */} +
+ +
+ + ); +} diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15/tests/server-action-redirect.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-15/tests/server-action-redirect.test.ts new file mode 100644 index 000000000000..d46936fa6b2f --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nextjs-15/tests/server-action-redirect.test.ts @@ -0,0 +1,47 @@ +import { expect, test } from '@playwright/test'; +import { waitForError, waitForTransaction } from '@sentry-internal/test-utils'; + +test('Should handle server action redirect without capturing errors', async ({ page }) => { + // Wait for the initial page load transaction + const pageLoadTransactionPromise = waitForTransaction('nextjs-15', async transactionEvent => { + return transactionEvent?.transaction === '/redirect/origin'; + }); + + // Navigate to the origin page + await page.goto('/redirect/origin'); + + const pageLoadTransaction = await pageLoadTransactionPromise; + expect(pageLoadTransaction).toBeDefined(); + + // Wait for the redirect transaction + const redirectTransactionPromise = waitForTransaction('nextjs-15', async transactionEvent => { + return transactionEvent?.transaction === 'GET /redirect/destination'; + }); + + // No error should be captured + const redirectErrorPromise = waitForError('nextjs-15', async errorEvent => { + return !!errorEvent; + }); + + // Click the redirect button + await page.click('button[type="submit"]'); + + await redirectTransactionPromise; + + // Verify we got redirected to the destination page + await expect(page).toHaveURL('/redirect/destination'); + + // Wait for potential errors with a 2 second timeout + const errorTimeout = new Promise((_, reject) => + setTimeout(() => reject(new Error('No error captured (timeout)')), 2000), + ); + + // We expect this to timeout since no error should be captured during the redirect + try { + await Promise.race([redirectErrorPromise, errorTimeout]); + throw new Error('Expected no error to be captured, but an error was found'); + } catch (e) { + // If we get a timeout error (as expected), no error was captured + expect((e as Error).message).toBe('No error captured (timeout)'); + } +});