@sentry/wizard 6.9.0 → 6.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/CHANGELOG.md +56 -1
  2. package/dist/ci-ensure-runtime-loaded.sh +82 -0
  3. package/dist/e2e-tests/tests/angular-17.test.js +72 -82
  4. package/dist/e2e-tests/tests/angular-17.test.js.map +1 -1
  5. package/dist/e2e-tests/tests/angular-19.test.js +71 -80
  6. package/dist/e2e-tests/tests/angular-19.test.js.map +1 -1
  7. package/dist/e2e-tests/tests/cloudflare-worker.test.d.ts +1 -0
  8. package/dist/e2e-tests/tests/cloudflare-worker.test.js +64 -0
  9. package/dist/e2e-tests/tests/cloudflare-worker.test.js.map +1 -0
  10. package/dist/e2e-tests/tests/cloudflare-wrangler-sourcemaps.test.js +2 -5
  11. package/dist/e2e-tests/tests/cloudflare-wrangler-sourcemaps.test.js.map +1 -1
  12. package/dist/e2e-tests/tests/expo.test.js +36 -61
  13. package/dist/e2e-tests/tests/expo.test.js.map +1 -1
  14. package/dist/e2e-tests/tests/flutter.test.js +63 -70
  15. package/dist/e2e-tests/tests/flutter.test.js.map +1 -1
  16. package/dist/e2e-tests/tests/help-message.test.js +2 -2
  17. package/dist/e2e-tests/tests/help-message.test.js.map +1 -1
  18. package/dist/e2e-tests/tests/nextjs-14.test.js +54 -82
  19. package/dist/e2e-tests/tests/nextjs-14.test.js.map +1 -1
  20. package/dist/e2e-tests/tests/nextjs-15.test.js +95 -105
  21. package/dist/e2e-tests/tests/nextjs-15.test.js.map +1 -1
  22. package/dist/e2e-tests/tests/nextjs-16.test.d.ts +1 -0
  23. package/dist/e2e-tests/tests/nextjs-16.test.js +123 -0
  24. package/dist/e2e-tests/tests/nextjs-16.test.js.map +1 -0
  25. package/dist/e2e-tests/tests/nuxt-3.test.js +45 -58
  26. package/dist/e2e-tests/tests/nuxt-3.test.js.map +1 -1
  27. package/dist/e2e-tests/tests/nuxt-4.test.js +59 -73
  28. package/dist/e2e-tests/tests/nuxt-4.test.js.map +1 -1
  29. package/dist/e2e-tests/tests/pnpm-workspace.test.js +4 -7
  30. package/dist/e2e-tests/tests/pnpm-workspace.test.js.map +1 -1
  31. package/dist/e2e-tests/tests/react-native.test.js +44 -80
  32. package/dist/e2e-tests/tests/react-native.test.js.map +1 -1
  33. package/dist/e2e-tests/tests/react-router.test.js +163 -145
  34. package/dist/e2e-tests/tests/react-router.test.js.map +1 -1
  35. package/dist/e2e-tests/tests/remix.test.js +162 -132
  36. package/dist/e2e-tests/tests/remix.test.js.map +1 -1
  37. package/dist/e2e-tests/tests/sveltekit-hooks.test.js +48 -36
  38. package/dist/e2e-tests/tests/sveltekit-hooks.test.js.map +1 -1
  39. package/dist/e2e-tests/tests/sveltekit-tracing.test.js +3 -6
  40. package/dist/e2e-tests/tests/sveltekit-tracing.test.js.map +1 -1
  41. package/dist/e2e-tests/utils/index.d.ts +21 -43
  42. package/dist/e2e-tests/utils/index.js +108 -183
  43. package/dist/e2e-tests/utils/index.js.map +1 -1
  44. package/dist/get-e2e-test-matrix.mjs +11 -0
  45. package/dist/lib/Constants.d.ts +1 -0
  46. package/dist/lib/Constants.js +5 -0
  47. package/dist/lib/Constants.js.map +1 -1
  48. package/dist/src/android/android-wizard.js +2 -4
  49. package/dist/src/android/android-wizard.js.map +1 -1
  50. package/dist/src/angular/angular-wizard.js +4 -6
  51. package/dist/src/angular/angular-wizard.js.map +1 -1
  52. package/dist/src/angular/sdk-setup.js +1 -1
  53. package/dist/src/angular/sdk-setup.js.map +1 -1
  54. package/dist/src/apple/apple-wizard.js +2 -4
  55. package/dist/src/apple/apple-wizard.js.map +1 -1
  56. package/dist/src/cloudflare/cloudflare-wizard.d.ts +3 -0
  57. package/dist/src/cloudflare/cloudflare-wizard.js +99 -0
  58. package/dist/src/cloudflare/cloudflare-wizard.js.map +1 -0
  59. package/dist/src/cloudflare/sdk-setup.d.ts +7 -0
  60. package/dist/src/cloudflare/sdk-setup.js +47 -0
  61. package/dist/src/cloudflare/sdk-setup.js.map +1 -0
  62. package/dist/src/cloudflare/templates.d.ts +4 -0
  63. package/dist/src/cloudflare/templates.js +44 -0
  64. package/dist/src/cloudflare/templates.js.map +1 -0
  65. package/dist/src/cloudflare/wrangler/create-wrangler-config.d.ts +4 -0
  66. package/dist/src/cloudflare/wrangler/create-wrangler-config.js +27 -0
  67. package/dist/src/cloudflare/wrangler/create-wrangler-config.js.map +1 -0
  68. package/dist/src/cloudflare/wrangler/ensure-wrangler-config.d.ts +4 -0
  69. package/dist/src/cloudflare/wrangler/ensure-wrangler-config.js +25 -0
  70. package/dist/src/cloudflare/wrangler/ensure-wrangler-config.js.map +1 -0
  71. package/dist/src/cloudflare/wrangler/find-wrangler-config.d.ts +4 -0
  72. package/dist/src/cloudflare/wrangler/find-wrangler-config.js +23 -0
  73. package/dist/src/cloudflare/wrangler/find-wrangler-config.js.map +1 -0
  74. package/dist/src/cloudflare/wrangler/get-entry-point-from-wrangler-config.d.ts +6 -0
  75. package/dist/src/cloudflare/wrangler/get-entry-point-from-wrangler-config.js +52 -0
  76. package/dist/src/cloudflare/wrangler/get-entry-point-from-wrangler-config.js.map +1 -0
  77. package/dist/src/cloudflare/wrangler/update-wrangler-config.d.ts +17 -0
  78. package/dist/src/cloudflare/wrangler/update-wrangler-config.js +173 -0
  79. package/dist/src/cloudflare/wrangler/update-wrangler-config.js.map +1 -0
  80. package/dist/src/cloudflare/wrap-worker.d.ts +32 -0
  81. package/dist/src/cloudflare/wrap-worker.js +109 -0
  82. package/dist/src/cloudflare/wrap-worker.js.map +1 -0
  83. package/dist/src/flutter/flutter-wizard.js +3 -6
  84. package/dist/src/flutter/flutter-wizard.js.map +1 -1
  85. package/dist/src/nextjs/nextjs-wizard.js +46 -10
  86. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  87. package/dist/src/nextjs/templates.d.ts +6 -3
  88. package/dist/src/nextjs/templates.js +144 -93
  89. package/dist/src/nextjs/templates.js.map +1 -1
  90. package/dist/src/nuxt/nuxt-wizard.js +3 -5
  91. package/dist/src/nuxt/nuxt-wizard.js.map +1 -1
  92. package/dist/src/react-native/react-native-wizard.js +2 -4
  93. package/dist/src/react-native/react-native-wizard.js.map +1 -1
  94. package/dist/src/react-router/codemods/client.entry.js +4 -1
  95. package/dist/src/react-router/codemods/client.entry.js.map +1 -1
  96. package/dist/src/react-router/react-router-wizard.js +3 -5
  97. package/dist/src/react-router/react-router-wizard.js.map +1 -1
  98. package/dist/src/react-router/sdk-example.js +5 -2
  99. package/dist/src/react-router/sdk-example.js.map +1 -1
  100. package/dist/src/react-router/sdk-setup.d.ts +1 -1
  101. package/dist/src/react-router/sdk-setup.js +3 -4
  102. package/dist/src/react-router/sdk-setup.js.map +1 -1
  103. package/dist/src/remix/remix-wizard.js +2 -4
  104. package/dist/src/remix/remix-wizard.js.map +1 -1
  105. package/dist/src/run.d.ts +1 -1
  106. package/dist/src/run.js +5 -0
  107. package/dist/src/run.js.map +1 -1
  108. package/dist/src/sourcemaps/tools/sentry-cli.js +1 -1
  109. package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
  110. package/dist/src/sourcemaps/tools/wrangler.js +1 -1
  111. package/dist/src/sourcemaps/tools/wrangler.js.map +1 -1
  112. package/dist/src/sveltekit/sveltekit-wizard.js +4 -6
  113. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  114. package/dist/src/telemetry.d.ts +1 -1
  115. package/dist/src/telemetry.js +52 -31
  116. package/dist/src/telemetry.js.map +1 -1
  117. package/dist/src/utils/abort-if-sportlight-not-supported.d.ts +5 -0
  118. package/dist/src/utils/abort-if-sportlight-not-supported.js +40 -0
  119. package/dist/src/utils/abort-if-sportlight-not-supported.js.map +1 -0
  120. package/dist/src/utils/ast-utils.d.ts +1 -1
  121. package/dist/src/utils/ast-utils.js.map +1 -1
  122. package/dist/src/utils/clack/index.d.ts +19 -2
  123. package/dist/src/utils/clack/index.js +174 -12
  124. package/dist/src/utils/clack/index.js.map +1 -1
  125. package/dist/src/utils/clack/mcp-config.js +117 -59
  126. package/dist/src/utils/clack/mcp-config.js.map +1 -1
  127. package/dist/src/version.d.ts +1 -1
  128. package/dist/src/version.js +1 -1
  129. package/dist/src/version.js.map +1 -1
  130. package/dist/test/angular/angular-wizard.test.js +2 -4
  131. package/dist/test/angular/angular-wizard.test.js.map +1 -1
  132. package/dist/test/apple/cocoapod.test.js +7 -3
  133. package/dist/test/apple/cocoapod.test.js.map +1 -1
  134. package/dist/test/apple/code-tools.test.js +8 -2
  135. package/dist/test/apple/code-tools.test.js.map +1 -1
  136. package/dist/test/cloudflare/create-wrangler-config.test.d.ts +1 -0
  137. package/dist/test/cloudflare/create-wrangler-config.test.js +48 -0
  138. package/dist/test/cloudflare/create-wrangler-config.test.js.map +1 -0
  139. package/dist/test/cloudflare/ensure-wrangler-config.test.d.ts +1 -0
  140. package/dist/test/cloudflare/ensure-wrangler-config.test.js +61 -0
  141. package/dist/test/cloudflare/ensure-wrangler-config.test.js.map +1 -0
  142. package/dist/test/cloudflare/find-wrangler-config.test.d.ts +1 -0
  143. package/dist/test/cloudflare/find-wrangler-config.test.js +77 -0
  144. package/dist/test/cloudflare/find-wrangler-config.test.js.map +1 -0
  145. package/dist/test/cloudflare/get-entry-point-from-wrangler-config.test.d.ts +1 -0
  146. package/dist/test/cloudflare/get-entry-point-from-wrangler-config.test.js +81 -0
  147. package/dist/test/cloudflare/get-entry-point-from-wrangler-config.test.js.map +1 -0
  148. package/dist/test/cloudflare/sdk-setup.test.d.ts +1 -0
  149. package/dist/test/cloudflare/sdk-setup.test.js +152 -0
  150. package/dist/test/cloudflare/sdk-setup.test.js.map +1 -0
  151. package/dist/test/cloudflare/templates.test.d.ts +1 -0
  152. package/dist/test/cloudflare/templates.test.js +68 -0
  153. package/dist/test/cloudflare/templates.test.js.map +1 -0
  154. package/dist/test/cloudflare/update-wrangler-config.test.d.ts +1 -0
  155. package/dist/test/cloudflare/update-wrangler-config.test.js +216 -0
  156. package/dist/test/cloudflare/update-wrangler-config.test.js.map +1 -0
  157. package/dist/test/cloudflare/wrap-worker.test.d.ts +1 -0
  158. package/dist/test/cloudflare/wrap-worker.test.js +143 -0
  159. package/dist/test/cloudflare/wrap-worker.test.js.map +1 -0
  160. package/dist/test/nextjs/templates.test.js +156 -87
  161. package/dist/test/nextjs/templates.test.js.map +1 -1
  162. package/dist/test/nextjs/wizard-double-wrap-prevention.test.js +12 -7
  163. package/dist/test/nextjs/wizard-double-wrap-prevention.test.js.map +1 -1
  164. package/dist/test/react-router/sdk-setup.test.js +2 -2
  165. package/dist/test/react-router/sdk-setup.test.js.map +1 -1
  166. package/dist/test/utils/clack/index.test.js +37 -29
  167. package/dist/test/utils/clack/index.test.js.map +1 -1
  168. package/dist/test/utils/clack/mcp-config.test.js +176 -51
  169. package/dist/test/utils/clack/mcp-config.test.js.map +1 -1
  170. package/package.json +6 -5
