@sentry/wizard 6.11.0 → 6.13.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 (245) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/bin.js +16 -1
  3. package/dist/bin.js.map +1 -1
  4. package/dist/e2e-tests/tests/angular-17.test.js +3 -4
  5. package/dist/e2e-tests/tests/angular-17.test.js.map +1 -1
  6. package/dist/e2e-tests/tests/angular-19.test.js +3 -4
  7. package/dist/e2e-tests/tests/angular-19.test.js.map +1 -1
  8. package/dist/e2e-tests/tests/cloudflare-worker.test.js +5 -0
  9. package/dist/e2e-tests/tests/cloudflare-worker.test.js.map +1 -1
  10. package/dist/e2e-tests/tests/flutter.test.js +60 -0
  11. package/dist/e2e-tests/tests/flutter.test.js.map +1 -1
  12. package/dist/e2e-tests/tests/help-message.test.js +8 -3
  13. package/dist/e2e-tests/tests/help-message.test.js.map +1 -1
  14. package/dist/e2e-tests/tests/nuxt-3.test.js +12 -6
  15. package/dist/e2e-tests/tests/nuxt-3.test.js.map +1 -1
  16. package/dist/e2e-tests/tests/nuxt-4.test.js +12 -6
  17. package/dist/e2e-tests/tests/nuxt-4.test.js.map +1 -1
  18. package/dist/e2e-tests/tests/pnpm-workspace.test.js +8 -4
  19. package/dist/e2e-tests/tests/pnpm-workspace.test.js.map +1 -1
  20. package/dist/e2e-tests/tests/react-router-instrumentation-api.test.js +96 -0
  21. package/dist/e2e-tests/tests/react-router-instrumentation-api.test.js.map +1 -0
  22. package/dist/e2e-tests/tests/react-router.test.js +6 -7
  23. package/dist/e2e-tests/tests/react-router.test.js.map +1 -1
  24. package/dist/e2e-tests/tests/remix.test.js +2 -4
  25. package/dist/e2e-tests/tests/remix.test.js.map +1 -1
  26. package/dist/e2e-tests/tests/sveltekit-hooks.test.js +24 -8
  27. package/dist/e2e-tests/tests/sveltekit-hooks.test.js.map +1 -1
  28. package/dist/e2e-tests/tests/sveltekit-tracing.test.js +8 -4
  29. package/dist/e2e-tests/tests/sveltekit-tracing.test.js.map +1 -1
  30. package/dist/lib/Constants.d.ts +1 -0
  31. package/dist/lib/Constants.js +5 -0
  32. package/dist/lib/Constants.js.map +1 -1
  33. package/dist/lib/Steps/Integrations/Electron.js +2 -2
  34. package/dist/lib/Steps/Integrations/Electron.js.map +1 -1
  35. package/dist/src/android/android-wizard.js +3 -0
  36. package/dist/src/android/android-wizard.js.map +1 -1
  37. package/dist/src/angular/codemods/main.d.ts +1 -1
  38. package/dist/src/angular/codemods/main.js +0 -1
  39. package/dist/src/angular/codemods/main.js.map +1 -1
  40. package/dist/src/apple/apple-wizard.js +2 -3
  41. package/dist/src/apple/apple-wizard.js.map +1 -1
  42. package/dist/src/apple/check-installed-cli.d.ts +1 -1
  43. package/dist/src/apple/check-installed-cli.js +13 -7
  44. package/dist/src/apple/check-installed-cli.js.map +1 -1
  45. package/dist/src/apple/code-tools.js +17 -3
  46. package/dist/src/apple/code-tools.js.map +1 -1
  47. package/dist/src/apple/configure-package-manager.js +18 -5
  48. package/dist/src/apple/configure-package-manager.js.map +1 -1
  49. package/dist/src/apple/configure-xcode-project.js +8 -1
  50. package/dist/src/apple/configure-xcode-project.js.map +1 -1
  51. package/dist/src/apple/lookup-xcode-project.d.ts +8 -5
  52. package/dist/src/apple/lookup-xcode-project.js +22 -17
  53. package/dist/src/apple/lookup-xcode-project.js.map +1 -1
  54. package/dist/src/apple/options.d.ts +5 -0
  55. package/dist/src/apple/options.js.map +1 -1
  56. package/dist/src/apple/sentry-swift-package.d.ts +4 -0
  57. package/dist/src/apple/sentry-swift-package.js +17 -0
  58. package/dist/src/apple/sentry-swift-package.js.map +1 -0
  59. package/dist/src/apple/snapshots/apple-snapshots-wizard.d.ts +2 -0
  60. package/dist/src/apple/snapshots/apple-snapshots-wizard.js +251 -0
  61. package/dist/src/apple/snapshots/apple-snapshots-wizard.js.map +1 -0
  62. package/dist/src/apple/snapshots/configure-snapshotpreviews-xcode-project.d.ts +13 -0
  63. package/dist/src/apple/snapshots/configure-snapshotpreviews-xcode-project.js +48 -0
  64. package/dist/src/apple/snapshots/configure-snapshotpreviews-xcode-project.js.map +1 -0
  65. package/dist/src/apple/snapshots/snapshot-test-file.d.ts +18 -0
  66. package/dist/src/apple/snapshots/snapshot-test-file.js +122 -0
  67. package/dist/src/apple/snapshots/snapshot-test-file.js.map +1 -0
  68. package/dist/src/apple/snapshots/snapshot-verification-scheme.d.ts +6 -0
  69. package/dist/src/apple/snapshots/snapshot-verification-scheme.js +147 -0
  70. package/dist/src/apple/snapshots/snapshot-verification-scheme.js.map +1 -0
  71. package/dist/src/apple/snapshots/snapshotpreviews-package.d.ts +4 -0
  72. package/dist/src/apple/snapshots/snapshotpreviews-package.js +8 -0
  73. package/dist/src/apple/snapshots/snapshotpreviews-package.js.map +1 -0
  74. package/dist/src/apple/snapshots/snapshots-cli-preflight.d.ts +23 -0
  75. package/dist/src/apple/snapshots/snapshots-cli-preflight.js +136 -0
  76. package/dist/src/apple/snapshots/snapshots-cli-preflight.js.map +1 -0
  77. package/dist/src/apple/xcode-manager.d.ts +59 -1
  78. package/dist/src/apple/xcode-manager.js +507 -106
  79. package/dist/src/apple/xcode-manager.js.map +1 -1
  80. package/dist/src/cloudflare/cloudflare-wizard.js +5 -0
  81. package/dist/src/cloudflare/cloudflare-wizard.js.map +1 -1
  82. package/dist/src/cloudflare/sdk-setup.d.ts +1 -0
  83. package/dist/src/cloudflare/sdk-setup.js.map +1 -1
  84. package/dist/src/cloudflare/templates.d.ts +1 -0
  85. package/dist/src/cloudflare/templates.js +7 -1
  86. package/dist/src/cloudflare/templates.js.map +1 -1
  87. package/dist/src/cloudflare/wrap-worker.d.ts +1 -0
  88. package/dist/src/cloudflare/wrap-worker.js +7 -0
  89. package/dist/src/cloudflare/wrap-worker.js.map +1 -1
  90. package/dist/src/flutter/flutter-wizard.js +3 -0
  91. package/dist/src/flutter/flutter-wizard.js.map +1 -1
  92. package/dist/src/nextjs/templates.js +12 -6
  93. package/dist/src/nextjs/templates.js.map +1 -1
  94. package/dist/src/nuxt/templates.js +12 -6
  95. package/dist/src/nuxt/templates.js.map +1 -1
  96. package/dist/src/react-native/expo.d.ts +6 -0
  97. package/dist/src/react-native/expo.js +27 -1
  98. package/dist/src/react-native/expo.js.map +1 -1
  99. package/dist/src/react-native/git.d.ts +5 -0
  100. package/dist/src/react-native/git.js +32 -1
  101. package/dist/src/react-native/git.js.map +1 -1
  102. package/dist/src/react-native/javascript.js +3 -1
  103. package/dist/src/react-native/javascript.js.map +1 -1
  104. package/dist/src/react-native/react-native-wizard.js +12 -6
  105. package/dist/src/react-native/react-native-wizard.js.map +1 -1
  106. package/dist/src/react-router/codemods/client.entry.d.ts +1 -1
  107. package/dist/src/react-router/codemods/client.entry.js +124 -26
  108. package/dist/src/react-router/codemods/client.entry.js.map +1 -1
  109. package/dist/src/react-router/codemods/react-router-config.js +1 -1
  110. package/dist/src/react-router/codemods/react-router-config.js.map +1 -1
  111. package/dist/src/react-router/codemods/server-entry.d.ts +1 -1
  112. package/dist/src/react-router/codemods/server-entry.js +40 -4
  113. package/dist/src/react-router/codemods/server-entry.js.map +1 -1
  114. package/dist/src/react-router/codemods/vite.js +46 -1
  115. package/dist/src/react-router/codemods/vite.js.map +1 -1
  116. package/dist/src/react-router/react-router-wizard.js +62 -21
  117. package/dist/src/react-router/react-router-wizard.js.map +1 -1
  118. package/dist/src/react-router/sdk-setup.d.ts +5 -3
  119. package/dist/src/react-router/sdk-setup.js +44 -16
  120. package/dist/src/react-router/sdk-setup.js.map +1 -1
  121. package/dist/src/react-router/templates.d.ts +2 -4
  122. package/dist/src/react-router/templates.js +89 -87
  123. package/dist/src/react-router/templates.js.map +1 -1
  124. package/dist/src/remix/sdk-setup.js +1 -2
  125. package/dist/src/remix/sdk-setup.js.map +1 -1
  126. package/dist/src/run.d.ts +4 -1
  127. package/dist/src/run.js +13 -0
  128. package/dist/src/run.js.map +1 -1
  129. package/dist/src/sourcemaps/tools/remix.js +4 -4
  130. package/dist/src/sourcemaps/tools/remix.js.map +1 -1
  131. package/dist/src/sourcemaps/tools/vite.js +1 -1
  132. package/dist/src/sourcemaps/tools/vite.js.map +1 -1
  133. package/dist/src/sveltekit/sdk-setup/setup.js +17 -4
  134. package/dist/src/sveltekit/sdk-setup/setup.js.map +1 -1
  135. package/dist/src/sveltekit/sdk-setup/vite.js +1 -1
  136. package/dist/src/sveltekit/sdk-setup/vite.js.map +1 -1
  137. package/dist/src/sveltekit/templates.js +12 -6
  138. package/dist/src/sveltekit/templates.js.map +1 -1
  139. package/dist/src/utils/ast-utils.d.ts +10 -0
  140. package/dist/src/utils/ast-utils.js +19 -1
  141. package/dist/src/utils/ast-utils.js.map +1 -1
  142. package/dist/src/utils/clack/index.d.ts +2 -1
  143. package/dist/src/utils/clack/index.js +17 -6
  144. package/dist/src/utils/clack/index.js.map +1 -1
  145. package/dist/src/utils/files.d.ts +2 -0
  146. package/dist/src/utils/files.js +58 -0
  147. package/dist/src/utils/files.js.map +1 -0
  148. package/dist/src/utils/git.d.ts +3 -1
  149. package/dist/src/utils/git.js +2 -1
  150. package/dist/src/utils/git.js.map +1 -1
  151. package/dist/src/utils/line-endings.d.ts +1 -0
  152. package/dist/src/utils/line-endings.js +76 -0
  153. package/dist/src/utils/line-endings.js.map +1 -0
  154. package/dist/src/version.d.ts +1 -1
  155. package/dist/src/version.js +1 -1
  156. package/dist/src/version.js.map +1 -1
  157. package/dist/test/angular/angular-wizard.test.js +0 -5
  158. package/dist/test/angular/angular-wizard.test.js.map +1 -1
  159. package/dist/test/apple/code-tools.test.js +78 -0
  160. package/dist/test/apple/code-tools.test.js.map +1 -1
  161. package/dist/test/apple/configure-package-manager.test.d.ts +1 -0
  162. package/dist/test/apple/configure-package-manager.test.js +161 -0
  163. package/dist/test/apple/configure-package-manager.test.js.map +1 -0
  164. package/dist/test/apple/lookup-xcode-project.test.d.ts +1 -0
  165. package/dist/test/apple/lookup-xcode-project.test.js +167 -0
  166. package/dist/test/apple/lookup-xcode-project.test.js.map +1 -0
  167. package/dist/test/apple/snapshots/apple-snapshots-wizard.test.d.ts +1 -0
  168. package/dist/test/apple/snapshots/apple-snapshots-wizard.test.js +487 -0
  169. package/dist/test/apple/snapshots/apple-snapshots-wizard.test.js.map +1 -0
  170. package/dist/test/apple/snapshots/hosted-test-target-fixture.d.ts +24 -0
  171. package/dist/test/apple/snapshots/hosted-test-target-fixture.js +191 -0
  172. package/dist/test/apple/snapshots/hosted-test-target-fixture.js.map +1 -0
  173. package/dist/test/apple/snapshots/snapshot-test-file.test.d.ts +1 -0
  174. package/dist/test/apple/snapshots/snapshot-test-file.test.js +110 -0
  175. package/dist/test/apple/snapshots/snapshot-test-file.test.js.map +1 -0
  176. package/dist/test/apple/snapshots/snapshot-verification-scheme.test.d.ts +1 -0
  177. package/dist/test/apple/snapshots/snapshot-verification-scheme.test.js +146 -0
  178. package/dist/test/apple/snapshots/snapshot-verification-scheme.test.js.map +1 -0
  179. package/dist/test/apple/snapshots/snapshotpreviews-xcode-smoke.test.d.ts +1 -0
  180. package/dist/test/apple/snapshots/snapshotpreviews-xcode-smoke.test.js +186 -0
  181. package/dist/test/apple/snapshots/snapshotpreviews-xcode-smoke.test.js.map +1 -0
  182. package/dist/test/apple/snapshots/snapshots-cli-preflight.test.d.ts +1 -0
  183. package/dist/test/apple/snapshots/snapshots-cli-preflight.test.js +192 -0
  184. package/dist/test/apple/snapshots/snapshots-cli-preflight.test.js.map +1 -0
  185. package/dist/test/apple/snapshots/source-file-insertion.test.d.ts +1 -0
  186. package/dist/test/apple/snapshots/source-file-insertion.test.js +77 -0
  187. package/dist/test/apple/snapshots/source-file-insertion.test.js.map +1 -0
  188. package/dist/test/apple/xcode-manager.test.js +452 -43
  189. package/dist/test/apple/xcode-manager.test.js.map +1 -1
  190. package/dist/test/cloudflare/sdk-setup.test.js +20 -2
  191. package/dist/test/cloudflare/sdk-setup.test.js.map +1 -1
  192. package/dist/test/cloudflare/templates.test.js +54 -0
  193. package/dist/test/cloudflare/templates.test.js.map +1 -1
  194. package/dist/test/cloudflare/wrap-worker.test.js +74 -11
  195. package/dist/test/cloudflare/wrap-worker.test.js.map +1 -1
  196. package/dist/test/constants.test.d.ts +1 -0
  197. package/dist/test/constants.test.js +12 -0
  198. package/dist/test/constants.test.js.map +1 -0
  199. package/dist/test/nextjs/templates.test.js +66 -33
  200. package/dist/test/nextjs/templates.test.js.map +1 -1
  201. package/dist/test/nuxt/templates.test.js +66 -36
  202. package/dist/test/nuxt/templates.test.js.map +1 -1
  203. package/dist/test/react-native/expo.test.js +140 -0
  204. package/dist/test/react-native/expo.test.js.map +1 -1
  205. package/dist/test/react-native/git.test.d.ts +1 -0
  206. package/dist/test/react-native/git.test.js +160 -0
  207. package/dist/test/react-native/git.test.js.map +1 -0
  208. package/dist/test/react-router/codemods/client-entry.test.js +38 -5
  209. package/dist/test/react-router/codemods/client-entry.test.js.map +1 -1
  210. package/dist/test/react-router/codemods/server-entry.test.js +83 -0
  211. package/dist/test/react-router/codemods/server-entry.test.js.map +1 -1
  212. package/dist/test/react-router/codemods/vite.test.js +89 -0
  213. package/dist/test/react-router/codemods/vite.test.js.map +1 -1
  214. package/dist/test/react-router/sdk-setup.test.js +98 -6
  215. package/dist/test/react-router/sdk-setup.test.js.map +1 -1
  216. package/dist/test/react-router/templates.test.js +50 -38
  217. package/dist/test/react-router/templates.test.js.map +1 -1
  218. package/dist/test/remix/build-script.test.d.ts +1 -0
  219. package/dist/test/remix/build-script.test.js +124 -0
  220. package/dist/test/remix/build-script.test.js.map +1 -0
  221. package/dist/test/remix/client-entry.test.js +4 -10
  222. package/dist/test/remix/client-entry.test.js.map +1 -1
  223. package/dist/test/run.test.d.ts +1 -0
  224. package/dist/test/run.test.js +137 -0
  225. package/dist/test/run.test.js.map +1 -0
  226. package/dist/test/sourcemaps/tools/vite.test.js +12 -8
  227. package/dist/test/sourcemaps/tools/vite.test.js.map +1 -1
  228. package/dist/test/sveltekit/templates.test.js +78 -27
  229. package/dist/test/sveltekit/templates.test.js.map +1 -1
  230. package/dist/test/utils/ast-utils.test.js +22 -0
  231. package/dist/test/utils/ast-utils.test.js.map +1 -1
  232. package/dist/test/utils/clack/index.test.js +101 -0
  233. package/dist/test/utils/clack/index.test.js.map +1 -1
  234. package/dist/test/utils/git.test.js +10 -0
  235. package/dist/test/utils/git.test.js.map +1 -1
  236. package/dist/test/utils/line-endings.test.d.ts +1 -0
  237. package/dist/test/utils/line-endings.test.js +103 -0
  238. package/dist/test/utils/line-endings.test.js.map +1 -0
  239. package/package.json +2 -2
  240. package/dist/src/react-router/codemods/root.d.ts +0 -1
  241. package/dist/src/react-router/codemods/root.js +0 -171
  242. package/dist/src/react-router/codemods/root.js.map +0 -1
  243. package/dist/test/react-router/codemods/root.test.js +0 -178
  244. package/dist/test/react-router/codemods/root.test.js.map +0 -1
  245. /package/dist/{test/react-router/codemods/root.test.d.ts → e2e-tests/tests/react-router-instrumentation-api.test.d.ts} +0 -0
