Skip to content

test(e2e): Add Next.js Turbopack E2E tests #14031

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,7 @@ jobs:
'nextjs-13',
'nextjs-14',
'nextjs-15',
'nextjs-turbo',
'nextjs-t3',
'react-17',
'react-19',
Expand Down Expand Up @@ -1126,6 +1127,12 @@ jobs:
- test-application: 'nextjs-15'
build-command: 'test:build-latest'
label: 'nextjs-15 (latest)'
- test-application: 'nextjs-turbo'
build-command: 'test:build-canary'
label: 'nextjs-turbo (canary)'
- test-application: 'nextjs-turbo'
build-command: 'test:build-latest'
label: 'nextjs-turbo (latest)'

steps:
- name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }})
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ jobs:
- test-application: 'nextjs-15'
build-command: 'test:build-latest'
label: 'nextjs-15 (latest)'
- test-application: 'nextjs-turbo'
build-command: 'test:build-canary'
label: 'nextjs-turbo (canary)'
- test-application: 'nextjs-turbo'
build-command: 'test:build-latest'
label: 'nextjs-turbo (latest)'
- test-application: 'react-create-hash-router'
build-command: 'test:build-canary'
label: 'react-create-hash-router (canary)'
Expand Down
46 changes: 46 additions & 0 deletions dev-packages/e2e-tests/test-applications/nextjs-turbo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

!*.d.ts

# Sentry
.sentryclirc

.vscode

test-results
event-dumps
2 changes: 2 additions & 0 deletions dev-packages/e2e-tests/test-applications/nextjs-turbo/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@sentry:registry=http://127.0.0.1:4873
@sentry-internal:registry=http://127.0.0.1:4873
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const dynamic = 'force-dynamic';

export default function Page() {
if (Math.random() > -1) {
throw new Error('page rsc render error');
}

return null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use client';

import * as Sentry from '@sentry/nextjs';
import NextError from 'next/error';
import { useEffect } from 'react';

export default function GlobalError({
error,
}: {
error: Error & { digest?: string };
}) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);

return (
<html>
<body>
{/* `NextError` is the default Next.js error page component. Its type
definition requires a `statusCode` prop. However, since the App Router
does not expose status codes for errors, we simply pass 0 to render a
generic error message. */}
<NextError statusCode={0} />
</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface Window {
recordedTransactions?: string[];
capturedExceptionId?: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as Sentry from '@sentry/nextjs';

export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./sentry.server.config');
}

if (process.env.NEXT_RUNTIME === 'edge') {
await import('./sentry.edge.config');
}
}

export const onRequestError = Sentry.captureRequestError;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { withSentryConfig } = require('@sentry/nextjs');

/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
turbo: {}, // Enables Turbopack for builds
},
};

module.exports = withSentryConfig(nextConfig, {
silent: true,
});
49 changes: 49 additions & 0 deletions dev-packages/e2e-tests/test-applications/nextjs-turbo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "create-next-app",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "next build > .tmp_build_stdout 2> .tmp_build_stderr || (cat .tmp_build_stdout && cat .tmp_build_stderr && exit 1)",
"clean": "npx rimraf node_modules pnpm-lock.yaml",
"test:prod": "TEST_ENV=production playwright test",
"test:dev": "TEST_ENV=development playwright test",
"test:build": "pnpm install && npx playwright install && pnpm build",
"test:build-canary": "pnpm install && pnpm add next@canary && pnpm add react@canary && pnpm add react-dom@canary && npx playwright install && pnpm build",
"test:build-latest": "pnpm install && pnpm add next@latest && pnpm add react@rc && pnpm add react-dom@rc && npx playwright install && pnpm build",
"test:assert": "pnpm test:prod && pnpm test:dev"
},
"dependencies": {
"@sentry/nextjs": "latest || *",
"@types/node": "18.11.17",
"@types/react": "18.0.26",
"@types/react-dom": "18.0.9",
"next": "15.0.0",
"react": "rc",
"react-dom": "rc",
"typescript": "4.9.5"
},
"devDependencies": {
"@playwright/test": "^1.44.1",
"@sentry-internal/test-utils": "link:../../../test-utils",
"@sentry-internal/feedback": "latest || *",
"@sentry-internal/replay-canvas": "latest || *",
"@sentry-internal/browser-utils": "latest || *",
"@sentry/browser": "latest || *",
"@sentry/core": "latest || *",
"@sentry/nextjs": "latest || *",
"@sentry/node": "latest || *",
"@sentry/opentelemetry": "latest || *",
"@sentry/react": "latest || *",
"@sentry-internal/replay": "latest || *",
"@sentry/types": "latest || *",
"@sentry/utils": "latest || *",
"@sentry/vercel-edge": "latest || *",
"import-in-the-middle": "1.11.2"
},
"overrides": {
"import-in-the-middle": "1.11.2"
},
"volta": {
"extends": "../../package.json"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { getPlaywrightConfig } from '@sentry-internal/test-utils';
const testEnv = process.env.TEST_ENV;

if (!testEnv) {
throw new Error('No test env defined');
}

const config = getPlaywrightConfig(
{
startCommand: testEnv === 'development' ? 'pnpm next dev -p 3030 --turbo' : 'pnpm next start -p 3030',
port: 3030,
},
{
// This comes with the risk of tests leaking into each other but the tests run quite slow so we should parallelize
workers: '100%',
},
);

export default config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as Sentry from '@sentry/nextjs';

Sentry.init({
environment: 'qa', // dynamic sampling bias to keep transactions
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
tunnel: `http://localhost:3031/`, // proxy server
tracesSampleRate: 1.0,
sendDefaultPii: true,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as Sentry from '@sentry/nextjs';

Sentry.init({
environment: 'qa', // dynamic sampling bias to keep transactions
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
tunnel: `http://localhost:3031/`, // proxy server
tracesSampleRate: 1.0,
sendDefaultPii: true,
transportOptions: {
// We are doing a lot of events at once in this test
bufferSize: 1000,
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as Sentry from '@sentry/nextjs';

Sentry.init({
environment: 'qa', // dynamic sampling bias to keep transactions
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
tunnel: `http://localhost:3031/`, // proxy server
tracesSampleRate: 1.0,
sendDefaultPii: true,
transportOptions: {
// We are doing a lot of events at once in this test
bufferSize: 1000,
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as fs from 'fs';
import * as path from 'path';
import { startEventProxyServer } from '@sentry-internal/test-utils';

const packageJson = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json')));

startEventProxyServer({
port: 3031,
proxyServerName: 'nextjs-turbo',
envelopeDumpPath: path.join(
process.cwd(),
`event-dumps/nextjs-turbo-${packageJson.dependencies.next}-${process.env.TEST_ENV}.dump`,
),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { expect, test } from '@playwright/test';
import { waitForError } from '@sentry-internal/test-utils';

test('Should capture errors from server components', async ({ page }) => {
const errorEventPromise = waitForError('nextjs-turbo', errorEvent => {
return !!errorEvent?.exception?.values?.some(value => value.value === 'page rsc render error');
});

await page.goto(`/123/rsc-page-error`);

const errorEvent = await errorEventPromise;

expect(errorEvent).toBeDefined();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "es2018",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"plugins": [
{
"name": "next"
}
],
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "next.config.js", ".next/types/**/*.ts"],
"exclude": ["node_modules", "playwright.config.ts"]
}
Loading