@@ -1 +1 @@
1
- {"version":3,"file":"react-router.test.js","sourceRoot":"","sources":["../../../e2e-tests/tests/react-router.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { Integration } from '../../lib/Constants';\nimport {\n KEYS,\n TEST_ARGS,\n checkEnvBuildPlugin,\n checkFileContents,\n checkFileExists,\n checkIfBuilds,\n checkIfRunsOnDevMode,\n checkIfRunsOnProdMode,\n checkPackageJson,\n cleanupGit,\n revertLocalChanges,\n startWizardInstance,\n} from '../utils';\nimport { afterAll, beforeAll, describe, test, expect } from 'vitest';\n\nasync function runWizardOnReactRouterProject(\n projectDir: string,\n integration: Integration,\n) {\n const wizardInstance = startWizardInstance(integration, projectDir);\n\n const packageManagerPrompted = await wizardInstance.waitForOutput(\n 'Please select your package manager.',\n );\n\n const tracingOptionPrompted =\n packageManagerPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.DOWN, KEYS.ENTER],\n 'to track the performance of your application?',\n { timeout: 240_000 }\n ));\n\n const replayOptionPrompted =\n tracingOptionPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.ENTER],\n 'to get a video-like reproduction of errors during a user session?'\n ));\n\n const logOptionPrompted =\n replayOptionPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.ENTER],\n 'to send your application logs to Sentry?'\n ));\n\n const profilingOptionPrompted =\n logOptionPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.ENTER],\n 'to track application performance in detail?'\n ));\n\n const examplePagePrompted =\n profilingOptionPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.ENTER],\n 'Do you want to create an example page'\n ));\n\n const mcpPrompted =\n examplePagePrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.ENTER],\n 'Optionally add a project-scoped MCP server configuration for the Sentry MCP?',\n { optional: true }\n ));\n\n mcpPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.DOWN, KEYS.ENTER],\n 'Successfully installed the Sentry React Router SDK!'\n ));\n\n wizardInstance.kill();\n}\n\nfunction checkReactRouterProject(projectDir: string, integration: Integration) {\n test('package.json is updated correctly', () => {\n checkPackageJson(projectDir, integration);\n });\n\n test('.env.sentry-build-plugin is created and contains the auth token', () => {\n checkEnvBuildPlugin(projectDir);\n });\n\n test('example page exists', () => {\n checkFileExists(`${projectDir}/app/routes/sentry-example-page.tsx`);\n });\n\n test('example API route exists', () => {\n checkFileExists(`${projectDir}/app/routes/api.sentry-example-api.ts`);\n });\n\n test('example page is added to routes configuration', () => {\n checkFileContents(`${projectDir}/app/routes.ts`, [\n 'route(\"/sentry-example-page\", \"routes/sentry-example-page.tsx\")',\n 'route(\"/api/sentry-example-api\", \"routes/api.sentry-example-api.ts\")',\n ]);\n });\n\n test('instrument.server file exists', () => {\n checkFileExists(`${projectDir}/instrument.server.mjs`);\n });\n\n test('entry.client file contains Sentry initialization', () => {\n checkFileContents(`${projectDir}/app/entry.client.tsx`, [\n 'import * as Sentry from',\n '@sentry/react-router',\n `Sentry.init({\n dsn: \"${TEST_ARGS.PROJECT_DSN}\",`,\n 'integrations: [Sentry.reactRouterTracingIntegration(), Sentry.replayIntegration()]',\n 'enableLogs: true,',\n 'tracesSampleRate: 1.0,',\n ]);\n });\n\n test('package.json scripts are updated correctly', () => {\n checkFileContents(`${projectDir}/package.json`, [\n `\"start\": \"NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js\"`,\n `\"dev\": \"NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev\"`,\n ]);\n });\n\n test('entry.server file contains Sentry instrumentation', () => {\n checkFileContents(`${projectDir}/app/entry.server.tsx`, [\n 'import * as Sentry from',\n '@sentry/react-router',\n 'export const handleError = Sentry.createSentryHandleError(',\n 'export default Sentry.wrapSentryHandleRequest(handleRequest);'\n ]);\n });\n\n test('instrument.server file contains Sentry initialization', () => {\n checkFileContents(`${projectDir}/instrument.server.mjs`, [\n 'import * as Sentry from \\'@sentry/react-router\\';',\n `Sentry.init({\n dsn: \"${TEST_ARGS.PROJECT_DSN}\",`,\n 'enableLogs: true,',\n ]);\n });\n\n test('root file contains Sentry ErrorBoundary', () => {\n checkFileContents(`${projectDir}/app/root.tsx`, [\n 'import * as Sentry from',\n '@sentry/react-router',\n 'export function ErrorBoundary',\n 'Sentry.captureException(error)',\n ]);\n });\n\n test('vite.config file contains sentryReactRouter plugin', () => {\n checkFileContents(`${projectDir}/vite.config.ts`, [\n 'import { sentryReactRouter } from',\n '@sentry/react-router',\n 'sentryReactRouter(',\n 'authToken: process.env.SENTRY_AUTH_TOKEN',\n ]);\n });\n\n test('react-router.config file contains buildEnd hook with sentryOnBuildEnd', () => {\n checkFileContents(`${projectDir}/react-router.config.ts`, [\n 'import { sentryOnBuildEnd } from',\n '@sentry/react-router',\n 'ssr: true,',\n 'buildEnd: async',\n 'await sentryOnBuildEnd({',\n ]);\n });\n\n test('builds successfully', async () => {\n await checkIfBuilds(projectDir);\n }, 60000); // 1 minute timeout\n\n test('runs on dev mode correctly', async () => {\n await checkIfRunsOnDevMode(projectDir, 'to expose');\n }, 30000); // 30 second timeout\n\n test('runs on prod mode correctly', async () => {\n await checkIfRunsOnProdMode(projectDir, 'react-router-serve');\n }, 30000); // 30 second timeout\n}\n\ndescribe('React Router', () => {\n describe('with empty project', () => {\n const integration = Integration.reactRouter;\n const projectDir = path.resolve(\n __dirname,\n '../test-applications/react-router-test-app',\n );\n\n beforeAll(async () => {\n await runWizardOnReactRouterProject(projectDir, integration);\n });\n\n afterAll(() => {\n revertLocalChanges(projectDir);\n cleanupGit(projectDir);\n });\n\n checkReactRouterProject(projectDir, integration);\n });\n\n describe('edge cases', () => {\n const baseProjectDir = path.resolve(\n __dirname,\n '../test-applications/react-router-test-app',\n );\n\n describe('existing Sentry setup', () => {\n const integration = Integration.reactRouter;\n const projectDir = path.resolve(\n __dirname,\n '../test-applications/react-router-test-app-existing',\n );\n\n beforeAll(async () => {\n // Copy project and add existing Sentry setup\n fs.cpSync(baseProjectDir, projectDir, { recursive: true });\n\n const clientEntryPath = path.join(projectDir, 'app', 'entry.client.tsx');\n const existingContent = `import * as Sentry from \"@sentry/react-router\";\nimport { startTransition, StrictMode } from \"react\";\nimport { hydrateRoot } from \"react-dom/client\";\nimport { HydratedRouter } from \"react-router/dom\";\n\nSentry.init({\n dsn: \"https://existing@dsn.ingest.sentry.io/1337\",\n tracesSampleRate: 1.0,\n});\n\nstartTransition(() => {\n hydrateRoot(\n document,\n <StrictMode>\n <HydratedRouter />\n </StrictMode>\n );\n});`;\n fs.writeFileSync(clientEntryPath, existingContent);\n\n await runWizardOnReactRouterProject(projectDir, integration);\n });\n\n afterAll(() => {\n revertLocalChanges(projectDir);\n cleanupGit(projectDir);\n try {\n fs.rmSync(projectDir, { recursive: true, force: true });\n } catch (e) {\n // Ignore cleanup errors\n }\n });\n\n test('wizard handles existing Sentry without duplication', () => {\n const clientContent = fs.readFileSync(`${projectDir}/app/entry.client.tsx`, 'utf8');\n const sentryImportCount = (clientContent.match(/import \\* as Sentry from \"@sentry\\/react-router\"/g) || []).length;\n const sentryInitCount = (clientContent.match(/Sentry\\.init\\(/g) || []).length;\n\n expect(sentryImportCount).toBe(1);\n expect(sentryInitCount).toBe(1);\n });\n\n // Only test the essential checks for this edge case\n test('package.json is updated correctly', () => {\n checkPackageJson(projectDir, integration);\n });\n\n test('essential files exist or wizard completes gracefully', () => {\n // Check if key directories exist\n expect(fs.existsSync(`${projectDir}/app`)).toBe(true);\n\n // When there's existing Sentry setup, the wizard may skip some file creation\n // to avoid conflicts. This is acceptable behavior.\n // Let's check if the wizard at least completed by verifying package.json was updated\n const packageJsonPath = `${projectDir}/package.json`;\n expect(fs.existsSync(packageJsonPath)).toBe(true);\n\n const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(packageJsonContent) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n\n const hasSentryPackage =\n (packageJson.dependencies?.['@sentry/react-router']) ||\n (packageJson.devDependencies?.['@sentry/react-router']);\n\n // The wizard should have at least installed the Sentry package\n expect(hasSentryPackage).toBeTruthy();\n });\n });\n\n describe('missing entry files', () => {\n const integration = Integration.reactRouter;\n const projectDir = path.resolve(\n __dirname,\n '../test-applications/react-router-test-app-missing-entries',\n );\n\n beforeAll(async () => {\n // Copy project and remove entry files\n fs.cpSync(baseProjectDir, projectDir, { recursive: true });\n\n const entryClientPath = path.join(projectDir, 'app', 'entry.client.tsx');\n const entryServerPath = path.join(projectDir, 'app', 'entry.server.tsx');\n\n if (fs.existsSync(entryClientPath)) fs.unlinkSync(entryClientPath);\n if (fs.existsSync(entryServerPath)) fs.unlinkSync(entryServerPath);\n\n await runWizardOnReactRouterProject(projectDir, integration);\n });\n\n afterAll(() => {\n revertLocalChanges(projectDir);\n cleanupGit(projectDir);\n try {\n fs.rmSync(projectDir, { recursive: true, force: true });\n } catch (e) {\n // Ignore cleanup errors\n }\n });\n\n test('wizard creates missing entry files', () => {\n checkFileExists(`${projectDir}/app/entry.client.tsx`);\n checkFileExists(`${projectDir}/app/entry.server.tsx`);\n });\n\n test('basic configuration still works', () => {\n checkPackageJson(projectDir, integration);\n checkFileExists(`${projectDir}/instrument.server.mjs`);\n });\n });\n });\n});\n"]}
1
+ {"version":3,"file":"react-router.test.js","sourceRoot":"","sources":["../../../e2e-tests/tests/react-router.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { Integration } from '../../lib/Constants';\nimport {\n TEST_ARGS,\n checkEnvBuildPlugin,\n checkFileContents,\n checkFileExists,\n checkIfBuilds,\n checkIfRunsOnDevMode,\n checkIfRunsOnProdMode,\n checkPackageJson,\n createIsolatedTestEnv,\n getWizardCommand,\n} from '../utils';\nimport { afterAll, beforeAll, describe, test, expect } from 'vitest';\n\n//@ts-expect-error - clifty is ESM only\nimport { KEYS, withEnv } from 'clifty';\n\nasync function runWizardOnReactRouterProject(\n projectDir: string,\n opts?: {\n modifiedFiles?: boolean;\n },\n): Promise<number> {\n const { modifiedFiles = false } = opts || {};\n\n const wizardInteraction = withEnv({\n cwd: projectDir,\n }).defineInteraction();\n\n if (modifiedFiles) {\n wizardInteraction\n .whenAsked('Do you want to continue anyway?')\n .respondWith(KEYS.ENTER);\n }\n\n wizardInteraction\n .whenAsked('Please select your package manager.')\n .respondWith(KEYS.DOWN, KEYS.ENTER)\n .expectOutput('Installing @sentry/react-router')\n .expectOutput('Installed @sentry/react-router', {\n timeout: 240_000,\n })\n\n .whenAsked('Do you want to enable Tracing')\n .respondWith(KEYS.ENTER)\n .whenAsked('Do you want to enable Session Replay')\n .respondWith(KEYS.ENTER)\n .whenAsked('Do you want to enable Logs')\n .respondWith(KEYS.ENTER)\n .whenAsked('Do you want to enable Profiling')\n .respondWith(KEYS.ENTER)\n .expectOutput('Installing @sentry/profiling-node')\n .expectOutput('Installed @sentry/profiling-node', {\n timeout: 240_000,\n })\n .whenAsked('Do you want to create an example page')\n .respondWith(KEYS.ENTER);\n\n if (modifiedFiles) {\n wizardInteraction\n .whenAsked('Would you like to try running npx react-router reveal')\n .respondWith(KEYS.ENTER)\n .whenAsked('Did you apply the snippet above?')\n .respondWith(KEYS.ENTER);\n }\n\n return wizardInteraction\n .whenAsked(\n 'Optionally add a project-scoped MCP server configuration for the Sentry MCP?',\n )\n .respondWith(KEYS.DOWN, KEYS.ENTER)\n .expectOutput('Successfully installed the Sentry React Router SDK!')\n .run(getWizardCommand(Integration.reactRouter));\n}\n\ndescribe('React Router', () => {\n describe('with empty project', () => {\n let wizardExitCode: number;\n const { projectDir, cleanup } = createIsolatedTestEnv(\n 'react-router-test-app',\n );\n\n beforeAll(async () => {\n wizardExitCode = await runWizardOnReactRouterProject(projectDir);\n });\n\n afterAll(() => {\n cleanup();\n });\n\n test('exits with exit code 0', () => {\n expect(wizardExitCode).toBe(0);\n });\n\n test('package.json is updated correctly', () => {\n checkPackageJson(projectDir, '@sentry/react-router');\n });\n\n test('.env.sentry-build-plugin is created and contains the auth token', () => {\n checkEnvBuildPlugin(projectDir);\n });\n\n test('example page exists', () => {\n checkFileExists(`${projectDir}/app/routes/sentry-example-page.tsx`);\n });\n\n test('example API route exists', () => {\n checkFileExists(`${projectDir}/app/routes/api.sentry-example-api.ts`);\n });\n\n test('example page is added to routes configuration', () => {\n checkFileContents(`${projectDir}/app/routes.ts`, [\n 'route(\"/sentry-example-page\", \"routes/sentry-example-page.tsx\")',\n 'route(\"/api/sentry-example-api\", \"routes/api.sentry-example-api.ts\")',\n ]);\n });\n\n test('instrument.server file exists', () => {\n checkFileExists(`${projectDir}/instrument.server.mjs`);\n });\n\n test('entry.client file contains Sentry initialization', () => {\n checkFileContents(`${projectDir}/app/entry.client.tsx`, [\n 'import * as Sentry from',\n '@sentry/react-router',\n `Sentry.init({\n dsn: \"${TEST_ARGS.PROJECT_DSN}\",`,\n 'integrations: [Sentry.reactRouterTracingIntegration(), Sentry.replayIntegration()]',\n 'enableLogs: true,',\n 'tracesSampleRate: 1.0,',\n ]);\n });\n\n test('package.json scripts are updated correctly', () => {\n checkFileContents(`${projectDir}/package.json`, [\n `\"start\": \"NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js\"`,\n `\"dev\": \"NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev\"`,\n ]);\n });\n\n test('entry.server file contains Sentry instrumentation', () => {\n checkFileContents(`${projectDir}/app/entry.server.tsx`, [\n 'import * as Sentry from',\n '@sentry/react-router',\n 'export const handleError = Sentry.createSentryHandleError(',\n 'export default Sentry.wrapSentryHandleRequest(handleRequest);',\n ]);\n });\n\n test('instrument.server file contains Sentry initialization', () => {\n checkFileContents(`${projectDir}/instrument.server.mjs`, [\n \"import * as Sentry from '@sentry/react-router';\",\n `Sentry.init({\n dsn: \"${TEST_ARGS.PROJECT_DSN}\",`,\n 'enableLogs: true,',\n ]);\n });\n\n test('root file contains Sentry ErrorBoundary', () => {\n checkFileContents(`${projectDir}/app/root.tsx`, [\n 'import * as Sentry from',\n '@sentry/react-router',\n 'export function ErrorBoundary',\n 'Sentry.captureException(error)',\n ]);\n });\n\n test('vite.config file contains sentryReactRouter plugin', () => {\n checkFileContents(`${projectDir}/vite.config.ts`, [\n 'import { sentryReactRouter } from',\n '@sentry/react-router',\n 'sentryReactRouter(',\n 'authToken: process.env.SENTRY_AUTH_TOKEN',\n ]);\n });\n\n test('react-router.config file contains buildEnd hook with sentryOnBuildEnd', () => {\n checkFileContents(`${projectDir}/react-router.config.ts`, [\n 'import { sentryOnBuildEnd } from',\n '@sentry/react-router',\n 'ssr: true,',\n 'buildEnd: async',\n 'await sentryOnBuildEnd({',\n ]);\n });\n\n test('builds successfully', async () => {\n await checkIfBuilds(projectDir);\n }, 60_000); // 1 minute timeout\n\n test('runs on dev mode correctly', async () => {\n await checkIfRunsOnDevMode(projectDir, 'to expose');\n }, 30_000); // 30 second timeout\n\n test('runs on prod mode correctly', async () => {\n await checkIfRunsOnProdMode(projectDir, 'react-router-serve');\n }, 30_000); // 30 second timeout\n });\n\n describe('edge cases', () => {\n describe('existing Sentry setup', () => {\n let wizardExitCode: number;\n\n const { projectDir, cleanup } = createIsolatedTestEnv(\n 'react-router-test-app',\n );\n\n beforeAll(async () => {\n // Add existing Sentry setup to the isolated test app\n const clientEntryPath = path.join(\n projectDir,\n 'app',\n 'entry.client.tsx',\n );\n const existingContent = `import * as Sentry from \"@sentry/react-router\";\nimport { startTransition, StrictMode } from \"react\";\nimport { hydrateRoot } from \"react-dom/client\";\nimport { HydratedRouter } from \"react-router/dom\";\n\nSentry.init({\n dsn: \"https://existing@dsn.ingest.sentry.io/1337\",\n tracesSampleRate: 1.0,\n});\n\nstartTransition(() => {\n hydrateRoot(\n document,\n <StrictMode>\n <HydratedRouter />\n </StrictMode>\n );\n});`;\n fs.writeFileSync(clientEntryPath, existingContent);\n\n wizardExitCode = await runWizardOnReactRouterProject(projectDir, {\n modifiedFiles: true,\n });\n });\n\n afterAll(() => {\n cleanup();\n });\n\n test('exits with exit code 0', () => {\n expect(wizardExitCode).toBe(0);\n });\n\n test('wizard handles existing Sentry without duplication', () => {\n const clientContent = fs.readFileSync(\n `${projectDir}/app/entry.client.tsx`,\n 'utf8',\n );\n const sentryImportCount = (\n clientContent.match(\n /import \\* as Sentry from \"@sentry\\/react-router\"/g,\n ) || []\n ).length;\n const sentryInitCount = (clientContent.match(/Sentry\\.init\\(/g) || [])\n .length;\n\n expect(sentryImportCount).toBe(1);\n expect(sentryInitCount).toBe(1);\n });\n\n // Only test the essential checks for this edge case\n test('package.json is updated correctly', () => {\n checkPackageJson(projectDir, '@sentry/react-router');\n });\n\n test('essential files exist or wizard completes gracefully', () => {\n // Check if key directories exist\n expect(fs.existsSync(`${projectDir}/app`)).toBe(true);\n\n // When there's existing Sentry setup, the wizard may skip some file creation\n // to avoid conflicts. This is acceptable behavior.\n // Let's check if the wizard at least completed by verifying package.json was updated\n const packageJsonPath = `${projectDir}/package.json`;\n expect(fs.existsSync(packageJsonPath)).toBe(true);\n\n const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(packageJsonContent) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n\n const hasSentryPackage =\n packageJson.dependencies?.['@sentry/react-router'] ||\n packageJson.devDependencies?.['@sentry/react-router'];\n\n // The wizard should have at least installed the Sentry package\n expect(hasSentryPackage).toBeTruthy();\n });\n });\n\n describe('missing entry files', () => {\n let wizardExitCode: number;\n\n const { projectDir, cleanup } = createIsolatedTestEnv(\n 'react-router-test-app',\n );\n\n beforeAll(async () => {\n // Copy project and remove entry files\n\n const entryClientPath = path.join(\n projectDir,\n 'app',\n 'entry.client.tsx',\n );\n const entryServerPath = path.join(\n projectDir,\n 'app',\n 'entry.server.tsx',\n );\n\n if (fs.existsSync(entryClientPath)) fs.unlinkSync(entryClientPath);\n if (fs.existsSync(entryServerPath)) fs.unlinkSync(entryServerPath);\n\n wizardExitCode = await runWizardOnReactRouterProject(projectDir);\n });\n\n afterAll(() => {\n cleanup();\n });\n\n test('exits with exit code 0', () => {\n expect(wizardExitCode).toBe(0);\n });\n\n test('wizard creates missing entry files', () => {\n checkFileExists(`${projectDir}/app/entry.client.tsx`);\n checkFileExists(`${projectDir}/app/entry.server.tsx`);\n });\n\n test('basic configuration still works', () => {\n checkPackageJson(projectDir, '@sentry/react-router');\n checkFileExists(`${projectDir}/instrument.server.mjs`);\n });\n });\n });\n});\n"]}
@@ -1,32 +1,10 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  Object.defineProperty(exports, "__esModule", { value: true });
26
- const path = __importStar(require("node:path"));
27
3
  const Constants_1 = require("../../lib/Constants");