@@ -80,6 +80,8 @@ vitest_1.vi.mock('../../../src/utils/debug', () => ({
80
80
  const lines = modifiedContent.split('\n');
81
81
  const sentryImportLine = lines.findIndex((line) => line.includes('import * as Sentry from "@sentry/react-router";'));
82
82
  (0, vitest_1.expect)(sentryImportLine).toBeGreaterThanOrEqual(0);
83
+ // Should make handleRequest async
84
+ (0, vitest_1.expect)(modifiedContent).toMatch(/async function handleRequest/);
83
85
  // Should create default handleError since none exists
84
86
  (0, vitest_1.expect)(modifiedContent).toContain('export const handleError = Sentry.createSentryHandleError({');
85
87
  (0, vitest_1.expect)(modifiedContent).toContain('logErrors: false');
@@ -111,6 +113,24 @@ vitest_1.vi.mock('../../../src/utils/debug', () => ({
111
113
  // Should preserve the variable export pattern
112
114
  (0, vitest_1.expect)(modifiedContent).toContain('export const handleError');
113
115
  });
116
+ (0, vitest_1.it)('should not add duplicate async keyword when handleRequest is already async', async () => {
117
+ const asyncContent = `
118
+ import { ServerRouter } from 'react-router';
119
+ import { renderToString } from 'react-dom/server';
120
+
121
+ export default async function handleRequest(request: Request) {
122
+ const html = renderToString(<ServerRouter />);
123
+ return new Response(html);
124
+ }
125
+ `;
126
+ fs.writeFileSync(tmpFile, asyncContent);
127
+ await (0, server_entry_1.instrumentServerEntry)(tmpFile);
128
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
129
+ // Should have async function handleRequest (not async async)
130
+ (0, vitest_1.expect)(modifiedContent).toMatch(/async function handleRequest/);
131
+ (0, vitest_1.expect)(modifiedContent).not.toMatch(/async\s+async/);
132
+ (0, vitest_1.expect)(modifiedContent).toContain('export default Sentry.wrapSentryHandleRequest(handleRequest);');
133
+ });
114
134
  });
115
135
  (0, vitest_1.describe)('instrumentHandleRequest', () => {
116
136
  let tmpDir;
@@ -412,4 +432,67 @@ export function handleError(error: unknown) {
412
432
  (0, vitest_1.expect)(thrownError).toBeNull();
413
433
  });
414
434
  });
435
+ (0, vitest_1.describe)('Instrumentation API', () => {
436
+ const fixturesDir = path.join(__dirname, 'fixtures', 'server-entry');
437
+ let tmpDir;
438
+ let tmpFile;
439
+ (0, vitest_1.beforeEach)(() => {
440
+ vitest_1.vi.clearAllMocks();
441
+ tmpDir = path.join(__dirname, 'fixtures', 'tmp', `test-instrumentation-api-${Date.now()}-${Math.random()
442
+ .toString(36)
443
+ .substring(2, 11)}`);
444
+ tmpFile = path.join(tmpDir, 'entry.server.tsx');
445
+ fs.mkdirSync(tmpDir, { recursive: true });
446
+ });
447
+ (0, vitest_1.afterEach)(() => {
448
+ if (fs.existsSync(tmpDir)) {
449
+ fs.rmSync(tmpDir, { recursive: true });
450
+ }
451
+ });
452
+ (0, vitest_1.it)('should add instrumentations export when useInstrumentationAPI is true', async () => {
453
+ const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
454
+ fs.writeFileSync(tmpFile, basicContent);
455
+ await (0, server_entry_1.instrumentServerEntry)(tmpFile, true);
456
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
457
+ (0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
458
+ (0, vitest_1.expect)(modifiedContent).toContain('export const instrumentations = [Sentry.createSentryServerInstrumentation()];');
459
+ });
460
+ (0, vitest_1.it)('should not add instrumentations export when useInstrumentationAPI is false', async () => {
461
+ const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
462
+ fs.writeFileSync(tmpFile, basicContent);
463
+ await (0, server_entry_1.instrumentServerEntry)(tmpFile, false);
464
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
465
+ (0, vitest_1.expect)(modifiedContent).not.toContain('instrumentations');
466
+ (0, vitest_1.expect)(modifiedContent).not.toContain('createSentryServerInstrumentation');
467
+ });
468
+ (0, vitest_1.it)('should not duplicate instrumentations export if already present', async () => {
469
+ const contentWithInstrumentations = `
470
+ import { ServerRouter } from 'react-router';
471
+ import * as Sentry from '@sentry/react-router';
472
+
473
+ export default function handleRequest() {}
474
+ export const handleError = () => {};
475
+ export const instrumentations = [Sentry.createSentryServerInstrumentation()];
476
+ `;
477
+ fs.writeFileSync(tmpFile, contentWithInstrumentations);
478
+ await (0, server_entry_1.instrumentServerEntry)(tmpFile, true);
479
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
480
+ const count = (modifiedContent.match(/\binstrumentations\b/g) || []).length;
481
+ (0, vitest_1.expect)(count).toBe(1);
482
+ });
483
+ (0, vitest_1.it)('should not duplicate if legacy unstable_instrumentations export is already present', async () => {
484
+ const contentWithLegacy = `
485
+ import { ServerRouter } from 'react-router';
486
+ import * as Sentry from '@sentry/react-router';
487
+
488
+ export default function handleRequest() {}
489
+ export const handleError = () => {};
490
+ export const unstable_instrumentations = [Sentry.createSentryServerInstrumentation()];
491
+ `;
492
+ fs.writeFileSync(tmpFile, contentWithLegacy);
493
+ await (0, server_entry_1.instrumentServerEntry)(tmpFile, true);
494
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
495
+ (0, vitest_1.expect)(modifiedContent).not.toContain('export const instrumentations =');
496
+ });
497
+ });
415
498
  //# sourceMappingURL=server-entry.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-entry.test.js","sourceRoot":"","sources":["../../../../test/react-router/codemods/server-entry.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as recast from 'recast';\nimport {\n instrumentServerEntry,\n instrumentHandleRequest,\n instrumentHandleError,\n} from '../../../src/react-router/codemods/server-entry';\n\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport { loadFile, generateCode } from 'magicast';\n\nvi.mock('@clack/prompts', () => {\n const mock = {\n log: {\n warn: vi.fn(),\n info: vi.fn(),\n success: vi.fn(),\n },\n };\n return {\n default: mock,\n ...mock,\n };\n});\n\nvi.mock('../../../src/utils/debug', () => ({\n debug: vi.fn(),\n}));\n\ndescribe('instrumentServerEntry', () => {\n const fixturesDir = path.join(__dirname, 'fixtures', 'server-entry');\n let tmpDir: string;\n let tmpFile: string;\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n // Create unique tmp directory for each test\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n tmpFile = path.join(tmpDir, 'entry.server.tsx');\n\n // Ensure tmp directory exists\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n // Clean up tmp directory\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should add Sentry import and wrap handleRequest function', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentServerEntry(tmpFile);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Should add Sentry import\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n\n // Should wrap the existing handleRequest function\n expect(modifiedContent).toContain(\n 'export default Sentry.wrapSentryHandleRequest(handleRequest);',\n );\n\n // Should add the Sentry import at the top of the file (after existing imports)\n const lines = modifiedContent.split('\\n');\n const sentryImportLine = lines.findIndex((line) =>\n line.includes('import * as Sentry from \"@sentry/react-router\";'),\n );\n expect(sentryImportLine).toBeGreaterThanOrEqual(0);\n\n // Should create default handleError since none exists\n expect(modifiedContent).toContain(\n 'export const handleError = Sentry.createSentryHandleError({',\n );\n expect(modifiedContent).toContain('logErrors: false');\n });\n\n it('should handle already instrumented server entry without duplication', async () => {\n const alreadyInstrumentedContent = fs.readFileSync(\n path.join(fixturesDir, 'already-instrumented.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, alreadyInstrumentedContent);\n\n await instrumentServerEntry(tmpFile);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Should not add duplicate imports or wrapping since already instrumented\n expect(modifiedContent).toContain(\n \"import * as Sentry from '@sentry/react-router';\",\n );\n expect(modifiedContent).toContain(\n 'export default Sentry.wrapSentryHandleRequest(handleRequest);',\n );\n\n // Should NOT add a new createSentryHandleError export since handleError already has captureException\n expect(modifiedContent).not.toContain(\n 'export const handleError = Sentry.createSentryHandleError({',\n );\n\n // Should preserve the existing handleError function with captureException\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n expect(modifiedContent).toContain('export async function handleError');\n });\n\n it('should handle variable export pattern with existing export', async () => {\n const variableExportContent = fs.readFileSync(\n path.join(fixturesDir, 'variable-export.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, variableExportContent);\n\n await instrumentServerEntry(tmpFile);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Should add Sentry import and wrap handleRequest\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain(\n 'export default Sentry.wrapSentryHandleRequest(handleRequest);',\n );\n\n // Should instrument the existing handleError variable with captureException\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n\n // Should preserve the variable export pattern\n expect(modifiedContent).toContain('export const handleError');\n });\n});\n\ndescribe('instrumentHandleRequest', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `handle-request-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should add required imports when creating new handleRequest', async () => {\n const content = `// Empty server entry file`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n instrumentHandleRequest(mod);\n\n // Check if required imports were added\n const imports = mod.imports.$items;\n const hasServerRouter = imports.some(\n (item: any) =>\n item.imported === 'ServerRouter' && item.from === 'react-router',\n );\n const hasRenderToPipeableStream = imports.some(\n (item: any) =>\n item.imported === 'renderToPipeableStream' &&\n item.from === 'react-dom/server',\n );\n\n expect(hasServerRouter).toBe(true);\n expect(hasRenderToPipeableStream).toBe(true);\n });\n\n it('should not duplicate imports if they already exist', async () => {\n const content = `\nimport { ServerRouter } from 'react-router';\nimport { renderToPipeableStream } from 'react-dom/server';\nimport { createReadableStreamFromReadable } from '@react-router/node';\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n const originalImportsCount = mod.imports.$items.length;\n\n instrumentHandleRequest(mod);\n\n // Should not add duplicate imports\n expect(mod.imports.$items.length).toBe(originalImportsCount);\n });\n});\n\ndescribe('instrumentHandleError', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `handle-error-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should not modify existing handleError with captureException', async () => {\n const content = `\nexport function handleError(error: unknown) {\n Sentry.captureException(error);\n console.error(error);\n}\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n const originalBodyLength = (mod.$ast as any).body.length;\n\n instrumentHandleError(mod);\n\n // Should not modify since captureException already exists\n expect((mod.$ast as any).body.length).toBe(originalBodyLength);\n });\n\n it('should not modify existing handleError with createSentryHandleError', async () => {\n const content = `\nexport const handleError = Sentry.createSentryHandleError({\n logErrors: false\n});\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const originalBodyLength = (mod.$ast as any).body.length;\n\n instrumentHandleError(mod);\n\n // Should not modify since createSentryHandleError already exists\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n expect((mod.$ast as any).body.length).toBe(originalBodyLength);\n });\n\n it('should add captureException to existing handleError function declaration without breaking AST', async () => {\n const content = `\nexport function handleError(error: unknown) {\n console.error('Custom error handling:', error);\n // some other logic here\n}\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This should not throw an error due to broken AST manipulation\n expect(() => instrumentHandleError(mod)).not.toThrow();\n\n // Verify the function was modified correctly\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n expect(modifiedCode).toContain(\n \"console.error('Custom error handling:', error)\",\n );\n });\n\n it('should add captureException to existing handleError variable declaration without breaking AST', async () => {\n const content = `\nexport const handleError = (error: unknown, { request }: { request: Request }) => {\n console.log('Handling error:', error.message);\n return new Response('Error occurred', { status: 500 });\n};\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This should not throw an error due to broken AST manipulation\n expect(() => instrumentHandleError(mod)).not.toThrow();\n\n // Verify the function was modified correctly\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n expect(modifiedCode).toContain(\n \"console.log('Handling error:', error.message)\",\n );\n });\n\n it('should handle existing handleError with only error parameter and add request parameter', async () => {\n const content = `\nexport const handleError = (error: unknown) => {\n console.error('Simple error handler:', error);\n};\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This should not throw an error due to broken AST manipulation\n expect(() => instrumentHandleError(mod)).not.toThrow();\n\n // Verify the function signature was updated correctly\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n expect(modifiedCode).toContain('if (!request.signal.aborted)');\n // Should add request parameter\n expect(modifiedCode).toMatch(\n /handleError.*=.*\\(\\s*error.*,\\s*\\{\\s*request\\s*\\}/,\n );\n });\n});\n\ndescribe('instrumentHandleError AST manipulation edge cases', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `ast-edge-cases-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should handle function declaration with existing try-catch block', async () => {\n const content = `\nexport function handleError(error: unknown, { request }: { request: Request }) {\n try {\n console.error('Error occurred:', error);\n logToExternalService(error);\n } catch (loggingError) {\n console.warn('Failed to log error:', loggingError);\n }\n}\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This test will expose the broken AST logic\n expect(() => instrumentHandleError(mod)).not.toThrow();\n\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n expect(modifiedCode).toContain('if (!request.signal.aborted)');\n // Should preserve existing try-catch\n expect(modifiedCode).toContain('try {');\n expect(modifiedCode).toContain('} catch (loggingError) {');\n });\n\n it('should handle arrow function with block body', async () => {\n const content = `\nexport const handleError = (error: unknown, context: any) => {\n const { request } = context;\n console.error('Error in route:', error);\n return new Response('Internal Server Error', { status: 500 });\n};\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This test will expose the broken AST logic\n expect(() => instrumentHandleError(mod)).not.toThrow();\n\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n expect(modifiedCode).toContain('if (!request.signal.aborted)');\n });\n\n it('should demonstrate that the AST bug is now fixed - no longer throws TypeError', async () => {\n const content = `\nexport function handleError(error: unknown) {\n console.error('Error occurred:', error);\n}\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This test specifically targets the broken AST logic at lines 279-284 in server-entry.ts\n // The bug is in this code:\n // implementation.declarations[0].init.arguments[0].body.body.unshift(...)\n // Where 'implementation' is an IfStatement, not a VariableDeclaration\n\n let thrownError: Error | null = null;\n try {\n instrumentHandleError(mod);\n } catch (error) {\n thrownError = error as Error;\n }\n\n // The bug is fixed - no error should be thrown\n expect(thrownError).toBeNull();\n\n // And the code should be successfully modified\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n\n // The error occurs because recast.parse() creates an IfStatement:\n // { type: 'IfStatement', test: ..., consequent: ... }\n // But the code tries to access .declarations[0] as if it were a VariableDeclaration\n });\n\n it('should demonstrate the specific line that breaks - recast.parse creates IfStatement not VariableDeclaration', () => {\n // This test shows exactly what the problematic line 278 in server-entry.ts creates\n const problematicCode = `if (!request.signal.aborted) {\n Sentry.captureException(error);\n}`;\n\n // This is what line 278 does: recast.parse(problematicCode).program.body[0]\n const implementation = recast.parse(problematicCode).program.body[0];\n\n // The implementation is an IfStatement, not a VariableDeclaration\n expect(implementation.type).toBe('IfStatement');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-assertion\n expect((implementation as any).declarations).toBeUndefined();\n\n // But lines 279-284 try to access implementation.declarations[0].init.arguments[0].body.body\n // This will throw \"Cannot read properties of undefined (reading '0')\"\n expect(() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unnecessary-type-assertion\n const declarations = (implementation as any).declarations;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return declarations[0]; // This line will throw the error\n }).toThrow('Cannot read properties of undefined');\n });\n});\n\n// Test for Bug #1: Array access vulnerability\ndescribe('Array access vulnerability bugs', () => {\n let tmpDir: string;\n let tmpFile: string;\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n // Create unique tmp directory for each test\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n tmpFile = path.join(tmpDir, 'entry.server.tsx');\n\n // Ensure tmp directory exists\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n // Clean up tmp directory\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n }\n });\n\n it('should safely handle VariableDeclaration with empty declarations array', () => {\n // This test verifies that the bug fix works correctly\n // Previously this would crash, but now it handles empty arrays safely\n\n // The implementation now includes proper safety checks, so we test that\n // it can handle edge cases without crashing\n\n // Test the actual safe implementation behavior\n const testResult = () => {\n // Simulate the safe check logic from the actual implementation\n const declarations: any[] = []; // Empty array\n if (!declarations || declarations.length === 0) {\n return false; // Safe early return\n }\n // This code would never be reached due to the safe check\n return declarations[0].id.name === 'handleError';\n };\n\n // Should return false safely without throwing\n expect(testResult()).toBe(false);\n });\n\n it('should safely handle VariableDeclaration with empty declarations array after fix', async () => {\n // This test will pass after we fix the bug\n\n fs.writeFileSync(tmpFile, 'export const handleError = () => {};');\n const mod = await loadFile(tmpFile);\n\n // Create a problematic AST structure\n const problematicNode = {\n type: 'ExportNamedDeclaration',\n declaration: {\n type: 'VariableDeclaration',\n kind: 'const',\n declarations: [], // Empty declarations array\n },\n };\n\n // Add the problematic node to the AST\n // @ts-expect-error - We need to access body for this test even though it's typed as any\n (mod.$ast.body as any[]).push(problematicNode);\n\n // After the fix, this should NOT throw an error\n let thrownError = null;\n try {\n instrumentHandleError(mod);\n } catch (error) {\n thrownError = error;\n }\n\n // After the fix, no error should be thrown\n expect(thrownError).toBeNull();\n });\n});\n"]}
1
+ {"version":3,"file":"server-entry.test.js","sourceRoot":"","sources":["../../../../test/react-router/codemods/server-entry.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as recast from 'recast';\nimport {\n instrumentServerEntry,\n instrumentHandleRequest,\n instrumentHandleError,\n} from '../../../src/react-router/codemods/server-entry';\n\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport { loadFile, generateCode } from 'magicast';\n\nvi.mock('@clack/prompts', () => {\n const mock = {\n log: {\n warn: vi.fn(),\n info: vi.fn(),\n success: vi.fn(),\n },\n };\n return {\n default: mock,\n ...mock,\n };\n});\n\nvi.mock('../../../src/utils/debug', () => ({\n debug: vi.fn(),\n}));\n\ndescribe('instrumentServerEntry', () => {\n const fixturesDir = path.join(__dirname, 'fixtures', 'server-entry');\n let tmpDir: string;\n let tmpFile: string;\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n // Create unique tmp directory for each test\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n tmpFile = path.join(tmpDir, 'entry.server.tsx');\n\n // Ensure tmp directory exists\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n // Clean up tmp directory\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should add Sentry import and wrap handleRequest function', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentServerEntry(tmpFile);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Should add Sentry import\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n\n // Should wrap the existing handleRequest function\n expect(modifiedContent).toContain(\n 'export default Sentry.wrapSentryHandleRequest(handleRequest);',\n );\n\n // Should add the Sentry import at the top of the file (after existing imports)\n const lines = modifiedContent.split('\\n');\n const sentryImportLine = lines.findIndex((line) =>\n line.includes('import * as Sentry from \"@sentry/react-router\";'),\n );\n expect(sentryImportLine).toBeGreaterThanOrEqual(0);\n\n // Should make handleRequest async\n expect(modifiedContent).toMatch(/async function handleRequest/);\n\n // Should create default handleError since none exists\n expect(modifiedContent).toContain(\n 'export const handleError = Sentry.createSentryHandleError({',\n );\n expect(modifiedContent).toContain('logErrors: false');\n });\n\n it('should handle already instrumented server entry without duplication', async () => {\n const alreadyInstrumentedContent = fs.readFileSync(\n path.join(fixturesDir, 'already-instrumented.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, alreadyInstrumentedContent);\n\n await instrumentServerEntry(tmpFile);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Should not add duplicate imports or wrapping since already instrumented\n expect(modifiedContent).toContain(\n \"import * as Sentry from '@sentry/react-router';\",\n );\n expect(modifiedContent).toContain(\n 'export default Sentry.wrapSentryHandleRequest(handleRequest);',\n );\n\n // Should NOT add a new createSentryHandleError export since handleError already has captureException\n expect(modifiedContent).not.toContain(\n 'export const handleError = Sentry.createSentryHandleError({',\n );\n\n // Should preserve the existing handleError function with captureException\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n expect(modifiedContent).toContain('export async function handleError');\n });\n\n it('should handle variable export pattern with existing export', async () => {\n const variableExportContent = fs.readFileSync(\n path.join(fixturesDir, 'variable-export.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, variableExportContent);\n\n await instrumentServerEntry(tmpFile);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Should add Sentry import and wrap handleRequest\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain(\n 'export default Sentry.wrapSentryHandleRequest(handleRequest);',\n );\n\n // Should instrument the existing handleError variable with captureException\n expect(modifiedContent).toContain('Sentry.captureException(error);');\n\n // Should preserve the variable export pattern\n expect(modifiedContent).toContain('export const handleError');\n });\n\n it('should not add duplicate async keyword when handleRequest is already async', async () => {\n const asyncContent = `\nimport { ServerRouter } from 'react-router';\nimport { renderToString } from 'react-dom/server';\n\nexport default async function handleRequest(request: Request) {\n const html = renderToString(<ServerRouter />);\n return new Response(html);\n}\n`;\n fs.writeFileSync(tmpFile, asyncContent);\n\n await instrumentServerEntry(tmpFile);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Should have async function handleRequest (not async async)\n expect(modifiedContent).toMatch(/async function handleRequest/);\n expect(modifiedContent).not.toMatch(/async\\s+async/);\n expect(modifiedContent).toContain(\n 'export default Sentry.wrapSentryHandleRequest(handleRequest);',\n );\n });\n});\n\ndescribe('instrumentHandleRequest', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `handle-request-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should add required imports when creating new handleRequest', async () => {\n const content = `// Empty server entry file`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n instrumentHandleRequest(mod);\n\n // Check if required imports were added\n const imports = mod.imports.$items;\n const hasServerRouter = imports.some(\n (item: any) =>\n item.imported === 'ServerRouter' && item.from === 'react-router',\n );\n const hasRenderToPipeableStream = imports.some(\n (item: any) =>\n item.imported === 'renderToPipeableStream' &&\n item.from === 'react-dom/server',\n );\n\n expect(hasServerRouter).toBe(true);\n expect(hasRenderToPipeableStream).toBe(true);\n });\n\n it('should not duplicate imports if they already exist', async () => {\n const content = `\nimport { ServerRouter } from 'react-router';\nimport { renderToPipeableStream } from 'react-dom/server';\nimport { createReadableStreamFromReadable } from '@react-router/node';\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n const originalImportsCount = mod.imports.$items.length;\n\n instrumentHandleRequest(mod);\n\n // Should not add duplicate imports\n expect(mod.imports.$items.length).toBe(originalImportsCount);\n });\n});\n\ndescribe('instrumentHandleError', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `handle-error-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should not modify existing handleError with captureException', async () => {\n const content = `\nexport function handleError(error: unknown) {\n Sentry.captureException(error);\n console.error(error);\n}\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n const originalBodyLength = (mod.$ast as any).body.length;\n\n instrumentHandleError(mod);\n\n // Should not modify since captureException already exists\n expect((mod.$ast as any).body.length).toBe(originalBodyLength);\n });\n\n it('should not modify existing handleError with createSentryHandleError', async () => {\n const content = `\nexport const handleError = Sentry.createSentryHandleError({\n logErrors: false\n});\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const originalBodyLength = (mod.$ast as any).body.length;\n\n instrumentHandleError(mod);\n\n // Should not modify since createSentryHandleError already exists\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n expect((mod.$ast as any).body.length).toBe(originalBodyLength);\n });\n\n it('should add captureException to existing handleError function declaration without breaking AST', async () => {\n const content = `\nexport function handleError(error: unknown) {\n console.error('Custom error handling:', error);\n // some other logic here\n}\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This should not throw an error due to broken AST manipulation\n expect(() => instrumentHandleError(mod)).not.toThrow();\n\n // Verify the function was modified correctly\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n expect(modifiedCode).toContain(\n \"console.error('Custom error handling:', error)\",\n );\n });\n\n it('should add captureException to existing handleError variable declaration without breaking AST', async () => {\n const content = `\nexport const handleError = (error: unknown, { request }: { request: Request }) => {\n console.log('Handling error:', error.message);\n return new Response('Error occurred', { status: 500 });\n};\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This should not throw an error due to broken AST manipulation\n expect(() => instrumentHandleError(mod)).not.toThrow();\n\n // Verify the function was modified correctly\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n expect(modifiedCode).toContain(\n \"console.log('Handling error:', error.message)\",\n );\n });\n\n it('should handle existing handleError with only error parameter and add request parameter', async () => {\n const content = `\nexport const handleError = (error: unknown) => {\n console.error('Simple error handler:', error);\n};\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This should not throw an error due to broken AST manipulation\n expect(() => instrumentHandleError(mod)).not.toThrow();\n\n // Verify the function signature was updated correctly\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n expect(modifiedCode).toContain('if (!request.signal.aborted)');\n // Should add request parameter\n expect(modifiedCode).toMatch(\n /handleError.*=.*\\(\\s*error.*,\\s*\\{\\s*request\\s*\\}/,\n );\n });\n});\n\ndescribe('instrumentHandleError AST manipulation edge cases', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `ast-edge-cases-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should handle function declaration with existing try-catch block', async () => {\n const content = `\nexport function handleError(error: unknown, { request }: { request: Request }) {\n try {\n console.error('Error occurred:', error);\n logToExternalService(error);\n } catch (loggingError) {\n console.warn('Failed to log error:', loggingError);\n }\n}\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This test will expose the broken AST logic\n expect(() => instrumentHandleError(mod)).not.toThrow();\n\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n expect(modifiedCode).toContain('if (!request.signal.aborted)');\n // Should preserve existing try-catch\n expect(modifiedCode).toContain('try {');\n expect(modifiedCode).toContain('} catch (loggingError) {');\n });\n\n it('should handle arrow function with block body', async () => {\n const content = `\nexport const handleError = (error: unknown, context: any) => {\n const { request } = context;\n console.error('Error in route:', error);\n return new Response('Internal Server Error', { status: 500 });\n};\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This test will expose the broken AST logic\n expect(() => instrumentHandleError(mod)).not.toThrow();\n\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n expect(modifiedCode).toContain('if (!request.signal.aborted)');\n });\n\n it('should demonstrate that the AST bug is now fixed - no longer throws TypeError', async () => {\n const content = `\nexport function handleError(error: unknown) {\n console.error('Error occurred:', error);\n}\n`;\n const tempFile = path.join(tmpDir, 'entry.server.tsx');\n fs.writeFileSync(tempFile, content);\n\n const mod = await loadFile(tempFile);\n\n // This test specifically targets the broken AST logic at lines 279-284 in server-entry.ts\n // The bug is in this code:\n // implementation.declarations[0].init.arguments[0].body.body.unshift(...)\n // Where 'implementation' is an IfStatement, not a VariableDeclaration\n\n let thrownError: Error | null = null;\n try {\n instrumentHandleError(mod);\n } catch (error) {\n thrownError = error as Error;\n }\n\n // The bug is fixed - no error should be thrown\n expect(thrownError).toBeNull();\n\n // And the code should be successfully modified\n const modifiedCode = generateCode(mod.$ast).code;\n expect(modifiedCode).toContain('Sentry.captureException(error)');\n\n // The error occurs because recast.parse() creates an IfStatement:\n // { type: 'IfStatement', test: ..., consequent: ... }\n // But the code tries to access .declarations[0] as if it were a VariableDeclaration\n });\n\n it('should demonstrate the specific line that breaks - recast.parse creates IfStatement not VariableDeclaration', () => {\n // This test shows exactly what the problematic line 278 in server-entry.ts creates\n const problematicCode = `if (!request.signal.aborted) {\n Sentry.captureException(error);\n}`;\n\n // This is what line 278 does: recast.parse(problematicCode).program.body[0]\n const implementation = recast.parse(problematicCode).program.body[0];\n\n // The implementation is an IfStatement, not a VariableDeclaration\n expect(implementation.type).toBe('IfStatement');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-assertion\n expect((implementation as any).declarations).toBeUndefined();\n\n // But lines 279-284 try to access implementation.declarations[0].init.arguments[0].body.body\n // This will throw \"Cannot read properties of undefined (reading '0')\"\n expect(() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unnecessary-type-assertion\n const declarations = (implementation as any).declarations;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return declarations[0]; // This line will throw the error\n }).toThrow('Cannot read properties of undefined');\n });\n});\n\n// Test for Bug #1: Array access vulnerability\ndescribe('Array access vulnerability bugs', () => {\n let tmpDir: string;\n let tmpFile: string;\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n // Create unique tmp directory for each test\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n tmpFile = path.join(tmpDir, 'entry.server.tsx');\n\n // Ensure tmp directory exists\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n // Clean up tmp directory\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n }\n });\n\n it('should safely handle VariableDeclaration with empty declarations array', () => {\n // This test verifies that the bug fix works correctly\n // Previously this would crash, but now it handles empty arrays safely\n\n // The implementation now includes proper safety checks, so we test that\n // it can handle edge cases without crashing\n\n // Test the actual safe implementation behavior\n const testResult = () => {\n // Simulate the safe check logic from the actual implementation\n const declarations: any[] = []; // Empty array\n if (!declarations || declarations.length === 0) {\n return false; // Safe early return\n }\n // This code would never be reached due to the safe check\n return declarations[0].id.name === 'handleError';\n };\n\n // Should return false safely without throwing\n expect(testResult()).toBe(false);\n });\n\n it('should safely handle VariableDeclaration with empty declarations array after fix', async () => {\n // This test will pass after we fix the bug\n\n fs.writeFileSync(tmpFile, 'export const handleError = () => {};');\n const mod = await loadFile(tmpFile);\n\n // Create a problematic AST structure\n const problematicNode = {\n type: 'ExportNamedDeclaration',\n declaration: {\n type: 'VariableDeclaration',\n kind: 'const',\n declarations: [], // Empty declarations array\n },\n };\n\n // Add the problematic node to the AST\n // @ts-expect-error - We need to access body for this test even though it's typed as any\n (mod.$ast.body as any[]).push(problematicNode);\n\n // After the fix, this should NOT throw an error\n let thrownError = null;\n try {\n instrumentHandleError(mod);\n } catch (error) {\n thrownError = error;\n }\n\n // After the fix, no error should be thrown\n expect(thrownError).toBeNull();\n });\n});\n\ndescribe('Instrumentation API', () => {\n const fixturesDir = path.join(__dirname, 'fixtures', 'server-entry');\n let tmpDir: string;\n let tmpFile: string;\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n tmpDir = path.join(\n __dirname,\n 'fixtures',\n 'tmp',\n `test-instrumentation-api-${Date.now()}-${Math.random()\n .toString(36)\n .substring(2, 11)}`,\n );\n tmpFile = path.join(tmpDir, 'entry.server.tsx');\n\n fs.mkdirSync(tmpDir, { recursive: true });\n });\n\n afterEach(() => {\n if (fs.existsSync(tmpDir)) {\n fs.rmSync(tmpDir, { recursive: true });\n }\n });\n\n it('should add instrumentations export when useInstrumentationAPI is true', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentServerEntry(tmpFile, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n expect(modifiedContent).toContain(\n 'export const instrumentations = [Sentry.createSentryServerInstrumentation()];',\n );\n });\n\n it('should not add instrumentations export when useInstrumentationAPI is false', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentServerEntry(tmpFile, false);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).not.toContain('instrumentations');\n expect(modifiedContent).not.toContain('createSentryServerInstrumentation');\n });\n\n it('should not duplicate instrumentations export if already present', async () => {\n const contentWithInstrumentations = `\nimport { ServerRouter } from 'react-router';\nimport * as Sentry from '@sentry/react-router';\n\nexport default function handleRequest() {}\nexport const handleError = () => {};\nexport const instrumentations = [Sentry.createSentryServerInstrumentation()];\n`;\n\n fs.writeFileSync(tmpFile, contentWithInstrumentations);\n\n await instrumentServerEntry(tmpFile, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n const count = (modifiedContent.match(/\\binstrumentations\\b/g) || []).length;\n expect(count).toBe(1);\n });\n\n it('should not duplicate if legacy unstable_instrumentations export is already present', async () => {\n const contentWithLegacy = `\nimport { ServerRouter } from 'react-router';\nimport * as Sentry from '@sentry/react-router';\n\nexport default function handleRequest() {}\nexport const handleError = () => {};\nexport const unstable_instrumentations = [Sentry.createSentryServerInstrumentation()];\n`;\n\n fs.writeFileSync(tmpFile, contentWithLegacy);\n\n await instrumentServerEntry(tmpFile, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).not.toContain('export const instrumentations =');\n });\n});\n"]}
@@ -93,6 +93,8 @@ export default defineConfig({
93
93
  (0, vitest_1.expect)(writtenConfig).toContain('org: "my-org"');
94
94
  (0, vitest_1.expect)(writtenConfig).toContain('project: "my-project"');
95
95
  (0, vitest_1.expect)(writtenConfig).toContain('config =>');
96
+ (0, vitest_1.expect)(writtenConfig).toContain('optimizeDeps');
97
+ (0, vitest_1.expect)(writtenConfig).toMatch(/exclude.*@sentry\/react-router/s);
96
98
  });
97
99
  (0, vitest_1.it)('should work with existing function form', async () => {
98
100
  const functionConfig = `import { defineConfig } from 'vite';
@@ -113,6 +115,91 @@ export default defineConfig(config => ({
113
115
  (0, vitest_1.expect)(writtenConfig).toContain('sentryReactRouter');
114
116
  (0, vitest_1.expect)(writtenConfig).toContain('org: "my-org"');
115
117
  (0, vitest_1.expect)(writtenConfig).toContain('project: "my-project"');
118
+ (0, vitest_1.expect)(writtenConfig).toContain('optimizeDeps');
119
+ (0, vitest_1.expect)(writtenConfig).toMatch(/exclude.*@sentry\/react-router/s);
120
+ });
121
+ (0, vitest_1.it)('should add @sentry/react-router to existing optimizeDeps.exclude', async () => {
122
+ const configWithExistingExclude = `import { defineConfig } from 'vite';
123
+
124
+ export default defineConfig(config => ({
125
+ plugins: [],
126
+ optimizeDeps: {
127
+ exclude: ["some-other-package"],
128
+ },
129
+ }));`;
130
+ const writtenFiles = {};
131
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(true);
132
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue(configWithExistingExclude);
133
+ vitest_1.vi.mocked(fs.promises.writeFile).mockImplementation((filePath, content) => {
134
+ writtenFiles[filePath] = content;
135
+ return Promise.resolve();
136
+ });
137
+ const result = await (0, vite_1.instrumentViteConfig)('my-org', 'my-project');
138
+ (0, vitest_1.expect)(result.wasConverted).toBe(false);
139
+ const writtenConfig = Object.values(writtenFiles)[0];
140
+ (0, vitest_1.expect)(writtenConfig).toContain('sentryReactRouter');
141
+ (0, vitest_1.expect)(writtenConfig).toContain('some-other-package');
142
+ (0, vitest_1.expect)(writtenConfig).toMatch(/exclude.*@sentry\/react-router/s);
143
+ });
144
+ (0, vitest_1.it)('should not duplicate exclude entry on repeated calls', async () => {
145
+ const configContent = `import { defineConfig } from 'vite';
146
+
147
+ export default defineConfig({
148
+ plugins: [],
149
+ });`;
150
+ const { parseModule, generateCode } = await import('magicast');
151
+ const mod = parseModule(configContent);
152
+ const program = mod.$ast;
153
+ (0, vite_1.addReactRouterPluginToViteConfig)(program, 'my-org', 'my-project');
154
+ (0, vite_1.addReactRouterPluginToViteConfig)(program, 'my-org', 'my-project');
155
+ const output = generateCode(mod).code;
156
+ const excludeMatches = output.match(/exclude.*@sentry\/react-router/gs) ?? [];
157
+ (0, vitest_1.expect)(excludeMatches).toHaveLength(1);
158
+ });
159
+ (0, vitest_1.it)('should skip non-object optimizeDeps', async () => {
160
+ const configWithFunctionOptimizeDeps = `import { defineConfig } from 'vite';
161
+ import { getOptimizeDeps } from './config-utils';
162
+
163
+ export default defineConfig(config => ({
164
+ plugins: [],
165
+ optimizeDeps: getOptimizeDeps(),
166
+ }));`;
167
+ const writtenFiles = {};
168
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(true);
169
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue(configWithFunctionOptimizeDeps);
170
+ vitest_1.vi.mocked(fs.promises.writeFile).mockImplementation((filePath, content) => {
171
+ writtenFiles[filePath] = content;
172
+ return Promise.resolve();
173
+ });
174
+ const result = await (0, vite_1.instrumentViteConfig)('my-org', 'my-project');
175
+ (0, vitest_1.expect)(result.wasConverted).toBe(false);
176
+ const writtenConfig = Object.values(writtenFiles)[0];
177
+ (0, vitest_1.expect)(writtenConfig).toContain('sentryReactRouter');
178
+ (0, vitest_1.expect)(writtenConfig).toContain('getOptimizeDeps()');
179
+ });
180
+ (0, vitest_1.it)('should skip non-array optimizeDeps.exclude', async () => {
181
+ const configWithFunctionExclude = `import { defineConfig } from 'vite';
182
+ import { getExcludes } from './config-utils';
183
+
184
+ export default defineConfig(config => ({
185
+ plugins: [],
186
+ optimizeDeps: {
187
+ exclude: getExcludes(),
188
+ },
189
+ }));`;
190
+ const writtenFiles = {};
191
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(true);
192
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue(configWithFunctionExclude);
193
+ vitest_1.vi.mocked(fs.promises.writeFile).mockImplementation((filePath, content) => {
194
+ writtenFiles[filePath] = content;
195
+ return Promise.resolve();
196
+ });
197
+ const result = await (0, vite_1.instrumentViteConfig)('my-org', 'my-project');
198
+ (0, vitest_1.expect)(result.wasConverted).toBe(false);
199
+ const writtenConfig = Object.values(writtenFiles)[0];
200
+ (0, vitest_1.expect)(writtenConfig).toContain('sentryReactRouter');
201
+ (0, vitest_1.expect)(writtenConfig).toContain('getExcludes()');
202
+ (0, vitest_1.expect)(writtenConfig).not.toMatch(/exclude.*@sentry\/react-router/s);
116
203
  });
117
204
  (0, vitest_1.it)('should prefer vite.config.ts over vite.config.js', async () => {
118
205
  const configContent = `import { defineConfig } from 'vite';
@@ -152,6 +239,8 @@ export default defineConfig(function(config) {
152
239
  (0, vitest_1.expect)(writtenConfig).toContain('sentryReactRouter');
153
240
  (0, vitest_1.expect)(writtenConfig).toContain('org: "my-org"');
154
241
  (0, vitest_1.expect)(writtenConfig).toContain('project: "my-project"');
242
+ (0, vitest_1.expect)(writtenConfig).toContain('optimizeDeps');
243
+ (0, vitest_1.expect)(writtenConfig).toMatch(/exclude.*@sentry\/react-router/s);
155
244
  });
156
245
  });
157
246
  });
