diff --git a/packages/e2e-tests/run.ts b/packages/e2e-tests/run.ts index 2709feb3a040..842911863f02 100644 --- a/packages/e2e-tests/run.ts +++ b/packages/e2e-tests/run.ts @@ -174,6 +174,7 @@ type RecipeResult = { type Recipe = { testApplicationName: string; buildCommand?: string; + buildAssertionCommand?: string; buildTimeoutSeconds?: number; tests: { testName: string; @@ -212,9 +213,9 @@ const recipeResults: RecipeResult[] = recipePaths.map(recipePath => { console.log(buildCommandProcess.stdout.replace(/^/gm, '[BUILD OUTPUT] ')); console.log(buildCommandProcess.stderr.replace(/^/gm, '[BUILD OUTPUT] ')); - const error: undefined | (Error & { code?: string }) = buildCommandProcess.error; + const buildCommandProcessError: undefined | (Error & { code?: string }) = buildCommandProcess.error; - if (error?.code === 'ETIMEDOUT') { + if (buildCommandProcessError?.code === 'ETIMEDOUT') { processShouldExitWithError = true; printCIErrorMessage( @@ -239,6 +240,58 @@ const recipeResults: RecipeResult[] = recipePaths.map(recipePath => { testResults: [], }; } + + if (recipe.buildAssertionCommand) { + console.log( + `Running E2E test build assertion for test application "${recipe.testApplicationName}"${dependencyOverridesInformationString}`, + ); + const buildAssertionCommandProcess = childProcess.spawnSync(recipe.buildAssertionCommand, { + cwd: path.dirname(recipePath), + input: buildCommandProcess.stdout, + encoding: 'utf8', + shell: true, // needed so we can pass the build command in as whole without splitting it up into args + timeout: (recipe.buildTimeoutSeconds ?? DEFAULT_BUILD_TIMEOUT_SECONDS) * 1000, + env: { + ...process.env, + ...envVarsToInject, + }, + }); + + // Prepends some text to the output build command's output so we can distinguish it from logging in this script + console.log(buildAssertionCommandProcess.stdout.replace(/^/gm, '[BUILD ASSERTION OUTPUT] ')); + console.log(buildAssertionCommandProcess.stderr.replace(/^/gm, '[BUILD ASSERTION OUTPUT] ')); + + const buildAssertionCommandProcessError: undefined | (Error & { code?: string }) = + buildAssertionCommandProcess.error; + + if (buildAssertionCommandProcessError?.code === 'ETIMEDOUT') { + processShouldExitWithError = true; + + printCIErrorMessage( + `Build assertion in test application "${recipe.testApplicationName}" (${path.dirname( + recipePath, + )}) timed out!`, + ); + + return { + dependencyOverrides, + buildFailed: true, + testResults: [], + }; + } else if (buildAssertionCommandProcess.status !== 0) { + processShouldExitWithError = true; + + printCIErrorMessage( + `Build assertion in test application "${recipe.testApplicationName}" (${path.dirname(recipePath)}) failed!`, + ); + + return { + dependencyOverrides, + buildFailed: true, + testResults: [], + }; + } + } } const testResults: TestResult[] = recipe.tests.map(test => { diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/assert-build.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/assert-build.ts new file mode 100644 index 000000000000..cb7adf38cde8 --- /dev/null +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/assert-build.ts @@ -0,0 +1,16 @@ +import * as fs from 'fs'; +import * as assert from 'assert/strict'; + +const stdin = fs.readFileSync(0).toString(); + +// Assert that all static components stay static and ally dynamic components stay dynamic + +assert.match(stdin, /○ \/client-component/); +assert.match(stdin, /● \/client-component\/parameter\/\[\.\.\.parameters\]/); +assert.match(stdin, /● \/client-component\/parameter\/\[parameter\]/); + +assert.match(stdin, /λ \/server-component/); +assert.match(stdin, /λ \/server-component\/parameter\/\[\.\.\.parameters\]/); +assert.match(stdin, /λ \/server-component\/parameter\/\[parameter\]/); + +export {}; diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/components/client-error-debug-tools.tsx b/packages/e2e-tests/test-applications/nextjs-app-dir/components/client-error-debug-tools.tsx index 4e7572a3fb3f..9eeaa227996f 100644 --- a/packages/e2e-tests/test-applications/nextjs-app-dir/components/client-error-debug-tools.tsx +++ b/packages/e2e-tests/test-applications/nextjs-app-dir/components/client-error-debug-tools.tsx @@ -5,7 +5,8 @@ import { TransactionContext } from './transaction-context'; import { captureException } from '@sentry/nextjs'; export function ClientErrorDebugTools() { - const { transactionActive, toggle } = useContext(TransactionContext); + const transactionContextValue = useContext(TransactionContext); + const [transactionName, setTransactionName] = useState(''); const [isFetchingAPIRoute, setIsFetchingAPIRoute] = useState(); const [isFetchingEdgeAPIRoute, setIsFetchingEdgeAPIRoute] = useState(); @@ -18,13 +19,34 @@ export function ClientErrorDebugTools() { return (
- + {transactionContextValue.transactionActive ? ( + + ) : ( + <> + { + setTransactionName(e.target.value); + }} + /> + + + )}