28
4
  const utils_1 = require("../utils");
29
5
  const vitest_1 = require("vitest");
6
+ //@ts-expect-error - clifty is ESM only
7
+ const clifty_1 = require("clifty");
30
8
  const SERVER_TEMPLATE = `import { createRequestHandler } from '@remix-run/express';
31
9
  import { installGlobals } from '@remix-run/node';
32
10
  import compression from 'compression';
@@ -70,70 +48,63 @@ app.all(
70
48
  app.listen(0, () => console.log('Express server listening'));
71
49
  `;
72
50
  async function runWizardOnRemixProject(projectDir, integration, fileModificationFn) {
73
- const wizardInstance = (0, utils_1.startWizardInstance)(integration, projectDir);
74
- let packageManagerPrompted = false;
51
+ const wizardInteraction = (0, clifty_1.withEnv)({
52
+ cwd: projectDir,
53
+ }).defineInteraction();
75
54
  if (fileModificationFn) {
76
55
  fileModificationFn(projectDir, integration);
77
- await wizardInstance.waitForOutput('Do you want to continue anyway?');
78
- packageManagerPrompted = await wizardInstance.sendStdinAndWaitForOutput([utils_1.KEYS.ENTER], 'Please select your package manager.');
79
- }
80
- else {
81
- packageManagerPrompted = await wizardInstance.waitForOutput('Please select your package manager.');
56
+ wizardInteraction
57
+ .whenAsked('Do you want to continue anyway?')
58
+ .respondWith(clifty_1.KEYS.ENTER);
82
59
  }
83
- const tracingOptionPrompted = packageManagerPrompted &&
84
- (await wizardInstance.sendStdinAndWaitForOutput(
85
- // Selecting `yarn` as the package manager
86
- [utils_1.KEYS.DOWN, utils_1.KEYS.ENTER],
87
- // "Do you want to enable Tracing", sometimes doesn't work as `Tracing` can be printed in bold.
88
- 'to track the performance of your application?', {
89
- timeout: 240000,
90
- }));
91
- const replayOptionPrompted = tracingOptionPrompted &&
92
- (await wizardInstance.sendStdinAndWaitForOutput([utils_1.KEYS.ENTER],
93
- // "Do you want to enable Sentry Session Replay", sometimes doesn't work as `Sentry Session Replay` can be printed in bold.
94
- 'to get a video-like reproduction of errors during a user session?'));
95
- const logOptionPrompted = replayOptionPrompted &&
96
- (await wizardInstance.sendStdinAndWaitForOutput([utils_1.KEYS.ENTER],
97
- // "Do you want to enable Logs", sometimes doesn't work as `Logs` can be printed in bold.
98
- 'to send your application logs to Sentry?'));
99
- const examplePagePrompted = logOptionPrompted &&
100
- (await wizardInstance.sendStdinAndWaitForOutput([utils_1.KEYS.ENTER], 'Do you want to create an example page', {
101
- optional: true,
102
- }));
103
- // After the example page prompt, we send ENTER to accept it
104
- // Then handle the MCP prompt that comes after
105
- const mcpPrompted = examplePagePrompted &&
106
- (await wizardInstance.sendStdinAndWaitForOutput([utils_1.KEYS.ENTER], // This ENTER is for accepting the example page
107
- 'Optionally add a project-scoped MCP server configuration for the Sentry MCP?', {
108
- optional: true,
109
- }));
110
- // Decline MCP config (default is Yes, so press DOWN then ENTER to select No)
111
- if (mcpPrompted) {
112
- await wizardInstance.sendStdinAndWaitForOutput([utils_1.KEYS.DOWN, utils_1.KEYS.ENTER], 'Sentry has been successfully configured for your Remix project');
113
- }
114
- else {
115
- // If MCP wasn't prompted, wait for success message directly
116
- await wizardInstance.waitForOutput('Sentry has been successfully configured for your Remix project');
117
- }
118
- wizardInstance.kill();
60
+ return wizardInteraction
61
+ .whenAsked('Please select your package manager.')
62
+ .respondWith(clifty_1.KEYS.DOWN, clifty_1.KEYS.ENTER)
63
+ .whenAsked('to track the performance of your application?', {
64
+ timeout: 240000, // package installation can take a while in CI
65
+ })
66
+ .respondWith(clifty_1.KEYS.ENTER)
67
+ .whenAsked('to get a video-like reproduction of errors during a user session?')
68
+ .respondWith(clifty_1.KEYS.ENTER)
69
+ .whenAsked('to send your application logs to Sentry?')
70
+ .respondWith(clifty_1.KEYS.ENTER)
71
+ .whenAsked('Do you want to create an example page')
72
+ .respondWith(clifty_1.KEYS.ENTER)
73
+ .whenAsked('Optionally add a project-scoped MCP server configuration for the Sentry MCP?')
74
+ .respondWith(clifty_1.KEYS.DOWN, clifty_1.KEYS.ENTER)
75
+ .expectOutput('Sentry has been successfully configured for your Remix project')
76
+ .run((0, utils_1.getWizardCommand)(integration));
119
77
  }