@@ -1 +1 @@
1
- {"version":3,"file":"vite.test.js","sourceRoot":"","sources":["../../../../test/react-router/codemods/vite.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport { instrumentViteConfig } from '../../../src/react-router/codemods/vite';\n\nvi.mock('@clack/prompts', () => ({\n default: {\n log: {\n info: vi.fn(),\n warn: vi.fn(),\n success: vi.fn(),\n },\n },\n}));\nvi.mock('fs', async () => {\n const actual = await vi.importActual<typeof fs>('fs');\n return {\n ...actual,\n existsSync: vi.fn(),\n promises: {\n ...actual.promises,\n readFile: vi.fn(),\n writeFile: vi.fn(),\n },\n };\n});\n\ndescribe('Vite Config Instrumentation', () => {\n const mockCwd = '/mock/project';\n\n beforeEach(() => {\n vi.clearAllMocks();\n vi.spyOn(process, 'cwd').mockReturnValue(mockCwd);\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n describe('instrumentViteConfig', () => {\n it('should throw error if vite config file does not exist', async () => {\n vi.mocked(fs.existsSync).mockReturnValue(false);\n\n await expect(\n instrumentViteConfig('my-org', 'my-project'),\n ).rejects.toThrow('Could not find vite.config.ts or vite.config.js');\n });\n\n it('should detect and skip if Sentry content already exists', async () => {\n const existingConfig = `import { defineConfig } from 'vite';\nimport { sentryReactRouter } from '@sentry/react-router';\n\nexport default defineConfig({\n plugins: [sentryReactRouter({ org: \"my-org\", project: \"my-project\" }, config)]\n});`;\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(existingConfig);\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(false);\n });\n\n it('should add sentryReactRouter plugin and convert to function form', async () => {\n const simpleConfig = `import { defineConfig } from 'vite';\n\nexport default defineConfig({\n plugins: []\n});`;\n\n const writtenFiles: Record<string, string> = {};\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(simpleConfig);\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(true);\n\n const writtenConfig = Object.values(writtenFiles)[0];\n expect(writtenConfig).toContain('sentryReactRouter');\n expect(writtenConfig).toContain('org: \"my-org\"');\n expect(writtenConfig).toContain('project: \"my-project\"');\n expect(writtenConfig).toContain('config =>');\n });\n\n it('should work with existing function form', async () => {\n const functionConfig = `import { defineConfig } from 'vite';\n\nexport default defineConfig(config => ({\n plugins: []\n}));`;\n\n const writtenFiles: Record<string, string> = {};\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(functionConfig);\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(false);\n\n const writtenConfig = Object.values(writtenFiles)[0];\n expect(writtenConfig).toContain('sentryReactRouter');\n expect(writtenConfig).toContain('org: \"my-org\"');\n expect(writtenConfig).toContain('project: \"my-project\"');\n });\n\n it('should prefer vite.config.ts over vite.config.js', async () => {\n const configContent = `import { defineConfig } from 'vite';\nexport default defineConfig({ plugins: [] });`;\n\n const writtenFiles: Record<string, string> = {};\n\n // First call checks for vite.config.ts (returns true), second call validates it exists\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(configContent);\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n await instrumentViteConfig('my-org', 'my-project');\n\n // Should write to vite.config.ts, not vite.config.js\n const writtenPath = Object.keys(writtenFiles)[0];\n expect(writtenPath).toContain('vite.config.ts');\n expect(writtenPath).not.toContain('vite.config.js');\n });\n\n it('should work with function expression form', async () => {\n const functionConfig = `import { defineConfig } from 'vite';\n\nexport default defineConfig(function(config) {\n return {\n plugins: []\n };\n});`;\n\n const writtenFiles: Record<string, string> = {};\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(functionConfig);\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(false);\n\n const writtenConfig = Object.values(writtenFiles)[0];\n expect(writtenConfig).toContain('sentryReactRouter');\n expect(writtenConfig).toContain('org: \"my-org\"');\n expect(writtenConfig).toContain('project: \"my-project\"');\n });\n });\n});\n"]}
1
+ {"version":3,"file":"vite.test.js","sourceRoot":"","sources":["../../../../test/react-router/codemods/vite.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport type { namedTypes as t } from 'ast-types';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport {\n addReactRouterPluginToViteConfig,\n instrumentViteConfig,\n} from '../../../src/react-router/codemods/vite';\n\nvi.mock('@clack/prompts', () => ({\n default: {\n log: {\n info: vi.fn(),\n warn: vi.fn(),\n success: vi.fn(),\n },\n },\n}));\nvi.mock('fs', async () => {\n const actual = await vi.importActual<typeof fs>('fs');\n return {\n ...actual,\n existsSync: vi.fn(),\n promises: {\n ...actual.promises,\n readFile: vi.fn(),\n writeFile: vi.fn(),\n },\n };\n});\n\ndescribe('Vite Config Instrumentation', () => {\n const mockCwd = '/mock/project';\n\n beforeEach(() => {\n vi.clearAllMocks();\n vi.spyOn(process, 'cwd').mockReturnValue(mockCwd);\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n describe('instrumentViteConfig', () => {\n it('should throw error if vite config file does not exist', async () => {\n vi.mocked(fs.existsSync).mockReturnValue(false);\n\n await expect(\n instrumentViteConfig('my-org', 'my-project'),\n ).rejects.toThrow('Could not find vite.config.ts or vite.config.js');\n });\n\n it('should detect and skip if Sentry content already exists', async () => {\n const existingConfig = `import { defineConfig } from 'vite';\nimport { sentryReactRouter } from '@sentry/react-router';\n\nexport default defineConfig({\n plugins: [sentryReactRouter({ org: \"my-org\", project: \"my-project\" }, config)]\n});`;\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(existingConfig);\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(false);\n });\n\n it('should add sentryReactRouter plugin and convert to function form', async () => {\n const simpleConfig = `import { defineConfig } from 'vite';\n\nexport default defineConfig({\n plugins: []\n});`;\n\n const writtenFiles: Record<string, string> = {};\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(simpleConfig);\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(true);\n\n const writtenConfig = Object.values(writtenFiles)[0];\n expect(writtenConfig).toContain('sentryReactRouter');\n expect(writtenConfig).toContain('org: \"my-org\"');\n expect(writtenConfig).toContain('project: \"my-project\"');\n expect(writtenConfig).toContain('config =>');\n expect(writtenConfig).toContain('optimizeDeps');\n expect(writtenConfig).toMatch(/exclude.*@sentry\\/react-router/s);\n });\n\n it('should work with existing function form', async () => {\n const functionConfig = `import { defineConfig } from 'vite';\n\nexport default defineConfig(config => ({\n plugins: []\n}));`;\n\n const writtenFiles: Record<string, string> = {};\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(functionConfig);\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(false);\n\n const writtenConfig = Object.values(writtenFiles)[0];\n expect(writtenConfig).toContain('sentryReactRouter');\n expect(writtenConfig).toContain('org: \"my-org\"');\n expect(writtenConfig).toContain('project: \"my-project\"');\n expect(writtenConfig).toContain('optimizeDeps');\n expect(writtenConfig).toMatch(/exclude.*@sentry\\/react-router/s);\n });\n\n it('should add @sentry/react-router to existing optimizeDeps.exclude', async () => {\n const configWithExistingExclude = `import { defineConfig } from 'vite';\n\nexport default defineConfig(config => ({\n plugins: [],\n optimizeDeps: {\n exclude: [\"some-other-package\"],\n },\n}));`;\n\n const writtenFiles: Record<string, string> = {};\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n configWithExistingExclude,\n );\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(false);\n\n const writtenConfig = Object.values(writtenFiles)[0];\n expect(writtenConfig).toContain('sentryReactRouter');\n expect(writtenConfig).toContain('some-other-package');\n expect(writtenConfig).toMatch(/exclude.*@sentry\\/react-router/s);\n });\n\n it('should not duplicate exclude entry on repeated calls', async () => {\n const configContent = `import { defineConfig } from 'vite';\n\nexport default defineConfig({\n plugins: [],\n});`;\n\n const { parseModule, generateCode } = await import('magicast');\n const mod = parseModule(configContent);\n const program = mod.$ast as t.Program;\n\n addReactRouterPluginToViteConfig(program, 'my-org', 'my-project');\n addReactRouterPluginToViteConfig(program, 'my-org', 'my-project');\n\n const output = generateCode(mod).code;\n const excludeMatches =\n output.match(/exclude.*@sentry\\/react-router/gs) ?? [];\n expect(excludeMatches).toHaveLength(1);\n });\n\n it('should skip non-object optimizeDeps', async () => {\n const configWithFunctionOptimizeDeps = `import { defineConfig } from 'vite';\nimport { getOptimizeDeps } from './config-utils';\n\nexport default defineConfig(config => ({\n plugins: [],\n optimizeDeps: getOptimizeDeps(),\n}));`;\n\n const writtenFiles: Record<string, string> = {};\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n configWithFunctionOptimizeDeps,\n );\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(false);\n\n const writtenConfig = Object.values(writtenFiles)[0];\n expect(writtenConfig).toContain('sentryReactRouter');\n expect(writtenConfig).toContain('getOptimizeDeps()');\n });\n\n it('should skip non-array optimizeDeps.exclude', async () => {\n const configWithFunctionExclude = `import { defineConfig } from 'vite';\nimport { getExcludes } from './config-utils';\n\nexport default defineConfig(config => ({\n plugins: [],\n optimizeDeps: {\n exclude: getExcludes(),\n },\n}));`;\n\n const writtenFiles: Record<string, string> = {};\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n configWithFunctionExclude,\n );\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(false);\n\n const writtenConfig = Object.values(writtenFiles)[0];\n expect(writtenConfig).toContain('sentryReactRouter');\n expect(writtenConfig).toContain('getExcludes()');\n expect(writtenConfig).not.toMatch(/exclude.*@sentry\\/react-router/s);\n });\n\n it('should prefer vite.config.ts over vite.config.js', async () => {\n const configContent = `import { defineConfig } from 'vite';\nexport default defineConfig({ plugins: [] });`;\n\n const writtenFiles: Record<string, string> = {};\n\n // First call checks for vite.config.ts (returns true), second call validates it exists\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(configContent);\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n await instrumentViteConfig('my-org', 'my-project');\n\n // Should write to vite.config.ts, not vite.config.js\n const writtenPath = Object.keys(writtenFiles)[0];\n expect(writtenPath).toContain('vite.config.ts');\n expect(writtenPath).not.toContain('vite.config.js');\n });\n\n it('should work with function expression form', async () => {\n const functionConfig = `import { defineConfig } from 'vite';\n\nexport default defineConfig(function(config) {\n return {\n plugins: []\n };\n});`;\n\n const writtenFiles: Record<string, string> = {};\n\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(fs.promises.readFile).mockResolvedValue(functionConfig);\n vi.mocked(fs.promises.writeFile).mockImplementation(\n (filePath, content) => {\n writtenFiles[filePath as string] = content as string;\n return Promise.resolve();\n },\n );\n\n const result = await instrumentViteConfig('my-org', 'my-project');\n\n expect(result.wasConverted).toBe(false);\n\n const writtenConfig = Object.values(writtenFiles)[0];\n expect(writtenConfig).toContain('sentryReactRouter');\n expect(writtenConfig).toContain('org: \"my-org\"');\n expect(writtenConfig).toContain('project: \"my-project\"');\n expect(writtenConfig).toContain('optimizeDeps');\n expect(writtenConfig).toMatch(/exclude.*@sentry\\/react-router/s);\n });\n });\n});\n"]}
@@ -134,6 +134,97 @@ const templates_1 = require("../../src/react-router/templates");
134
134
  (0, vitest_1.expect)((0, sdk_setup_1.isReactRouterV7)({})).toBe(false);
