@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
@@ -1,7 +1,35 @@
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
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  const vitest_1 = require("vitest");
4
27
  const expo_1 = require("../../src/react-native/expo");
28
+ const fs = __importStar(require("fs"));
29
+ const git = __importStar(require("../../src/react-native/git"));
30
+ // Mock modules
31
+ vitest_1.vi.mock('fs');
32
+ vitest_1.vi.mock('../../src/react-native/git');
5
33
  (0, vitest_1.describe)('expo', () => {
6
34
  const MOCK_CONFIG = {
7
35
  url: 'https://sentry.mock/',
@@ -9,6 +37,12 @@ const expo_1 = require("../../src/react-native/expo");
9
37
  project: 'project-mock',
10
38
  authToken: 'authToken-mock',
11
39
  };
40
+ (0, vitest_1.beforeEach)(() => {
41
+ vitest_1.vi.clearAllMocks();
42
+ });
43
+ (0, vitest_1.afterEach)(() => {
44
+ vitest_1.vi.restoreAllMocks();
45
+ });
12
46
  (0, vitest_1.describe)('addWithSentryToAppConfigJson', () => {
13
47
  (0, vitest_1.test)('do not add if sentry-expo present', () => {
14
48
  const appConfigJson = `{
@@ -74,5 +108,111 @@ const expo_1 = require("../../src/react-native/expo");
74
108
  });
75
109
  });
76
110
  });
111
+ (0, vitest_1.describe)('isExpoCNG', () => {
112
+ (0, vitest_1.test)('returns true when neither ios nor android folders exist', async () => {
113
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(false);
114
+ const result = await (0, expo_1.isExpoCNG)();
115
+ (0, vitest_1.expect)(result).toBe(true);
116
+ // Should check for ios folder existence
117
+ (0, vitest_1.expect)(fs.existsSync).toHaveBeenCalled();
118
+ // Should not check gitignore if folders don't exist
119
+ (0, vitest_1.expect)(git.isFolderInGitignore).not.toHaveBeenCalled();
120
+ });
121
+ (0, vitest_1.test)('returns true when only ios exists and is in gitignore (android considered ignored)', async () => {
122
+ vitest_1.vi.mocked(fs.existsSync).mockImplementation((path) => path === 'ios');
123
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);
124
+ const result = await (0, expo_1.isExpoCNG)();
125
+ (0, vitest_1.expect)(result).toBe(true);
126
+ // Should only check ios since android doesn't exist (auto-resolves to true)
127
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledTimes(1);
128
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledWith('ios');
129
+ });
130
+ (0, vitest_1.test)('returns true when only android exists and is in gitignore (ios considered ignored)', async () => {
131
+ vitest_1.vi.mocked(fs.existsSync).mockImplementation((path) => path === 'android');
132
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);
133
+ const result = await (0, expo_1.isExpoCNG)();
134
+ (0, vitest_1.expect)(result).toBe(true);
135
+ // Should only check android since ios doesn't exist (auto-resolves to true)
136
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledTimes(1);
137
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledWith('android');
138
+ });
139
+ (0, vitest_1.test)('returns false when only ios exists but is NOT in gitignore', async () => {
140
+ vitest_1.vi.mocked(fs.existsSync).mockImplementation((path) => path === 'ios');
141
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockResolvedValue(false);
142
+ const result = await (0, expo_1.isExpoCNG)();
143
+ (0, vitest_1.expect)(result).toBe(false);
144
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledTimes(1);
145
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledWith('ios');
146
+ });
147
+ (0, vitest_1.test)('returns true when both folders exist AND both are in gitignore', async () => {
148
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(true);
149
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);
150
+ const result = await (0, expo_1.isExpoCNG)();
151
+ (0, vitest_1.expect)(result).toBe(true);
152
+ (0, vitest_1.expect)(fs.existsSync).toHaveBeenCalledWith('ios');
153
+ (0, vitest_1.expect)(fs.existsSync).toHaveBeenCalledWith('android');
154
+ // Should check both folders with Promise.all
155
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledTimes(2);
156
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledWith('ios');
157
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledWith('android');
158
+ });
159
+ (0, vitest_1.test)('returns false when both folders exist BUT neither is in gitignore', async () => {
160
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(true);
161
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockResolvedValue(false);
162
+ const result = await (0, expo_1.isExpoCNG)();
163
+ (0, vitest_1.expect)(result).toBe(false);
164
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledTimes(2);
165
+ });
166
+ (0, vitest_1.test)('returns false when both folders exist but only ios is in gitignore', async () => {
167
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(true);
168
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockImplementation((folder) => Promise.resolve(folder === 'ios'));
169
+ const result = await (0, expo_1.isExpoCNG)();
170
+ (0, vitest_1.expect)(result).toBe(false);
171
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledTimes(2);
172
+ });
173
+ (0, vitest_1.test)('returns false when both folders exist but only android is in gitignore', async () => {
174
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(true);
175
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockImplementation((folder) => Promise.resolve(folder === 'android'));
176
+ const result = await (0, expo_1.isExpoCNG)();
177
+ (0, vitest_1.expect)(result).toBe(false);
178
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledTimes(2);
179
+ });
180
+ (0, vitest_1.test)('uses Promise.all to check both folders in parallel when both exist', async () => {
181
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(true);
182
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);
183
+ await (0, expo_1.isExpoCNG)();
184
+ // Should check both folders
185
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledTimes(2);
186
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledWith('ios');
187
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledWith('android');
188
+ });
189
+ (0, vitest_1.test)('only checks existing folders', async () => {
190
+ // Test when only ios exists
191
+ vitest_1.vi.mocked(fs.existsSync).mockImplementation((path) => path === 'ios');
192
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);
193
+ await (0, expo_1.isExpoCNG)();
194
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledTimes(1);
195
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledWith('ios');
196
+ // Reset and test when only android exists
197
+ vitest_1.vi.clearAllMocks();
198
+ vitest_1.vi.mocked(fs.existsSync).mockImplementation((path) => path === 'android');
199
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);
200
+ await (0, expo_1.isExpoCNG)();
201
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledTimes(1);
202
+ (0, vitest_1.expect)(git.isFolderInGitignore).toHaveBeenCalledWith('android');
203
+ // Reset and test when neither exists
204
+ vitest_1.vi.clearAllMocks();
205
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(false);
206
+ await (0, expo_1.isExpoCNG)();
207
+ (0, vitest_1.expect)(git.isFolderInGitignore).not.toHaveBeenCalled();
208
+ });
209
+ (0, vitest_1.test)('handles errors from isFolderInGitignore gracefully', async () => {
210
+ vitest_1.vi.mocked(fs.existsSync).mockReturnValue(true);
211
+ vitest_1.vi.mocked(git.isFolderInGitignore).mockRejectedValue(new Error('File system error'));
212
+ const result = await (0, expo_1.isExpoCNG)();
213
+ // Should catch error and return false instead of throwing
214
+ (0, vitest_1.expect)(result).toBe(false);
215
+ });
216
+ });
77
217
  });
78
218
  //# sourceMappingURL=expo.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"expo.test.js","sourceRoot":"","sources":["../../../test/react-native/expo.test.ts"],"names":[],"mappings":";;AAAA,mCAAgD;AAChD,sDAA2E;AAG3E,IAAA,iBAAQ,EAAC,MAAM,EAAE,GAAG,EAAE;IACpB,MAAM,WAAW,GAA4B;QAC3C,GAAG,EAAE,sBAAsB;QAC3B,GAAG,EAAE,aAAa;QAClB,OAAO,EAAE,cAAc;QACvB,SAAS,EAAE,gBAAgB;KAC5B,CAAC;IAEF,IAAA,iBAAQ,EAAC,8BAA8B,EAAE,GAAG,EAAE;QAC5C,IAAA,aAAI,EAAC,mCAAmC,EAAE,GAAG,EAAE;YAC7C,MAAM,aAAa,GAAG;;;;QAIpB,CAAC;YACH,IAAA,eAAM,EACJ,IAAA,mCAA4B,EAAC,aAAa,EAAE,WAAW,CAAC,CACzD,CAAC,QAAQ,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,IAAA,aAAI,EAAC,gDAAgD,EAAE,GAAG,EAAE;YAC1D,MAAM,aAAa,GAAG;;;;QAIpB,CAAC;YACH,IAAA,eAAM,EACJ,IAAA,mCAA4B,EAAC,aAAa,EAAE,WAAW,CAAC,CACzD,CAAC,QAAQ,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,aAAI,CAAC,IAAI,CAAC;YACR;gBACE;;;;UAIE;aACH;YACD;gBACE;;UAEE;aACH;SACF,CAAC,CAAC,uCAAuC,EAAE,CAAC,aAAa,EAAE,EAAE;YAC5D,IAAA,eAAM,EACJ,IAAA,mCAA4B,EAAC,aAAa,EAAE,WAAW,CAAC,CACzD,CAAC,QAAQ,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,aAAI,CAAC,IAAI,CAAC;YACR;gBACE;;;;UAIE;aACH;YACD,CAAC,IAAI,CAAC;YACN;gBACE;;UAEE;aACH;SACF,CAAC,CAAC,mDAAmD,EAAE,CAAC,aAAa,EAAE,EAAE;YACxE,MAAM,MAAM,GAAG,IAAA,mCAA4B,EAAC,aAAa,EAAE,WAAW,CAAC,CAAC;YACxE,IAAA,eAAM,EAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC;gBAC/C,IAAI,EAAE;oBACJ,OAAO,EAAE;wBACP;4BACE,2BAA2B;4BAC3B;gCACE,GAAG,EAAE,sBAAsB;gCAC3B,YAAY,EAAE,aAAa;gCAC3B,OAAO,EAAE,cAAc;6BACxB;yBACF;qBACF;iBACF;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, test } from 'vitest';\nimport { addWithSentryToAppConfigJson } from '../../src/react-native/expo';\nimport { RNCliSetupConfigContent } from '../../src/react-native/react-native-wizard';\n\ndescribe('expo', () => {\n const MOCK_CONFIG: RNCliSetupConfigContent = {\n url: 'https://sentry.mock/',\n org: 'sentry-mock',\n project: 'project-mock',\n authToken: 'authToken-mock',\n };\n\n describe('addWithSentryToAppConfigJson', () => {\n test('do not add if sentry-expo present', () => {\n const appConfigJson = `{\n \"expo\": {\n \"plugins\": [\"sentry-expo\"]\n }\n }`;\n expect(\n addWithSentryToAppConfigJson(appConfigJson, MOCK_CONFIG),\n ).toBeNull();\n });\n\n test('do not add if sentry-react-native/expo present', () => {\n const appConfigJson = `{\n \"expo\": {\n \"plugins\": [\"@sentry/react-native/expo\"]\n }\n }`;\n expect(\n addWithSentryToAppConfigJson(appConfigJson, MOCK_CONFIG),\n ).toBeNull();\n });\n\n test.each([\n [\n `{\n \"expo\": {\n \"plugins\": \"should be an array, but it is not\"\n }\n }`,\n ],\n [\n `{\n \"expo\": [\"should be an object, but it is not\"]\n }`,\n ],\n ])('do not add if plugins is not an array', (appConfigJson) => {\n expect(\n addWithSentryToAppConfigJson(appConfigJson, MOCK_CONFIG),\n ).toBeNull();\n });\n\n test.each([\n [\n `{\n \"expo\": {\n \"plugins\": []\n }\n }`,\n ],\n [`{}`],\n [\n `{\n \"expo\": {}\n }`,\n ],\n ])('add sentry react native expo plugin configuration', (appConfigJson) => {\n const result = addWithSentryToAppConfigJson(appConfigJson, MOCK_CONFIG);\n expect(JSON.parse(result ?? '{}')).toStrictEqual({\n expo: {\n plugins: [\n [\n '@sentry/react-native/expo',\n {\n url: 'https://sentry.mock/',\n organization: 'sentry-mock',\n project: 'project-mock',\n },\n ],\n ],\n },\n });\n });\n });\n});\n"]}
1
+ {"version":3,"file":"expo.test.js","sourceRoot":"","sources":["../../../test/react-native/expo.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, test, vi, beforeEach, afterEach } from 'vitest';\nimport {\n addWithSentryToAppConfigJson,\n isExpoCNG,\n} from '../../src/react-native/expo';\nimport { RNCliSetupConfigContent } from '../../src/react-native/react-native-wizard';\nimport * as fs from 'fs';\nimport * as git from '../../src/react-native/git';\n\n// Mock modules\nvi.mock('fs');\nvi.mock('../../src/react-native/git');\n\ndescribe('expo', () => {\n const MOCK_CONFIG: RNCliSetupConfigContent = {\n url: 'https://sentry.mock/',\n org: 'sentry-mock',\n project: 'project-mock',\n authToken: 'authToken-mock',\n };\n\n beforeEach(() => {\n vi.clearAllMocks();\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n describe('addWithSentryToAppConfigJson', () => {\n test('do not add if sentry-expo present', () => {\n const appConfigJson = `{\n \"expo\": {\n \"plugins\": [\"sentry-expo\"]\n }\n }`;\n expect(\n addWithSentryToAppConfigJson(appConfigJson, MOCK_CONFIG),\n ).toBeNull();\n });\n\n test('do not add if sentry-react-native/expo present', () => {\n const appConfigJson = `{\n \"expo\": {\n \"plugins\": [\"@sentry/react-native/expo\"]\n }\n }`;\n expect(\n addWithSentryToAppConfigJson(appConfigJson, MOCK_CONFIG),\n ).toBeNull();\n });\n\n test.each([\n [\n `{\n \"expo\": {\n \"plugins\": \"should be an array, but it is not\"\n }\n }`,\n ],\n [\n `{\n \"expo\": [\"should be an object, but it is not\"]\n }`,\n ],\n ])('do not add if plugins is not an array', (appConfigJson) => {\n expect(\n addWithSentryToAppConfigJson(appConfigJson, MOCK_CONFIG),\n ).toBeNull();\n });\n\n test.each([\n [\n `{\n \"expo\": {\n \"plugins\": []\n }\n }`,\n ],\n [`{}`],\n [\n `{\n \"expo\": {}\n }`,\n ],\n ])('add sentry react native expo plugin configuration', (appConfigJson) => {\n const result = addWithSentryToAppConfigJson(appConfigJson, MOCK_CONFIG);\n expect(JSON.parse(result ?? '{}')).toStrictEqual({\n expo: {\n plugins: [\n [\n '@sentry/react-native/expo',\n {\n url: 'https://sentry.mock/',\n organization: 'sentry-mock',\n project: 'project-mock',\n },\n ],\n ],\n },\n });\n });\n });\n\n describe('isExpoCNG', () => {\n test('returns true when neither ios nor android folders exist', async () => {\n vi.mocked(fs.existsSync).mockReturnValue(false);\n\n const result = await isExpoCNG();\n\n expect(result).toBe(true);\n // Should check for ios folder existence\n expect(fs.existsSync).toHaveBeenCalled();\n // Should not check gitignore if folders don't exist\n expect(git.isFolderInGitignore).not.toHaveBeenCalled();\n });\n\n test('returns true when only ios exists and is in gitignore (android considered ignored)', async () => {\n vi.mocked(fs.existsSync).mockImplementation((path) => path === 'ios');\n vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);\n\n const result = await isExpoCNG();\n\n expect(result).toBe(true);\n // Should only check ios since android doesn't exist (auto-resolves to true)\n expect(git.isFolderInGitignore).toHaveBeenCalledTimes(1);\n expect(git.isFolderInGitignore).toHaveBeenCalledWith('ios');\n });\n\n test('returns true when only android exists and is in gitignore (ios considered ignored)', async () => {\n vi.mocked(fs.existsSync).mockImplementation((path) => path === 'android');\n vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);\n\n const result = await isExpoCNG();\n\n expect(result).toBe(true);\n // Should only check android since ios doesn't exist (auto-resolves to true)\n expect(git.isFolderInGitignore).toHaveBeenCalledTimes(1);\n expect(git.isFolderInGitignore).toHaveBeenCalledWith('android');\n });\n\n test('returns false when only ios exists but is NOT in gitignore', async () => {\n vi.mocked(fs.existsSync).mockImplementation((path) => path === 'ios');\n vi.mocked(git.isFolderInGitignore).mockResolvedValue(false);\n\n const result = await isExpoCNG();\n\n expect(result).toBe(false);\n expect(git.isFolderInGitignore).toHaveBeenCalledTimes(1);\n expect(git.isFolderInGitignore).toHaveBeenCalledWith('ios');\n });\n\n test('returns true when both folders exist AND both are in gitignore', async () => {\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);\n\n const result = await isExpoCNG();\n\n expect(result).toBe(true);\n expect(fs.existsSync).toHaveBeenCalledWith('ios');\n expect(fs.existsSync).toHaveBeenCalledWith('android');\n // Should check both folders with Promise.all\n expect(git.isFolderInGitignore).toHaveBeenCalledTimes(2);\n expect(git.isFolderInGitignore).toHaveBeenCalledWith('ios');\n expect(git.isFolderInGitignore).toHaveBeenCalledWith('android');\n });\n\n test('returns false when both folders exist BUT neither is in gitignore', async () => {\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(git.isFolderInGitignore).mockResolvedValue(false);\n\n const result = await isExpoCNG();\n\n expect(result).toBe(false);\n expect(git.isFolderInGitignore).toHaveBeenCalledTimes(2);\n });\n\n test('returns false when both folders exist but only ios is in gitignore', async () => {\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(git.isFolderInGitignore).mockImplementation((folder) =>\n Promise.resolve(folder === 'ios'),\n );\n\n const result = await isExpoCNG();\n\n expect(result).toBe(false);\n expect(git.isFolderInGitignore).toHaveBeenCalledTimes(2);\n });\n\n test('returns false when both folders exist but only android is in gitignore', async () => {\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(git.isFolderInGitignore).mockImplementation((folder) =>\n Promise.resolve(folder === 'android'),\n );\n\n const result = await isExpoCNG();\n\n expect(result).toBe(false);\n expect(git.isFolderInGitignore).toHaveBeenCalledTimes(2);\n });\n\n test('uses Promise.all to check both folders in parallel when both exist', async () => {\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);\n\n await isExpoCNG();\n\n // Should check both folders\n expect(git.isFolderInGitignore).toHaveBeenCalledTimes(2);\n expect(git.isFolderInGitignore).toHaveBeenCalledWith('ios');\n expect(git.isFolderInGitignore).toHaveBeenCalledWith('android');\n });\n\n test('only checks existing folders', async () => {\n // Test when only ios exists\n vi.mocked(fs.existsSync).mockImplementation((path) => path === 'ios');\n vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);\n\n await isExpoCNG();\n\n expect(git.isFolderInGitignore).toHaveBeenCalledTimes(1);\n expect(git.isFolderInGitignore).toHaveBeenCalledWith('ios');\n\n // Reset and test when only android exists\n vi.clearAllMocks();\n vi.mocked(fs.existsSync).mockImplementation((path) => path === 'android');\n vi.mocked(git.isFolderInGitignore).mockResolvedValue(true);\n\n await isExpoCNG();\n\n expect(git.isFolderInGitignore).toHaveBeenCalledTimes(1);\n expect(git.isFolderInGitignore).toHaveBeenCalledWith('android');\n\n // Reset and test when neither exists\n vi.clearAllMocks();\n vi.mocked(fs.existsSync).mockReturnValue(false);\n\n await isExpoCNG();\n\n expect(git.isFolderInGitignore).not.toHaveBeenCalled();\n });\n\n test('handles errors from isFolderInGitignore gracefully', async () => {\n vi.mocked(fs.existsSync).mockReturnValue(true);\n vi.mocked(git.isFolderInGitignore).mockRejectedValue(\n new Error('File system error'),\n );\n\n const result = await isExpoCNG();\n\n // Should catch error and return false instead of throwing\n expect(result).toBe(false);\n });\n });\n});\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,160 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const vitest_1 = require("vitest");
27
+ const fs = __importStar(require("fs"));
28
+ const git_1 = require("../../src/react-native/git");
29
+ // Mock fs module
30
+ vitest_1.vi.mock('fs', () => ({
31
+ promises: {
32
+ readFile: vitest_1.vi.fn(),
33
+ appendFile: vitest_1.vi.fn(),
34
+ },
35
+ }));
36
+ (0, vitest_1.describe)('git', () => {
37
+ (0, vitest_1.beforeEach)(() => {
38
+ vitest_1.vi.clearAllMocks();
39
+ });
40
+ (0, vitest_1.afterEach)(() => {
41
+ vitest_1.vi.restoreAllMocks();
42
+ });
43
+ (0, vitest_1.describe)('isFolderInGitignore', () => {
44
+ (0, vitest_1.test)('returns true when ios is in gitignore', async () => {
45
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios\nandroid\n');
46
+ const result = await (0, git_1.isFolderInGitignore)('ios');
47
+ (0, vitest_1.expect)(result).toBe(true);
48
+ });
49
+ (0, vitest_1.test)('returns true when android is in gitignore', async () => {
50
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios\nandroid\n');
51
+ const result = await (0, git_1.isFolderInGitignore)('android');
52
+ (0, vitest_1.expect)(result).toBe(true);
53
+ });
54
+ (0, vitest_1.test)('returns true when folder has trailing slash pattern', async () => {
55
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios/\nandroid/\n');
56
+ const result = await (0, git_1.isFolderInGitignore)('ios');
57
+ (0, vitest_1.expect)(result).toBe(true);
58
+ });
59
+ (0, vitest_1.test)('returns true when folder has leading slash pattern', async () => {
60
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\n/ios\nandroid\n');
61
+ const result = await (0, git_1.isFolderInGitignore)('ios');
62
+ (0, vitest_1.expect)(result).toBe(true);
63
+ });
64
+ (0, vitest_1.test)('returns true when folder has wildcard pattern', async () => {
65
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios/*\nandroid/*\n');
66
+ const result = await (0, git_1.isFolderInGitignore)('ios');
67
+ (0, vitest_1.expect)(result).toBe(true);
68
+ });
69
+ (0, vitest_1.test)('returns true with leading and trailing slash pattern', async () => {
70
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\n/ios/\nandroid\n');
71
+ const result = await (0, git_1.isFolderInGitignore)('ios');
72
+ (0, vitest_1.expect)(result).toBe(true);
73
+ });
74
+ (0, vitest_1.test)('returns true when folder is in gitignore with additional content', async () => {
75
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('# Dependencies\nnode_modules\n\n# Native folders\nios\nandroid\n\n# Build\nbuild/\ndist/\n');
76
+ const result = await (0, git_1.isFolderInGitignore)('ios');
77
+ (0, vitest_1.expect)(result).toBe(true);
78
+ });
79
+ (0, vitest_1.test)('returns false when specified folder is not in gitignore', async () => {
80
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nandroid\nbuild\n');
81
+ const result = await (0, git_1.isFolderInGitignore)('ios');
82
+ (0, vitest_1.expect)(result).toBe(false);
83
+ });
84
+ (0, vitest_1.test)('returns true when specified folder is in gitignore', async () => {
85
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios\nbuild\n');
86
+ const result = await (0, git_1.isFolderInGitignore)('ios');
87
+ (0, vitest_1.expect)(result).toBe(true);
88
+ });
89
+ (0, vitest_1.test)('returns false when gitignore is empty', async () => {
90
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('');
91
+ const result = await (0, git_1.isFolderInGitignore)('ios');
92
+ (0, vitest_1.expect)(result).toBe(false);
93
+ });
94
+ (0, vitest_1.test)('returns false when gitignore contains folder only in comments', async () => {
95
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('# ios folder\n# android folder\nnode_modules\n');
96
+ const result = await (0, git_1.isFolderInGitignore)('ios');
97
+ (0, vitest_1.expect)(result).toBe(false);
98
+ });
99
+ (0, vitest_1.test)('returns false when gitignore contains similar names as substrings', async () => {
100
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\niosApp\nandroidApp\n');
101
+ const result = await (0, git_1.isFolderInGitignore)('ios');
102
+ (0, vitest_1.expect)(result).toBe(false);
103
+ });
104
+ (0, vitest_1.test)('returns false when gitignore file does not exist', async () => {
105
+ vitest_1.vi.mocked(fs.promises.readFile).mockRejectedValue(new Error('ENOENT: no such file or directory'));
106
+ const result = await (0, git_1.isFolderInGitignore)('ios');
107
+ (0, vitest_1.expect)(result).toBe(false);
108
+ });
109
+ (0, vitest_1.test)('returns false when fs.promises.readFile throws permission error', async () => {
110
+ vitest_1.vi.mocked(fs.promises.readFile).mockRejectedValue(new Error('EACCES: permission denied'));
111
+ const result = await (0, git_1.isFolderInGitignore)('ios');
112
+ (0, vitest_1.expect)(result).toBe(false);
113
+ });
114
+ (0, vitest_1.test)('returns false when fs.promises.readFile throws any error', async () => {
115
+ vitest_1.vi.mocked(fs.promises.readFile).mockRejectedValue(new Error('Unknown error'));
116
+ const result = await (0, git_1.isFolderInGitignore)('ios');
117
+ (0, vitest_1.expect)(result).toBe(false);
118
+ });
119
+ (0, vitest_1.test)('handles gitignore with CRLF line endings', async () => {
120
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\r\nios\r\nandroid\r\n');
121
+ const result = await (0, git_1.isFolderInGitignore)('ios');
122
+ (0, vitest_1.expect)(result).toBe(true);
123
+ });
124
+ (0, vitest_1.test)('handles gitignore with no trailing newline', async () => {
125
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nios\nandroid');
126
+ const result = await (0, git_1.isFolderInGitignore)('ios');
127
+ (0, vitest_1.expect)(result).toBe(true);
128
+ });
129
+ (0, vitest_1.test)('ignores folder name in comments', async () => {
130
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\n# ios - native folder\nios\nandroid\n');
131
+ const result = await (0, git_1.isFolderInGitignore)('ios');
132
+ (0, vitest_1.expect)(result).toBe(true);
133
+ });
134
+ (0, vitest_1.test)('returns false when similar folder names exist but not exact match', async () => {
135
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nbiosensor\nhumanoid\n');
136
+ const result = await (0, git_1.isFolderInGitignore)('ios');
137
+ (0, vitest_1.expect)(result).toBe(false);
138
+ });
139
+ (0, vitest_1.test)('returns true when folder is at the start of gitignore file', async () => {
140
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('ios\nandroid\nnode_modules\n');
141
+ const result = await (0, git_1.isFolderInGitignore)('ios');
142
+ (0, vitest_1.expect)(result).toBe(true);
143
+ });
144
+ (0, vitest_1.test)('returns true when folder is at the start with trailing slash', async () => {
145
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('ios/\nandroid/\nnode_modules\n');
146
+ const result = await (0, git_1.isFolderInGitignore)('ios');
147
+ (0, vitest_1.expect)(result).toBe(true);
148
+ });
149
+ (0, vitest_1.test)('works with different folder names', async () => {
150
+ vitest_1.vi.mocked(fs.promises.readFile).mockResolvedValue('node_modules\nbuild\ndist\n');
151
+ const buildResult = await (0, git_1.isFolderInGitignore)('build');
152
+ const distResult = await (0, git_1.isFolderInGitignore)('dist');
153
+ const srcResult = await (0, git_1.isFolderInGitignore)('src');
154
+ (0, vitest_1.expect)(buildResult).toBe(true);
155
+ (0, vitest_1.expect)(distResult).toBe(true);
156
+ (0, vitest_1.expect)(srcResult).toBe(false);
157
+ });
158
+ });
159
+ });
160
+ //# sourceMappingURL=git.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.test.js","sourceRoot":"","sources":["../../../test/react-native/git.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, test, vi, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport { isFolderInGitignore } from '../../src/react-native/git';\n\n// Mock fs module\nvi.mock('fs', () => ({\n promises: {\n readFile: vi.fn(),\n appendFile: vi.fn(),\n },\n}));\n\ndescribe('git', () => {\n beforeEach(() => {\n vi.clearAllMocks();\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n describe('isFolderInGitignore', () => {\n test('returns true when ios is in gitignore', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios\\nandroid\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true when android is in gitignore', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios\\nandroid\\n',\n );\n\n const result = await isFolderInGitignore('android');\n\n expect(result).toBe(true);\n });\n\n test('returns true when folder has trailing slash pattern', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios/\\nandroid/\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true when folder has leading slash pattern', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\n/ios\\nandroid\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true when folder has wildcard pattern', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios/*\\nandroid/*\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true with leading and trailing slash pattern', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\n/ios/\\nandroid\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true when folder is in gitignore with additional content', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n '# Dependencies\\nnode_modules\\n\\n# Native folders\\nios\\nandroid\\n\\n# Build\\nbuild/\\ndist/\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns false when specified folder is not in gitignore', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nandroid\\nbuild\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns true when specified folder is in gitignore', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios\\nbuild\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns false when gitignore is empty', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue('');\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns false when gitignore contains folder only in comments', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n '# ios folder\\n# android folder\\nnode_modules\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns false when gitignore contains similar names as substrings', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\niosApp\\nandroidApp\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns false when gitignore file does not exist', async () => {\n vi.mocked(fs.promises.readFile).mockRejectedValue(\n new Error('ENOENT: no such file or directory'),\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns false when fs.promises.readFile throws permission error', async () => {\n vi.mocked(fs.promises.readFile).mockRejectedValue(\n new Error('EACCES: permission denied'),\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns false when fs.promises.readFile throws any error', async () => {\n vi.mocked(fs.promises.readFile).mockRejectedValue(\n new Error('Unknown error'),\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('handles gitignore with CRLF line endings', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\r\\nios\\r\\nandroid\\r\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('handles gitignore with no trailing newline', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nios\\nandroid',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('ignores folder name in comments', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\n# ios - native folder\\nios\\nandroid\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns false when similar folder names exist but not exact match', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nbiosensor\\nhumanoid\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(false);\n });\n\n test('returns true when folder is at the start of gitignore file', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'ios\\nandroid\\nnode_modules\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('returns true when folder is at the start with trailing slash', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'ios/\\nandroid/\\nnode_modules\\n',\n );\n\n const result = await isFolderInGitignore('ios');\n\n expect(result).toBe(true);\n });\n\n test('works with different folder names', async () => {\n vi.mocked(fs.promises.readFile).mockResolvedValue(\n 'node_modules\\nbuild\\ndist\\n',\n );\n\n const buildResult = await isFolderInGitignore('build');\n const distResult = await isFolderInGitignore('dist');\n const srcResult = await isFolderInGitignore('src');\n\n expect(buildResult).toBe(true);\n expect(distResult).toBe(true);\n expect(srcResult).toBe(false);\n });\n });\n});\n"]}
@@ -61,7 +61,7 @@ vitest_1.vi.mock('@clack/prompts', () => {
61
61
  (0, vitest_1.it)('should add Sentry import and initialization with all features enabled', async () => {
62
62
  const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
63
63
  fs.writeFileSync(tmpFile, basicContent);
64
- await (0, client_entry_1.instrumentClientEntry)(tmpFile, 'test-dsn', true, true, true);
64
+ await (0, client_entry_1.instrumentClientEntry)(tmpFile, 'test-dsn', true, true, true, false, true);
65
65
  const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
66
66
  (0, vitest_1.expect)(modifiedContent).toContain('import * as Sentry from "@sentry/react-router";');
67
67
  (0, vitest_1.expect)(modifiedContent).toContain('Sentry.init({');
@@ -70,6 +70,7 @@ vitest_1.vi.mock('@clack/prompts', () => {
70
70
  (0, vitest_1.expect)(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');
71
71
  (0, vitest_1.expect)(modifiedContent).toContain('Sentry.replayIntegration(');
72
72
  (0, vitest_1.expect)(modifiedContent).toContain('enableLogs: true');
73
+ (0, vitest_1.expect)(modifiedContent).toContain('onError={Sentry.sentryOnError}');
73
74
  });
74
75
  (0, vitest_1.it)('should add Sentry initialization with only tracing enabled', async () => {
75
76
  const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
@@ -123,13 +124,16 @@ vitest_1.vi.mock('@clack/prompts', () => {
123
124
  (0, vitest_1.expect)(modifiedContent).not.toContain('Sentry.replayIntegration()');
124
125
  (0, vitest_1.expect)(modifiedContent).not.toContain('enableLogs: true');
125
126
  });
126
- (0, vitest_1.it)('should not modify file when Sentry content already exists', async () => {
127
+ (0, vitest_1.it)('should not add Sentry.init when Sentry content already exists but still add onError', async () => {
127
128
  const withSentryContent = fs.readFileSync(path.join(fixturesDir, 'with-sentry.tsx'), 'utf8');
128
129
  fs.writeFileSync(tmpFile, withSentryContent);
129
- await (0, client_entry_1.instrumentClientEntry)(tmpFile, 'test-dsn', true, true, true);
130
+ await (0, client_entry_1.instrumentClientEntry)(tmpFile, 'test-dsn', true, true, true, false, true);
130
131
  const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
131
- // Content should remain unchanged
132
- (0, vitest_1.expect)(modifiedContent).toBe(withSentryContent);
132
+ // Should not duplicate Sentry.init
133
+ const initCount = (modifiedContent.match(/Sentry\.init\(/g) || []).length;
134
+ (0, vitest_1.expect)(initCount).toBe(1);
135
+ // Should still add onError prop to HydratedRouter
136
+ (0, vitest_1.expect)(modifiedContent).toContain('onError={Sentry.sentryOnError}');
133
137
  });
134
138
  (0, vitest_1.it)('should insert Sentry initialization after imports', async () => {
135
139
  const withImportsContent = fs.readFileSync(path.join(fixturesDir, 'with-imports.tsx'), 'utf8');
@@ -164,5 +168,34 @@ vitest_1.vi.mock('@clack/prompts', () => {
164
168
  (0, vitest_1.expect)(modifiedContent).toContain('hydrateRoot');
165
169
  (0, vitest_1.expect)(modifiedContent).toContain('<StrictMode>');
166
170
  });
171
+ (0, vitest_1.describe)('Instrumentation API', () => {
172
+ (0, vitest_1.it)('should add instrumentation API setup when enabled', async () => {
173
+ const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
174
+ fs.writeFileSync(tmpFile, basicContent);
175
+ await (0, client_entry_1.instrumentClientEntry)(tmpFile, 'test-dsn', true, false, false, true);
176
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
177
+ (0, vitest_1.expect)(modifiedContent).toContain('const tracing = Sentry.reactRouterTracingIntegration();');
178
+ (0, vitest_1.expect)(modifiedContent).toContain('integrations: [tracing]');
179
+ (0, vitest_1.expect)(modifiedContent).toContain('instrumentations={[tracing.clientInstrumentation]}');
180
+ });
181
+ (0, vitest_1.it)('should combine instrumentation API with replay', async () => {
182
+ const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
183
+ fs.writeFileSync(tmpFile, basicContent);
184
+ await (0, client_entry_1.instrumentClientEntry)(tmpFile, 'test-dsn', true, true, false, true);
185
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
186
+ (0, vitest_1.expect)(modifiedContent).toContain('const tracing = Sentry.reactRouterTracingIntegration();');
187
+ (0, vitest_1.expect)(modifiedContent).toContain('integrations: [tracing, Sentry.replayIntegration()]');
188
+ (0, vitest_1.expect)(modifiedContent).toContain('instrumentations={[tracing.clientInstrumentation]}');
189
+ });
190
+ (0, vitest_1.it)('should not use instrumentation API when useInstrumentationAPI is false', async () => {
191
+ const basicContent = fs.readFileSync(path.join(fixturesDir, 'basic.tsx'), 'utf8');
192
+ fs.writeFileSync(tmpFile, basicContent);
193
+ await (0, client_entry_1.instrumentClientEntry)(tmpFile, 'test-dsn', true, false, false, false);
194
+ const modifiedContent = fs.readFileSync(tmpFile, 'utf8');
195
+ (0, vitest_1.expect)(modifiedContent).not.toContain('const tracing');
196
+ (0, vitest_1.expect)(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');
197
+ (0, vitest_1.expect)(modifiedContent).not.toContain('instrumentations');
198
+ });
199
+ });
167
200
  });
168
201
  //# sourceMappingURL=client-entry.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-entry.test.js","sourceRoot":"","sources":["../../../../test/react-router/codemods/client-entry.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { instrumentClientEntry } from '../../../src/react-router/codemods/client.entry';\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\ndescribe('instrumentClientEntry', () => {\n const fixturesDir = path.join(__dirname, 'fixtures', 'client-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 fixturesDir,\n 'tmp',\n `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n tmpFile = path.join(tmpDir, 'entry.client.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 initialization with all features enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, 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('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n expect(modifiedContent).toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only tracing enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, false, false);\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('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only replay enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, true, false);\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('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only logs enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, false, 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('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).toContain('enableLogs: true');\n });\n\n it('should add minimal Sentry initialization when all features are disabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, false, false);\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('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: []');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should not modify file when Sentry content already exists', async () => {\n const withSentryContent = fs.readFileSync(\n path.join(fixturesDir, 'with-sentry.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, withSentryContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Content should remain unchanged\n expect(modifiedContent).toBe(withSentryContent);\n });\n\n it('should insert Sentry initialization after imports', async () => {\n const withImportsContent = fs.readFileSync(\n path.join(fixturesDir, 'with-imports.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, withImportsContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, false, false);\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('Sentry.init({');\n\n // Check that the Sentry import is before the init call\n const sentryImportIndex = modifiedContent.indexOf(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n const sentryInitIndex = modifiedContent.indexOf('Sentry.init({');\n expect(sentryImportIndex).toBeLessThan(sentryInitIndex);\n });\n\n it('should handle files with no imports', async () => {\n const noImportsContent = fs.readFileSync(\n path.join(fixturesDir, 'no-imports.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, noImportsContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, true, false);\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('Sentry.init({');\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n });\n\n it('should preserve existing code structure', async () => {\n const complexContent = fs.readFileSync(\n path.join(fixturesDir, 'complex.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, complexContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, false);\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('Sentry.init({');\n\n // Original content should still be there\n expect(modifiedContent).toContain('startTransition');\n expect(modifiedContent).toContain('hydrateRoot');\n expect(modifiedContent).toContain('<StrictMode>');\n });\n});\n"]}
1
+ {"version":3,"file":"client-entry.test.js","sourceRoot":"","sources":["../../../../test/react-router/codemods/client-entry.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { instrumentClientEntry } from '../../../src/react-router/codemods/client.entry';\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\ndescribe('instrumentClientEntry', () => {\n const fixturesDir = path.join(__dirname, 'fixtures', 'client-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 fixturesDir,\n 'tmp',\n `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n );\n tmpFile = path.join(tmpDir, 'entry.client.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 initialization with all features enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(\n tmpFile,\n 'test-dsn',\n true,\n true,\n true,\n false,\n true,\n );\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('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n expect(modifiedContent).toContain('enableLogs: true');\n expect(modifiedContent).toContain('onError={Sentry.sentryOnError}');\n });\n\n it('should add Sentry initialization with only tracing enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, false, false);\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('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).toContain('Sentry.reactRouterTracingIntegration()');\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only replay enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, true, false);\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('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should add Sentry initialization with only logs enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, false, 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('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: [');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).toContain('enableLogs: true');\n });\n\n it('should add minimal Sentry initialization when all features are disabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, false, false);\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('Sentry.init({');\n expect(modifiedContent).toContain('dsn: \"test-dsn\"');\n expect(modifiedContent).toContain('integrations: []');\n expect(modifiedContent).not.toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).not.toContain('Sentry.replayIntegration()');\n expect(modifiedContent).not.toContain('enableLogs: true');\n });\n\n it('should not add Sentry.init when Sentry content already exists but still add onError', async () => {\n const withSentryContent = fs.readFileSync(\n path.join(fixturesDir, 'with-sentry.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, withSentryContent);\n\n await instrumentClientEntry(\n tmpFile,\n 'test-dsn',\n true,\n true,\n true,\n false,\n true,\n );\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n // Should not duplicate Sentry.init\n const initCount = (modifiedContent.match(/Sentry\\.init\\(/g) || []).length;\n expect(initCount).toBe(1);\n\n // Should still add onError prop to HydratedRouter\n expect(modifiedContent).toContain('onError={Sentry.sentryOnError}');\n });\n\n it('should insert Sentry initialization after imports', async () => {\n const withImportsContent = fs.readFileSync(\n path.join(fixturesDir, 'with-imports.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, withImportsContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, false, false);\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('Sentry.init({');\n\n // Check that the Sentry import is before the init call\n const sentryImportIndex = modifiedContent.indexOf(\n 'import * as Sentry from \"@sentry/react-router\";',\n );\n const sentryInitIndex = modifiedContent.indexOf('Sentry.init({');\n expect(sentryImportIndex).toBeLessThan(sentryInitIndex);\n });\n\n it('should handle files with no imports', async () => {\n const noImportsContent = fs.readFileSync(\n path.join(fixturesDir, 'no-imports.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, noImportsContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', false, true, false);\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('Sentry.init({');\n expect(modifiedContent).toContain('Sentry.replayIntegration(');\n });\n\n it('should preserve existing code structure', async () => {\n const complexContent = fs.readFileSync(\n path.join(fixturesDir, 'complex.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, complexContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, false);\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('Sentry.init({');\n\n // Original content should still be there\n expect(modifiedContent).toContain('startTransition');\n expect(modifiedContent).toContain('hydrateRoot');\n expect(modifiedContent).toContain('<StrictMode>');\n });\n\n describe('Instrumentation API', () => {\n it('should add instrumentation API setup when enabled', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(\n tmpFile,\n 'test-dsn',\n true,\n false,\n false,\n true,\n );\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'const tracing = Sentry.reactRouterTracingIntegration();',\n );\n expect(modifiedContent).toContain('integrations: [tracing]');\n expect(modifiedContent).toContain(\n 'instrumentations={[tracing.clientInstrumentation]}',\n );\n });\n\n it('should combine instrumentation API with replay', async () => {\n const basicContent = fs.readFileSync(\n path.join(fixturesDir, 'basic.tsx'),\n 'utf8',\n );\n\n fs.writeFileSync(tmpFile, basicContent);\n\n await instrumentClientEntry(tmpFile, 'test-dsn', true, true, false, true);\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).toContain(\n 'const tracing = Sentry.reactRouterTracingIntegration();',\n );\n expect(modifiedContent).toContain(\n 'integrations: [tracing, Sentry.replayIntegration()]',\n );\n expect(modifiedContent).toContain(\n 'instrumentations={[tracing.clientInstrumentation]}',\n );\n });\n\n it('should not use instrumentation API 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 instrumentClientEntry(\n tmpFile,\n 'test-dsn',\n true,\n false,\n false,\n false,\n );\n\n const modifiedContent = fs.readFileSync(tmpFile, 'utf8');\n\n expect(modifiedContent).not.toContain('const tracing');\n expect(modifiedContent).toContain(\n 'Sentry.reactRouterTracingIntegration()',\n );\n expect(modifiedContent).not.toContain('instrumentations');\n });\n });\n});\n"]}