120
- function checkRemixProject(projectDir, integration, options) {
121
- (0, vitest_1.test)('package.json is updated correctly', () => {
122
- (0, utils_1.checkPackageJson)(projectDir, integration);
123
- });
124
- (0, vitest_1.test)('.env-sentry-build-plugin is created and contains the auth token', () => {
125
- (0, utils_1.checkEnvBuildPlugin)(projectDir);
126
- });
127
- (0, vitest_1.test)('example page exists', () => {
128
- (0, utils_1.checkFileExists)(`${projectDir}/app/routes/sentry-example-page.tsx`);
129
- });
130
- (0, vitest_1.test)('instrumentation.server file exists', () => {
131
- (0, utils_1.checkFileExists)(`${projectDir}/instrumentation.server.mjs`);
132
- });
133
- (0, vitest_1.test)('entry.client file contains Sentry initialization', () => {
134
- (0, utils_1.checkFileContents)(`${projectDir}/app/entry.client.tsx`, [
135
- 'import { init, replayIntegration, browserTracingIntegration } from "@sentry/remix";',
136
- `init({
78
+ (0, vitest_1.describe)('Remix', () => {
79
+ (0, vitest_1.describe)('with empty project', () => {
80
+ const integration = Constants_1.Integration.remix;
81
+ let wizardExitCode;
82
+ const { projectDir, cleanup } = (0, utils_1.createIsolatedTestEnv)('remix-test-app');
83
+ (0, vitest_1.beforeAll)(async () => {
84
+ wizardExitCode = await runWizardOnRemixProject(projectDir, integration);
85
+ });
86
+ (0, vitest_1.afterAll)(() => {
87
+ cleanup();
88
+ });
89
+ (0, vitest_1.test)('exits with exit code 0', () => {
90
+ (0, vitest_1.expect)(wizardExitCode).toBe(0);
91
+ });
92
+ (0, vitest_1.test)('package.json is updated correctly', () => {
93
+ (0, utils_1.checkPackageJson)(projectDir, '@sentry/remix');
94
+ });
95
+ (0, vitest_1.test)('.env-sentry-build-plugin is created and contains the auth token', () => {
96
+ (0, utils_1.checkEnvBuildPlugin)(projectDir);
97
+ });
98
+ (0, vitest_1.test)('example page exists', () => {
99
+ (0, utils_1.checkFileExists)(`${projectDir}/app/routes/sentry-example-page.tsx`);
100
+ });
101
+ (0, vitest_1.test)('instrumentation.server file exists', () => {
102
+ (0, utils_1.checkFileExists)(`${projectDir}/instrumentation.server.mjs`);
103
+ });
104
+ (0, vitest_1.test)('entry.client file contains Sentry initialization', () => {
105
+ (0, utils_1.checkFileContents)(`${projectDir}/app/entry.client.tsx`, [
106
+ 'import { init, replayIntegration, browserTracingIntegration } from "@sentry/remix";',
107
+ `init({
137
108
  dsn: "${utils_1.TEST_ARGS.PROJECT_DSN}",
138
109
  tracesSampleRate: 1,
139
110
  enableLogs: true,
@@ -151,65 +122,53 @@ function checkRemixProject(projectDir, integration, options) {
151
122
  replaysOnErrorSampleRate: 1,
152
123
  sendDefaultPii: true
153
124
  })`,
154
- ]);
155
- });
156
- (0, vitest_1.test)('entry.server file contains Sentry code', () => {
157
- (0, utils_1.checkFileContents)(`${projectDir}/app/entry.server.tsx`, [
158
- 'import * as Sentry from "@sentry/remix";',
159
- `export const handleError = Sentry.wrapHandleErrorWithSentry((error, { request }) => {
125
+ ]);
126
+ });
127
+ (0, vitest_1.test)('entry.server file contains Sentry code', () => {
128
+ (0, utils_1.checkFileContents)(`${projectDir}/app/entry.server.tsx`, [
129
+ 'import * as Sentry from "@sentry/remix";',
130
+ `export const handleError = Sentry.wrapHandleErrorWithSentry((error, { request }) => {
160
131
  // Custom handleError implementation
161
132
  });`,
162
- ]);
163
- });
164
- (0, vitest_1.test)('instrumentation.server file contains Sentry initialization', () => {
165
- (0, utils_1.checkFileContents)(`${projectDir}/instrumentation.server.mjs`, [
166
- 'import * as Sentry from "@sentry/remix";',
167
- `Sentry.init({
133
+ ]);
134
+ });
135
+ (0, vitest_1.test)('instrumentation.server file contains Sentry initialization', () => {
136
+ (0, utils_1.checkFileContents)(`${projectDir}/instrumentation.server.mjs`, [
137
+ 'import * as Sentry from "@sentry/remix";',
138
+ `Sentry.init({
168
139
  dsn: "${utils_1.TEST_ARGS.PROJECT_DSN}",
169
140
  tracesSampleRate: 1,
170
141
  enableLogs: true
171
142
  })`,
172
- ]);
173
- });
174
- (0, vitest_1.test)('root file contains Sentry ErrorBoundary and withSentry wrapper', () => {
175
- (0, utils_1.checkFileContents)(`${projectDir}/app/root.tsx`, [
176
- 'import { captureRemixErrorBoundaryError, withSentry } from "@sentry/remix";',
177
- `export const ErrorBoundary = () => {
143
+ ]);
144
+ });
145
+ (0, vitest_1.test)('root file contains Sentry ErrorBoundary and withSentry wrapper', () => {
146
+ (0, utils_1.checkFileContents)(`${projectDir}/app/root.tsx`, [
147
+ 'import { captureRemixErrorBoundaryError, withSentry } from "@sentry/remix";',
148
+ `export const ErrorBoundary = () => {
178
149
  const error = useRouteError();
179
150
  captureRemixErrorBoundaryError(error);
180
151
  return <div>Something went wrong</div>;
181
152
  };`,
182
- `export default withSentry(App);`,
183
- ]);
184
- });
185
- (0, vitest_1.test)('builds successfully', async () => {
186
- await (0, utils_1.checkIfBuilds)(projectDir);
187
- });
188
- (0, vitest_1.test)('runs on dev mode correctly', async () => {
189
- await (0, utils_1.checkIfRunsOnDevMode)(projectDir, options?.devModeExpectedOutput || 'to expose');
190
- });
191
- (0, vitest_1.test)('runs on prod mode correctly', async () => {
192
- await (0, utils_1.checkIfRunsOnProdMode)(projectDir, options?.prodModeExpectedOutput || '[remix-serve]');
193
- });
194
- }
195
- (0, vitest_1.describe)('Remix', () => {
196
- (0, vitest_1.describe)('with empty project', () => {
197
- const integration = Constants_1.Integration.remix;
198
- const projectDir = path.resolve(__dirname, '../test-applications/remix-test-app');
199
- (0, vitest_1.beforeAll)(async () => {
200
- await runWizardOnRemixProject(projectDir, integration);
153
+ `export default withSentry(App);`,
154
+ ]);
201
155
  });
202
- (0, vitest_1.afterAll)(() => {
203
- (0, utils_1.revertLocalChanges)(projectDir);
204
- (0, utils_1.cleanupGit)(projectDir);
156
+ (0, vitest_1.test)('builds successfully', async () => {
157
+ await (0, utils_1.checkIfBuilds)(projectDir);
158
+ });
159
+ (0, vitest_1.test)('runs on dev mode correctly', async () => {
160
+ await (0, utils_1.checkIfRunsOnDevMode)(projectDir, 'to expose');
161
+ });
162
+ (0, vitest_1.test)('runs on prod mode correctly', async () => {
163
+ await (0, utils_1.checkIfRunsOnProdMode)(projectDir, '[remix-serve]');
205
164
  });
206
- checkRemixProject(projectDir, integration);
207
165
  });
208
166
  (0, vitest_1.describe)('with existing custom Express server', () => {
209
167
  const integration = Constants_1.Integration.remix;
210
- const projectDir = path.resolve(__dirname, '../test-applications/remix-test-app');
168
+ let wizardExitCode;
169
+ const { projectDir, cleanup } = (0, utils_1.createIsolatedTestEnv)('remix-test-app');
211
170
  (0, vitest_1.beforeAll)(async () => {
212
- await runWizardOnRemixProject(projectDir, integration, (projectDir) => {
171
+ wizardExitCode = await runWizardOnRemixProject(projectDir, integration, (projectDir) => {
213
172
  (0, utils_1.createFile)(`${projectDir}/server.mjs`, SERVER_TEMPLATE);
214
173
  (0, utils_1.modifyFile)(`${projectDir}/package.json`, {
215
174
  '"start": "remix-serve ./build/server/index.js"': '"start": "node ./server.mjs"',
@@ -218,12 +177,83 @@ function checkRemixProject(projectDir, integration, options) {
218
177
  });
219
178
  });
220
179
  (0, vitest_1.afterAll)(() => {
221
- (0, utils_1.revertLocalChanges)(projectDir);
222
- (0, utils_1.cleanupGit)(projectDir);
180
+ cleanup();
181
+ });
182
+ (0, vitest_1.test)('exits with exit code 0', () => {
183
+ (0, vitest_1.expect)(wizardExitCode).toBe(0);
184
+ });
185
+ (0, vitest_1.test)('package.json is updated correctly', () => {
186
+ (0, utils_1.checkPackageJson)(projectDir, '@sentry/remix');
187
+ });
188
+ (0, vitest_1.test)('.env-sentry-build-plugin is created and contains the auth token', () => {
189
+ (0, utils_1.checkEnvBuildPlugin)(projectDir);
190
+ });
191
+ (0, vitest_1.test)('example page exists', () => {
192
+ (0, utils_1.checkFileExists)(`${projectDir}/app/routes/sentry-example-page.tsx`);
193
+ });
194
+ (0, vitest_1.test)('instrumentation.server file exists', () => {
195
+ (0, utils_1.checkFileExists)(`${projectDir}/instrumentation.server.mjs`);
196
+ });
197
+ (0, vitest_1.test)('entry.client file contains Sentry initialization', () => {
198
+ (0, utils_1.checkFileContents)(`${projectDir}/app/entry.client.tsx`, [
199
+ 'import { init, replayIntegration, browserTracingIntegration } from "@sentry/remix";',
200
+ `init({
201
+ dsn: "${utils_1.TEST_ARGS.PROJECT_DSN}",
202
+ tracesSampleRate: 1,
203
+ enableLogs: true,
204
+
205
+ integrations: [browserTracingIntegration({
206
+ useEffect,
207
+ useLocation,
208
+ useMatches
209
+ }), replayIntegration({
210
+ maskAllText: true,
211
+ blockAllMedia: true
212
+ })],
213
+
214
+ replaysSessionSampleRate: 0.1,
215
+ replaysOnErrorSampleRate: 1,
216
+ sendDefaultPii: true
217
+ })`,
218
+ ]);
219
+ });
220
+ (0, vitest_1.test)('entry.server file contains Sentry code', () => {
221
+ (0, utils_1.checkFileContents)(`${projectDir}/app/entry.server.tsx`, [
222
+ 'import * as Sentry from "@sentry/remix";',
223
+ `export const handleError = Sentry.wrapHandleErrorWithSentry((error, { request }) => {
224
+ // Custom handleError implementation
225
+ });`,
226
+ ]);
227
+ });
228
+ (0, vitest_1.test)('instrumentation.server file contains Sentry initialization', () => {
229
+ (0, utils_1.checkFileContents)(`${projectDir}/instrumentation.server.mjs`, [
230
+ 'import * as Sentry from "@sentry/remix";',
231
+ `Sentry.init({
232
+ dsn: "${utils_1.TEST_ARGS.PROJECT_DSN}",
233
+ tracesSampleRate: 1,
234
+ enableLogs: true
235
+ })`,
236
+ ]);
237
+ });
238
+ (0, vitest_1.test)('root file contains Sentry ErrorBoundary and withSentry wrapper', () => {
239
+ (0, utils_1.checkFileContents)(`${projectDir}/app/root.tsx`, [
240
+ 'import { captureRemixErrorBoundaryError, withSentry } from "@sentry/remix";',
241
+ `export const ErrorBoundary = () => {
242
+ const error = useRouteError();
243
+ captureRemixErrorBoundaryError(error);
244
+ return <div>Something went wrong</div>;
245
+ };`,
246
+ `export default withSentry(App);`,
247
+ ]);
248
+ });
249
+ (0, vitest_1.test)('builds successfully', async () => {
250
+ await (0, utils_1.checkIfBuilds)(projectDir);
251
+ });
252
+ (0, vitest_1.test)('runs on dev mode correctly', async () => {
253
+ await (0, utils_1.checkIfRunsOnDevMode)(projectDir, 'Express server listening');
223
254
  });
224
- checkRemixProject(projectDir, integration, {
225
- devModeExpectedOutput: 'Express server listening',
226
- prodModeExpectedOutput: 'Express server listening',
255
+ (0, vitest_1.test)('runs on prod mode correctly', async () => {
256
+ await (0, utils_1.checkIfRunsOnProdMode)(projectDir, 'Express server listening');
227
257
  });
228
258
  (0, vitest_1.test)('server.mjs contains instrumentation file import', () => {
229
259
  (0, utils_1.checkFileContents)(`${projectDir}/server.mjs`, [
@@ -1 +1 @@
1
- {"version":3,"file":"remix.test.js","sourceRoot":"","sources":["../../../e2e-tests/tests/remix.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'node:path';\nimport { Integration } from '../../lib/Constants';\nimport {\n KEYS,\n TEST_ARGS,\n checkEnvBuildPlugin,\n checkFileContents,\n checkFileExists,\n checkIfBuilds,\n checkIfRunsOnDevMode,\n checkIfRunsOnProdMode,\n checkPackageJson,\n cleanupGit,\n createFile,\n modifyFile,\n revertLocalChanges,\n startWizardInstance,\n} from '../utils';\nimport { afterAll, beforeAll, describe, test } from 'vitest';\n\nconst SERVER_TEMPLATE = `import { createRequestHandler } from '@remix-run/express';\nimport { installGlobals } from '@remix-run/node';\nimport compression from 'compression';\nimport express from 'express';\nimport morgan from 'morgan';\n\ninstallGlobals();\n\nconst viteDevServer =\n process.env.NODE_ENV === 'production'\n ? undefined\n : await import('vite').then(vite =>\n vite.createServer({\n server: { middlewareMode: true },\n }),\n );\n\nconst app = express();\n\napp.use(compression());\napp.disable('x-powered-by');\n\nif (viteDevServer) {\n app.use(viteDevServer.middlewares);\n} else {\n app.use('/assets', express.static('build/client/assets', { immutable: true, maxAge: '1y' }));\n}\n\napp.use(express.static('build/client', { maxAge: '1h' }));\napp.use(morgan('tiny'));\n\napp.all(\n '*',\n createRequestHandler({\n build: viteDevServer\n ? () => viteDevServer.ssrLoadModule('virtual:remix/server-build')\n : await import('./build/server/index.js'),\n }),\n);\n\napp.listen(0, () => console.log('Express server listening'));\n`;\n\nasync function runWizardOnRemixProject(\n projectDir: string,\n integration: Integration,\n fileModificationFn?: (\n projectDir: string,\n integration: Integration,\n ) => unknown,\n) {\n const wizardInstance = startWizardInstance(integration, projectDir);\n let packageManagerPrompted = false;\n\n if (fileModificationFn) {\n fileModificationFn(projectDir, integration);\n\n await wizardInstance.waitForOutput('Do you want to continue anyway?');\n\n packageManagerPrompted = await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.ENTER],\n 'Please select your package manager.',\n );\n } else {\n packageManagerPrompted = await wizardInstance.waitForOutput(\n 'Please select your package manager.',\n );\n }\n\n const tracingOptionPrompted =\n packageManagerPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n // Selecting `yarn` as the package manager\n [KEYS.DOWN, KEYS.ENTER],\n // \"Do you want to enable Tracing\", sometimes doesn't work as `Tracing` can be printed in bold.\n 'to track the performance of your application?',\n {\n timeout: 240_000,\n },\n ));\n\n const replayOptionPrompted =\n tracingOptionPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.ENTER],\n // \"Do you want to enable Sentry Session Replay\", sometimes doesn't work as `Sentry Session Replay` can be printed in bold.\n 'to get a video-like reproduction of errors during a user session?',\n ));\n\n const logOptionPrompted =\n replayOptionPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.ENTER],\n // \"Do you want to enable Logs\", sometimes doesn't work as `Logs` can be printed in bold.\n 'to send your application logs to Sentry?',\n ));\n\n const examplePagePrompted =\n logOptionPrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.ENTER],\n 'Do you want to create an example page',\n {\n optional: true,\n },\n ));\n\n // After the example page prompt, we send ENTER to accept it\n // Then handle the MCP prompt that comes after\n const mcpPrompted =\n examplePagePrompted &&\n (await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.ENTER], // This ENTER is for accepting the example page\n 'Optionally add a project-scoped MCP server configuration for the Sentry MCP?',\n {\n optional: true,\n },\n ));\n\n // Decline MCP config (default is Yes, so press DOWN then ENTER to select No)\n if (mcpPrompted) {\n await wizardInstance.sendStdinAndWaitForOutput(\n [KEYS.DOWN, KEYS.ENTER],\n 'Sentry has been successfully configured for your Remix project',\n );\n } else {\n // If MCP wasn't prompted, wait for success message directly\n await wizardInstance.waitForOutput(\n 'Sentry has been successfully configured for your Remix project',\n );\n }\n\n wizardInstance.kill();\n}\n\nfunction checkRemixProject(\n projectDir: string,\n integration: Integration,\n options?: {\n devModeExpectedOutput?: string;\n prodModeExpectedOutput?: string;\n },\n) {\n test('package.json is updated correctly', () => {\n checkPackageJson(projectDir, integration);\n });\n\n test('.env-sentry-build-plugin is created and contains the auth token', () => {\n checkEnvBuildPlugin(projectDir);\n });\n\n test('example page exists', () => {\n checkFileExists(`${projectDir}/app/routes/sentry-example-page.tsx`);\n });\n\n test('instrumentation.server file exists', () => {\n checkFileExists(`${projectDir}/instrumentation.server.mjs`);\n });\n\n test('entry.client file contains Sentry initialization', () => {\n checkFileContents(`${projectDir}/app/entry.client.tsx`, [\n 'import { init, replayIntegration, browserTracingIntegration } from \"@sentry/remix\";',\n `init({\n dsn: \"${TEST_ARGS.PROJECT_DSN}\",\n tracesSampleRate: 1,\n enableLogs: true,\n\n integrations: [browserTracingIntegration({\n useEffect,\n useLocation,\n useMatches\n }), replayIntegration({\n maskAllText: true,\n blockAllMedia: true\n })],\n\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1,\n sendDefaultPii: true\n})`,\n ]);\n });\n\n test('entry.server file contains Sentry code', () => {\n checkFileContents(`${projectDir}/app/entry.server.tsx`, [\n 'import * as Sentry from \"@sentry/remix\";',\n `export const handleError = Sentry.wrapHandleErrorWithSentry((error, { request }) => {\n // Custom handleError implementation\n});`,\n ]);\n });\n\n test('instrumentation.server file contains Sentry initialization', () => {\n checkFileContents(`${projectDir}/instrumentation.server.mjs`, [\n 'import * as Sentry from \"@sentry/remix\";',\n `Sentry.init({\n dsn: \"${TEST_ARGS.PROJECT_DSN}\",\n tracesSampleRate: 1,\n enableLogs: true\n})`,\n ]);\n });\n\n test('root file contains Sentry ErrorBoundary and withSentry wrapper', () => {\n checkFileContents(`${projectDir}/app/root.tsx`, [\n 'import { captureRemixErrorBoundaryError, withSentry } from \"@sentry/remix\";',\n `export const ErrorBoundary = () => {\n const error = useRouteError();\n captureRemixErrorBoundaryError(error);\n return <div>Something went wrong</div>;\n};`,\n `export default withSentry(App);`,\n ]);\n });\n\n test('builds successfully', async () => {\n await checkIfBuilds(projectDir);\n });\n\n test('runs on dev mode correctly', async () => {\n await checkIfRunsOnDevMode(\n projectDir,\n options?.devModeExpectedOutput || 'to expose',\n );\n });\n\n test('runs on prod mode correctly', async () => {\n await checkIfRunsOnProdMode(\n projectDir,\n options?.prodModeExpectedOutput || '[remix-serve]',\n );\n });\n}\n\ndescribe('Remix', () => {\n describe('with empty project', () => {\n const integration = Integration.remix;\n const projectDir = path.resolve(\n __dirname,\n '../test-applications/remix-test-app',\n );\n\n beforeAll(async () => {\n await runWizardOnRemixProject(projectDir, integration);\n });\n\n afterAll(() => {\n revertLocalChanges(projectDir);\n cleanupGit(projectDir);\n });\n\n checkRemixProject(projectDir, integration);\n });\n\n describe('with existing custom Express server', () => {\n const integration = Integration.remix;\n const projectDir = path.resolve(\n __dirname,\n '../test-applications/remix-test-app',\n );\n\n beforeAll(async () => {\n await runWizardOnRemixProject(projectDir, integration, (projectDir) => {\n createFile(`${projectDir}/server.mjs`, SERVER_TEMPLATE);\n\n modifyFile(`${projectDir}/package.json`, {\n '\"start\": \"remix-serve ./build/server/index.js\"':\n '\"start\": \"node ./server.mjs\"',\n '\"dev\": \"remix vite:dev\"': '\"dev\": \"node ./server.mjs\"',\n });\n });\n });\n\n afterAll(() => {\n revertLocalChanges(projectDir);\n cleanupGit(projectDir);\n });\n\n checkRemixProject(projectDir, integration, {\n devModeExpectedOutput: 'Express server listening',\n prodModeExpectedOutput: 'Express server listening',\n });\n\n test('server.mjs contains instrumentation file import', () => {\n checkFileContents(`${projectDir}/server.mjs`, [\n \"import './instrumentation.server.mjs';\",\n ]);\n });\n });\n});\n"]}
1
+ {"version":3,"file":"remix.test.js","sourceRoot":"","sources":["../../../e2e-tests/tests/remix.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { Integration } from '../../lib/Constants';\nimport {\n TEST_ARGS,\n checkEnvBuildPlugin,\n checkFileContents,\n checkFileExists,\n checkIfBuilds,\n checkIfRunsOnDevMode,\n checkIfRunsOnProdMode,\n checkPackageJson,\n createFile,\n createIsolatedTestEnv,\n getWizardCommand,\n modifyFile,\n} from '../utils';\nimport { afterAll, beforeAll, describe, expect, test } from 'vitest';\n\n//@ts-expect-error - clifty is ESM only\nimport { KEYS, withEnv } from 'clifty';\n\nconst SERVER_TEMPLATE = `import { createRequestHandler } from '@remix-run/express';\nimport { installGlobals } from '@remix-run/node';\nimport compression from 'compression';\nimport express from 'express';\nimport morgan from 'morgan';\n\ninstallGlobals();\n\nconst viteDevServer =\n process.env.NODE_ENV === 'production'\n ? undefined\n : await import('vite').then(vite =>\n vite.createServer({\n server: { middlewareMode: true },\n }),\n );\n\nconst app = express();\n\napp.use(compression());\napp.disable('x-powered-by');\n\nif (viteDevServer) {\n app.use(viteDevServer.middlewares);\n} else {\n app.use('/assets', express.static('build/client/assets', { immutable: true, maxAge: '1y' }));\n}\n\napp.use(express.static('build/client', { maxAge: '1h' }));\napp.use(morgan('tiny'));\n\napp.all(\n '*',\n createRequestHandler({\n build: viteDevServer\n ? () => viteDevServer.ssrLoadModule('virtual:remix/server-build')\n : await import('./build/server/index.js'),\n }),\n);\n\napp.listen(0, () => console.log('Express server listening'));\n`;\n\nasync function runWizardOnRemixProject(\n projectDir: string,\n integration: Integration,\n fileModificationFn?: (\n projectDir: string,\n integration: Integration,\n ) => unknown,\n): Promise<number> {\n const wizardInteraction = withEnv({\n cwd: projectDir,\n }).defineInteraction();\n\n if (fileModificationFn) {\n fileModificationFn(projectDir, integration);\n\n wizardInteraction\n .whenAsked('Do you want to continue anyway?')\n .respondWith(KEYS.ENTER);\n }\n\n return wizardInteraction\n .whenAsked('Please select your package manager.')\n .respondWith(KEYS.DOWN, KEYS.ENTER)\n .whenAsked('to track the performance of your application?', {\n timeout: 240_000, // package installation can take a while in CI\n })\n .respondWith(KEYS.ENTER)\n .whenAsked(\n 'to get a video-like reproduction of errors during a user session?',\n )\n .respondWith(KEYS.ENTER)\n .whenAsked('to send your application logs to Sentry?')\n .respondWith(KEYS.ENTER)\n .whenAsked('Do you want to create an example page')\n .respondWith(KEYS.ENTER)\n .whenAsked(\n 'Optionally add a project-scoped MCP server configuration for the Sentry MCP?',\n )\n .respondWith(KEYS.DOWN, KEYS.ENTER)\n .expectOutput(\n 'Sentry has been successfully configured for your Remix project',\n )\n .run(getWizardCommand(integration));\n}\n\ndescribe('Remix', () => {\n describe('with empty project', () => {\n const integration = Integration.remix;\n let wizardExitCode: number;\n\n const { projectDir, cleanup } = createIsolatedTestEnv('remix-test-app');\n\n beforeAll(async () => {\n wizardExitCode = await runWizardOnRemixProject(projectDir, integration);\n });\n\n afterAll(() => {\n cleanup();\n });\n\n test('exits with exit code 0', () => {\n expect(wizardExitCode).toBe(0);\n });\n\n test('package.json is updated correctly', () => {\n checkPackageJson(projectDir, '@sentry/remix');\n });\n\n test('.env-sentry-build-plugin is created and contains the auth token', () => {\n checkEnvBuildPlugin(projectDir);\n });\n\n test('example page exists', () => {\n checkFileExists(`${projectDir}/app/routes/sentry-example-page.tsx`);\n });\n\n test('instrumentation.server file exists', () => {\n checkFileExists(`${projectDir}/instrumentation.server.mjs`);\n });\n\n test('entry.client file contains Sentry initialization', () => {\n checkFileContents(`${projectDir}/app/entry.client.tsx`, [\n 'import { init, replayIntegration, browserTracingIntegration } from \"@sentry/remix\";',\n `init({\n dsn: \"${TEST_ARGS.PROJECT_DSN}\",\n tracesSampleRate: 1,\n enableLogs: true,\n\n integrations: [browserTracingIntegration({\n useEffect,\n useLocation,\n useMatches\n }), replayIntegration({\n maskAllText: true,\n blockAllMedia: true\n })],\n\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1,\n sendDefaultPii: true\n})`,\n ]);\n });\n\n test('entry.server file contains Sentry code', () => {\n checkFileContents(`${projectDir}/app/entry.server.tsx`, [\n 'import * as Sentry from \"@sentry/remix\";',\n `export const handleError = Sentry.wrapHandleErrorWithSentry((error, { request }) => {\n // Custom handleError implementation\n});`,\n ]);\n });\n\n test('instrumentation.server file contains Sentry initialization', () => {\n checkFileContents(`${projectDir}/instrumentation.server.mjs`, [\n 'import * as Sentry from \"@sentry/remix\";',\n `Sentry.init({\n dsn: \"${TEST_ARGS.PROJECT_DSN}\",\n tracesSampleRate: 1,\n enableLogs: true\n})`,\n ]);\n });\n\n test('root file contains Sentry ErrorBoundary and withSentry wrapper', () => {\n checkFileContents(`${projectDir}/app/root.tsx`, [\n 'import { captureRemixErrorBoundaryError, withSentry } from \"@sentry/remix\";',\n `export const ErrorBoundary = () => {\n const error = useRouteError();\n captureRemixErrorBoundaryError(error);\n return <div>Something went wrong</div>;\n};`,\n `export default withSentry(App);`,\n ]);\n });\n\n test('builds successfully', async () => {\n await checkIfBuilds(projectDir);\n });\n\n test('runs on dev mode correctly', async () => {\n await checkIfRunsOnDevMode(projectDir, 'to expose');\n });\n\n test('runs on prod mode correctly', async () => {\n await checkIfRunsOnProdMode(projectDir, '[remix-serve]');\n });\n });\n\n describe('with existing custom Express server', () => {\n const integration = Integration.remix;\n let wizardExitCode: number;\n\n const { projectDir, cleanup } = createIsolatedTestEnv('remix-test-app');\n\n beforeAll(async () => {\n wizardExitCode = await runWizardOnRemixProject(\n projectDir,\n integration,\n (projectDir) => {\n createFile(`${projectDir}/server.mjs`, SERVER_TEMPLATE);\n\n modifyFile(`${projectDir}/package.json`, {\n '\"start\": \"remix-serve ./build/server/index.js\"':\n '\"start\": \"node ./server.mjs\"',\n '\"dev\": \"remix vite:dev\"': '\"dev\": \"node ./server.mjs\"',\n });\n },\n );\n });\n\n afterAll(() => {\n cleanup();\n });\n\n test('exits with exit code 0', () => {\n expect(wizardExitCode).toBe(0);\n });\n\n test('package.json is updated correctly', () => {\n checkPackageJson(projectDir, '@sentry/remix');\n });\n\n test('.env-sentry-build-plugin is created and contains the auth token', () => {\n checkEnvBuildPlugin(projectDir);\n });\n\n test('example page exists', () => {\n checkFileExists(`${projectDir}/app/routes/sentry-example-page.tsx`);\n });\n\n test('instrumentation.server file exists', () => {\n checkFileExists(`${projectDir}/instrumentation.server.mjs`);\n });\n\n test('entry.client file contains Sentry initialization', () => {\n checkFileContents(`${projectDir}/app/entry.client.tsx`, [\n 'import { init, replayIntegration, browserTracingIntegration } from \"@sentry/remix\";',\n `init({\n dsn: \"${TEST_ARGS.PROJECT_DSN}\",\n tracesSampleRate: 1,\n enableLogs: true,\n\n integrations: [browserTracingIntegration({\n useEffect,\n useLocation,\n useMatches\n }), replayIntegration({\n maskAllText: true,\n blockAllMedia: true\n })],\n\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1,\n sendDefaultPii: true\n})`,\n ]);\n });\n\n test('entry.server file contains Sentry code', () => {\n checkFileContents(`${projectDir}/app/entry.server.tsx`, [\n 'import * as Sentry from \"@sentry/remix\";',\n `export const handleError = Sentry.wrapHandleErrorWithSentry((error, { request }) => {\n // Custom handleError implementation\n});`,\n ]);\n });\n\n test('instrumentation.server file contains Sentry initialization', () => {\n checkFileContents(`${projectDir}/instrumentation.server.mjs`, [\n 'import * as Sentry from \"@sentry/remix\";',\n `Sentry.init({\n dsn: \"${TEST_ARGS.PROJECT_DSN}\",\n tracesSampleRate: 1,\n enableLogs: true\n})`,\n ]);\n });\n\n test('root file contains Sentry ErrorBoundary and withSentry wrapper', () => {\n checkFileContents(`${projectDir}/app/root.tsx`, [\n 'import { captureRemixErrorBoundaryError, withSentry } from \"@sentry/remix\";',\n `export const ErrorBoundary = () => {\n const error = useRouteError();\n captureRemixErrorBoundaryError(error);\n return <div>Something went wrong</div>;\n};`,\n `export default withSentry(App);`,\n ]);\n });\n\n test('builds successfully', async () => {\n await checkIfBuilds(projectDir);\n });\n\n test('runs on dev mode correctly', async () => {\n await checkIfRunsOnDevMode(projectDir, 'Express server listening');\n });\n\n test('runs on prod mode correctly', async () => {\n await checkIfRunsOnProdMode(projectDir, 'Express server listening');\n });\n\n test('server.mjs contains instrumentation file import', () => {\n checkFileContents(`${projectDir}/server.mjs`, [\n \"import './instrumentation.server.mjs';\",\n ]);\n });\n });\n});\n"]}