135
135
  });
136
136
  });
137
+ (0, vitest_1.describe)('getReactRouterVersion', () => {
138
+ (0, vitest_1.it)('should coerce range version from package.json', () => {
139
+ (0, vitest_1.expect)((0, sdk_setup_1.getReactRouterVersion)({
140
+ dependencies: { '@react-router/dev': '^7.8.2' },
141
+ })).toBe('7.8.2');
142
+ });
143
+ (0, vitest_1.it)('should return undefined when package is not in package.json', () => {
144
+ (0, vitest_1.expect)((0, sdk_setup_1.getReactRouterVersion)({ dependencies: { react: '^18.0.0' } })).toBeUndefined();
145
+ (0, vitest_1.expect)((0, sdk_setup_1.getReactRouterVersion)({})).toBeUndefined();
146
+ });
147
+ });
148
+ (0, vitest_1.describe)('supportsInstrumentationAPI', () => {
149
+ (0, vitest_1.it)('should return true for React Router v7.15.0 or higher', () => {
150
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
151
+ dependencies: { '@react-router/dev': '7.15.0' },
152
+ })).toBe(true);
153
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
154
+ dependencies: { '@react-router/dev': '^7.15.0' },
155
+ })).toBe(true);
156
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
157
+ dependencies: { '@react-router/dev': '7.16.0' },
158
+ })).toBe(true);
159
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
160
+ dependencies: { '@react-router/dev': '8.0.0' },
161
+ })).toBe(true);
162
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
163
+ devDependencies: { '@react-router/dev': '7.15.0' },
164
+ })).toBe(true);
165
+ });
166
+ (0, vitest_1.it)('should return false for React Router versions below v7.15.0', () => {
167
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
168
+ dependencies: { '@react-router/dev': '7.14.0' },
169
+ })).toBe(false);
170
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
171
+ dependencies: { '@react-router/dev': '7.0.0' },
172
+ })).toBe(false);
173
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
174
+ dependencies: { '@react-router/dev': '7.9.5' },
175
+ })).toBe(false);
176
+ });
177
+ (0, vitest_1.it)('should return false when @react-router/dev is not installed', () => {
178
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
179
+ dependencies: { react: '^18.0.0' },
180
+ })).toBe(false);
181
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({})).toBe(false);
182
+ });
183
+ (0, vitest_1.it)('should handle semver range specifiers correctly', () => {
184
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
185
+ dependencies: { '@react-router/dev': '~7.15.0' },
186
+ })).toBe(true);
187
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsInstrumentationAPI)({
188
+ dependencies: { '@react-router/dev': '>=7.15.0' },
189
+ })).toBe(true);
190
+ });
191
+ });
192
+ (0, vitest_1.describe)('supportsOnError', () => {
193
+ (0, vitest_1.it)('should return true for React Router v7.11.0 or higher', () => {
194
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsOnError)({
195
+ dependencies: { '@react-router/dev': '7.11.0' },
196
+ })).toBe(true);
197
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsOnError)({
198
+ dependencies: { '@react-router/dev': '^7.11.0' },
199
+ })).toBe(true);
200
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsOnError)({
201
+ dependencies: { '@react-router/dev': '7.12.0' },
202
+ })).toBe(true);
203
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsOnError)({
204
+ dependencies: { '@react-router/dev': '8.0.0' },
205
+ })).toBe(true);
206
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsOnError)({
207
+ devDependencies: { '@react-router/dev': '7.11.0' },
208
+ })).toBe(true);
209
+ });
210
+ (0, vitest_1.it)('should return false for React Router versions below v7.11.0', () => {
211
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsOnError)({
212
+ dependencies: { '@react-router/dev': '7.10.0' },
213
+ })).toBe(false);
214
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsOnError)({
215
+ dependencies: { '@react-router/dev': '7.0.0' },
216
+ })).toBe(false);
217
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsOnError)({
218
+ dependencies: { '@react-router/dev': '7.8.2' },
219
+ })).toBe(false);
220
+ });
221
+ (0, vitest_1.it)('should return false when @react-router/dev is not installed', () => {
222
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsOnError)({
223
+ dependencies: { react: '^18.0.0' },
224
+ })).toBe(false);
225
+ (0, vitest_1.expect)((0, sdk_setup_1.supportsOnError)({})).toBe(false);
226
+ });
227
+ });
137
228
  (0, vitest_1.describe)('generateServerInstrumentation', () => {
138
229
  (0, vitest_1.it)('should generate server instrumentation file with all features enabled', () => {
139
230
  const dsn = 'https://sentry.io/123';
@@ -322,8 +413,8 @@ const templates_1 = require("../../src/react-router/templates");
322
413
  const writtenContent = JSON.parse(writeFileMock.mock.calls[0]?.[1]);
323
414
  // Both dev and start scripts should use the correct filenames and commands according to documentation
324
415
  (0, vitest_1.expect)(writtenContent.scripts.dev).toBe("NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev");
325
- // The start script should use react-router-serve with build path according to documentation
326
- (0, vitest_1.expect)(writtenContent.scripts.start).toBe("NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js");
416
+ // Start script should have NODE_ENV=production before --import
417
+ (0, vitest_1.expect)(writtenContent.scripts.start).toBe("NODE_ENV=production NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js");
327
418
  // The build script should remain unchanged
328
419
  (0, vitest_1.expect)(writtenContent.scripts.build).toBe('react-router build');
329
420
  });
@@ -343,7 +434,7 @@ const templates_1 = require("../../src/react-router/templates");
343
434
  await (0, sdk_setup_1.updatePackageJsonScripts)();
344
435
  // Verify only start script is modified when dev doesn't exist
345
436
  const writtenContent = JSON.parse(writeFileMock.mock.calls[0]?.[1]);
346
- (0, vitest_1.expect)(writtenContent.scripts.start).toBe("NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js");
437
+ (0, vitest_1.expect)(writtenContent.scripts.start).toBe("NODE_ENV=production NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js");
347
438
  (0, vitest_1.expect)(writtenContent.scripts.dev).toBeUndefined();
348
439
  });
349
440
  (0, vitest_1.it)('should throw error when no start script exists', async () => {
@@ -386,8 +477,8 @@ const templates_1 = require("../../src/react-router/templates");
386
477
  .mockResolvedValue();
387
478
  await (0, sdk_setup_1.updatePackageJsonScripts)();
388
479
  const writtenContent = JSON.parse(writeFileMock.mock.calls[0]?.[1]);
389
- // Should merge unquoted NODE_OPTIONS and wrap result in single quotes
390
- (0, vitest_1.expect)(writtenContent.scripts.start).toBe("NODE_OPTIONS='--require ./dotenv-config.js --import ./instrument.server.mjs' react-router-serve ./build/server/index.js");
480
+ // Should merge unquoted NODE_OPTIONS and prepend NODE_ENV
481
+ (0, vitest_1.expect)(writtenContent.scripts.start).toBe("NODE_ENV=production NODE_OPTIONS='--require ./dotenv-config.js --import ./instrument.server.mjs' react-router-serve ./build/server/index.js");
391
482
  });
392
483
  (0, vitest_1.it)('should handle quoted NODE_OPTIONS and standardize to single quotes', async () => {
393
484
  const mockPackageJson = {
@@ -405,7 +496,8 @@ const templates_1 = require("../../src/react-router/templates");
405
496
  const writtenContent = JSON.parse(writeFileMock.mock.calls[0]?.[1]);
406
497
  // Should standardize to single quotes
407
498
  (0, vitest_1.expect)(writtenContent.scripts.dev).toBe("NODE_OPTIONS='--max-old-space-size=4096 --import ./instrument.server.mjs' react-router dev");
408
- (0, vitest_1.expect)(writtenContent.scripts.start).toBe("NODE_OPTIONS='--enable-source-maps --import ./instrument.server.mjs' react-router serve");
499
+ // Should prepend NODE_ENV=production to start script
500
+ (0, vitest_1.expect)(writtenContent.scripts.start).toBe("NODE_ENV=production NODE_OPTIONS='--enable-source-maps --import ./instrument.server.mjs' react-router serve");
409
501
  });
410
502
  });
411
503
  //# sourceMappingURL=sdk-setup.test.js.map