ai-first-cli 1.3.1 → 1.3.5

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 (532) hide show
  1. package/.ai-dev/index.db +0 -0
  2. package/BETA_EVALUATION_REPORT.md +151 -0
  3. package/CHANGELOG.md +178 -0
  4. package/PHASE1_USER_SIMULATION.md +56 -0
  5. package/PHASE2_USER_SIMULATION.md +81 -0
  6. package/PHASE3_USER_SIMULATION.md +176 -0
  7. package/README.es.md +18 -0
  8. package/README.md +80 -1
  9. package/ai/graph/knowledge-graph.json +10 -0
  10. package/ai-context/ai_context.md +130 -0
  11. package/{test-projects/react-app/.ai-dev → ai-context}/ai_rules.md +10 -5
  12. package/ai-context/architecture.md +136 -0
  13. package/ai-context/context/features/src.json +69 -0
  14. package/ai-context/context/features/test-projects.json +69 -0
  15. package/ai-context/context/flows/App.json +17 -0
  16. package/ai-context/context/flows/DashboardPage.json +14 -0
  17. package/ai-context/context/flows/LoginPage.json +14 -0
  18. package/ai-context/context/flows/admin.json +10 -0
  19. package/ai-context/context/flows/ai-first.json +9 -0
  20. package/ai-context/context/flows/androidresources.json +11 -0
  21. package/ai-context/context/flows/auth.json +13 -0
  22. package/ai-context/context/flows/authController.json +14 -0
  23. package/ai-context/context/flows/doctor.json +9 -0
  24. package/ai-context/context/flows/entrypoints.json +9 -0
  25. package/ai-context/context/flows/explore.json +9 -0
  26. package/ai-context/context/flows/fastapiAdapter.json +14 -0
  27. package/ai-context/context/flows/fastapiadapter.json +11 -0
  28. package/ai-context/context/flows/index.json +19 -0
  29. package/ai-context/context/flows/indexer.json +9 -0
  30. package/ai-context/context/flows/indexstate.json +9 -0
  31. package/ai-context/context/flows/init.json +22 -0
  32. package/ai-context/context/flows/main.json +18 -0
  33. package/ai-context/context/flows/mainactivity.json +9 -0
  34. package/ai-context/context/flows/models.json +15 -0
  35. package/ai-context/context/flows/posts.json +15 -0
  36. package/ai-context/context/flows/repoMapper.json +20 -0
  37. package/ai-context/context/flows/repomapper.json +11 -0
  38. package/ai-context/context/flows/routes.json +15 -0
  39. package/ai-context/context/flows/serializers.json +10 -0
  40. package/ai-context/context/flows/user.json +23 -0
  41. package/ai-context/context/flows/views.json +12 -0
  42. package/{test-projects/react-app/.ai-dev → ai-context}/conventions.md +3 -2
  43. package/ai-context/dependencies.json +3360 -0
  44. package/ai-context/entrypoints.md +45 -0
  45. package/ai-context/index-state.json +196 -0
  46. package/ai-context/modules.json +901 -0
  47. package/ai-context/project.json +33 -0
  48. package/ai-context/repo_map.json +8857 -0
  49. package/ai-context/repo_map.md +2002 -0
  50. package/{test-projects/flask-app/.ai-dev → ai-context}/schema.json +1 -1
  51. package/ai-context/summary.md +46 -0
  52. package/ai-context/symbols.json +82467 -0
  53. package/{test-projects/react-app/.ai-dev → ai-context}/tech_stack.md +15 -7
  54. package/ai-context-evaluation-report-1774223059505.md +206 -0
  55. package/dist/analyzers/architecture.d.ts.map +1 -1
  56. package/dist/analyzers/architecture.js +6 -0
  57. package/dist/analyzers/architecture.js.map +1 -1
  58. package/dist/analyzers/entrypoints.d.ts.map +1 -1
  59. package/dist/analyzers/entrypoints.js +105 -0
  60. package/dist/analyzers/entrypoints.js.map +1 -1
  61. package/dist/analyzers/symbols.d.ts.map +1 -1
  62. package/dist/analyzers/symbols.js +72 -1
  63. package/dist/analyzers/symbols.js.map +1 -1
  64. package/dist/analyzers/techStack.d.ts +8 -0
  65. package/dist/analyzers/techStack.d.ts.map +1 -1
  66. package/dist/analyzers/techStack.js +75 -0
  67. package/dist/analyzers/techStack.js.map +1 -1
  68. package/dist/scripts/ai-context-evaluator.js +367 -0
  69. package/package.json +1 -1
  70. package/quick-evaluation-report-1774396002305.md +64 -0
  71. package/quick-evaluator.ts +200 -0
  72. package/scripts/ai-context-evaluator.ts +440 -0
  73. package/src/analyzers/architecture.ts +8 -0
  74. package/src/analyzers/entrypoints.ts +115 -0
  75. package/src/analyzers/symbols.ts +77 -1
  76. package/src/analyzers/techStack.ts +93 -0
  77. package/tests/apex-parser.test.ts +193 -0
  78. package/tests/cli-commands-batch1.test.ts +808 -0
  79. package/tests/cli-commands-batch2.test.ts +1113 -0
  80. package/tests/cli-commands-batch3.test.ts +1128 -0
  81. package/tests/cli-index.test.ts +1007 -0
  82. package/tests/cli-init.test.ts +761 -0
  83. package/tests/salesforce-apex-classes.test.ts +713 -0
  84. package/tests/salesforce-apex-triggers.test.ts +871 -0
  85. package/tests/salesforce-custom-objects.test.ts +918 -0
  86. package/tests/salesforce-flows.test.ts +710 -0
  87. package/tests/salesforce-lwc.test.ts +963 -0
  88. package/tests/salesforce-sfdx-integration.test.ts +1125 -0
  89. package/ANALISIS_COMPLETO.md +0 -424
  90. package/ANALISIS_MEJORAS.md +0 -327
  91. package/CONTRIBUTING.md +0 -89
  92. package/FLOW.md +0 -129
  93. package/TEST_RESULTS.md +0 -198
  94. package/TEST_RESULTS_COMPARATIVE.md +0 -159
  95. package/TEST_RESULTS_COMPLETE.md +0 -127
  96. package/TEST_RESULTS_COMPREHENSIVE.md +0 -208
  97. package/install.sh +0 -188
  98. package/run-all-tests.sh +0 -184
  99. package/test-ai-context-understanding.sh +0 -21
  100. package/test-projects/django-app/.ai-dev/ai_context.md +0 -92
  101. package/test-projects/django-app/.ai-dev/ai_rules.md +0 -47
  102. package/test-projects/django-app/.ai-dev/architecture.md +0 -57
  103. package/test-projects/django-app/.ai-dev/cache.json +0 -169
  104. package/test-projects/django-app/.ai-dev/context/flows/views.json +0 -10
  105. package/test-projects/django-app/.ai-dev/conventions.md +0 -51
  106. package/test-projects/django-app/.ai-dev/dependencies.json +0 -312
  107. package/test-projects/django-app/.ai-dev/entrypoints.md +0 -4
  108. package/test-projects/django-app/.ai-dev/files.json +0 -209
  109. package/test-projects/django-app/.ai-dev/graph/knowledge-graph.json +0 -36
  110. package/test-projects/django-app/.ai-dev/graph/module-graph.json +0 -145
  111. package/test-projects/django-app/.ai-dev/graph/symbol-graph.json +0 -1488
  112. package/test-projects/django-app/.ai-dev/graph/symbol-references.json +0 -1
  113. package/test-projects/django-app/.ai-dev/index-state.json +0 -294
  114. package/test-projects/django-app/.ai-dev/modules.json +0 -35
  115. package/test-projects/django-app/.ai-dev/project.json +0 -11
  116. package/test-projects/django-app/.ai-dev/repo_map.json +0 -412
  117. package/test-projects/django-app/.ai-dev/repo_map.md +0 -105
  118. package/test-projects/django-app/.ai-dev/schema.json +0 -5
  119. package/test-projects/django-app/.ai-dev/summary.md +0 -15
  120. package/test-projects/django-app/.ai-dev/symbols.json +0 -1
  121. package/test-projects/django-app/.ai-dev/tech_stack.md +0 -32
  122. package/test-projects/django-app/README.md +0 -91
  123. package/test-projects/django-app/blog/__init__.py +0 -0
  124. package/test-projects/django-app/blog/admin.py +0 -31
  125. package/test-projects/django-app/blog/models.py +0 -55
  126. package/test-projects/django-app/blog/serializers.py +0 -69
  127. package/test-projects/django-app/blog/urls.py +0 -14
  128. package/test-projects/django-app/blog/views.py +0 -96
  129. package/test-projects/django-app/django_app/__init__.py +0 -0
  130. package/test-projects/django-app/django_app/settings.py +0 -90
  131. package/test-projects/django-app/django_app/urls.py +0 -11
  132. package/test-projects/django-app/django_app/wsgi.py +0 -9
  133. package/test-projects/django-app/manage.py +0 -23
  134. package/test-projects/django-app/requirements.txt +0 -3
  135. package/test-projects/django-app/users/__init__.py +0 -0
  136. package/test-projects/django-app/users/admin.py +0 -42
  137. package/test-projects/django-app/users/models.py +0 -54
  138. package/test-projects/django-app/users/serializers.py +0 -113
  139. package/test-projects/django-app/users/urls.py +0 -13
  140. package/test-projects/django-app/users/views.py +0 -135
  141. package/test-projects/express-api/.ai-dev/ai_context.md +0 -112
  142. package/test-projects/express-api/.ai-dev/ai_rules.md +0 -50
  143. package/test-projects/express-api/.ai-dev/architecture.md +0 -62
  144. package/test-projects/express-api/.ai-dev/context/features/controllers.json +0 -13
  145. package/test-projects/express-api/.ai-dev/context/features/services.json +0 -13
  146. package/test-projects/express-api/.ai-dev/context/flows/auth.json +0 -12
  147. package/test-projects/express-api/.ai-dev/context/flows/user.json +0 -13
  148. package/test-projects/express-api/.ai-dev/conventions.md +0 -51
  149. package/test-projects/express-api/.ai-dev/dependencies.json +0 -54
  150. package/test-projects/express-api/.ai-dev/entrypoints.md +0 -17
  151. package/test-projects/express-api/.ai-dev/modules.json +0 -30
  152. package/test-projects/express-api/.ai-dev/project.json +0 -15
  153. package/test-projects/express-api/.ai-dev/repo_map.json +0 -100
  154. package/test-projects/express-api/.ai-dev/repo_map.md +0 -36
  155. package/test-projects/express-api/.ai-dev/schema.json +0 -5
  156. package/test-projects/express-api/.ai-dev/summary.md +0 -14
  157. package/test-projects/express-api/.ai-dev/symbols.json +0 -7
  158. package/test-projects/express-api/.ai-dev/tech_stack.md +0 -38
  159. package/test-projects/express-api/.ai-dev/tools.json +0 -10
  160. package/test-projects/express-api/controllers/authController.js +0 -32
  161. package/test-projects/express-api/controllers/userController.js +0 -51
  162. package/test-projects/express-api/index.js +0 -30
  163. package/test-projects/express-api/middleware/authMiddleware.js +0 -30
  164. package/test-projects/express-api/models/userRepository.js +0 -25
  165. package/test-projects/express-api/package.json +0 -18
  166. package/test-projects/express-api/services/authService.js +0 -17
  167. package/test-projects/express-api/services/userService.js +0 -28
  168. package/test-projects/fastapi-app/.ai-dev/ai_context.md +0 -89
  169. package/test-projects/fastapi-app/.ai-dev/ai_rules.md +0 -47
  170. package/test-projects/fastapi-app/.ai-dev/architecture.md +0 -39
  171. package/test-projects/fastapi-app/.ai-dev/cache.json +0 -125
  172. package/test-projects/fastapi-app/.ai-dev/conventions.md +0 -51
  173. package/test-projects/fastapi-app/.ai-dev/dependencies.json +0 -244
  174. package/test-projects/fastapi-app/.ai-dev/entrypoints.md +0 -4
  175. package/test-projects/fastapi-app/.ai-dev/files.json +0 -154
  176. package/test-projects/fastapi-app/.ai-dev/graph/knowledge-graph.json +0 -15
  177. package/test-projects/fastapi-app/.ai-dev/graph/module-graph.json +0 -78
  178. package/test-projects/fastapi-app/.ai-dev/graph/symbol-graph.json +0 -1724
  179. package/test-projects/fastapi-app/.ai-dev/graph/symbol-references.json +0 -51
  180. package/test-projects/fastapi-app/.ai-dev/index-state.json +0 -217
  181. package/test-projects/fastapi-app/.ai-dev/modules.json +0 -16
  182. package/test-projects/fastapi-app/.ai-dev/project.json +0 -9
  183. package/test-projects/fastapi-app/.ai-dev/repo_map.json +0 -298
  184. package/test-projects/fastapi-app/.ai-dev/repo_map.md +0 -74
  185. package/test-projects/fastapi-app/.ai-dev/schema.json +0 -5
  186. package/test-projects/fastapi-app/.ai-dev/summary.md +0 -12
  187. package/test-projects/fastapi-app/.ai-dev/symbols.json +0 -1
  188. package/test-projects/fastapi-app/.ai-dev/tech_stack.md +0 -32
  189. package/test-projects/fastapi-app/.ai-dev/tools.json +0 -10
  190. package/test-projects/fastapi-app/README.md +0 -118
  191. package/test-projects/fastapi-app/app/database.py +0 -21
  192. package/test-projects/fastapi-app/app/dependencies.py +0 -107
  193. package/test-projects/fastapi-app/app/main.py +0 -47
  194. package/test-projects/fastapi-app/app/models.py +0 -149
  195. package/test-projects/fastapi-app/app/routers/auth.py +0 -117
  196. package/test-projects/fastapi-app/app/routers/posts.py +0 -272
  197. package/test-projects/fastapi-app/app/schemas.py +0 -191
  198. package/test-projects/fastapi-app/requirements.txt +0 -10
  199. package/test-projects/flask-app/.ai-dev/ai_context.md +0 -94
  200. package/test-projects/flask-app/.ai-dev/ai_rules.md +0 -47
  201. package/test-projects/flask-app/.ai-dev/architecture.md +0 -49
  202. package/test-projects/flask-app/.ai-dev/cache.json +0 -157
  203. package/test-projects/flask-app/.ai-dev/context/features/app.json +0 -25
  204. package/test-projects/flask-app/.ai-dev/context/flows/routes.json +0 -14
  205. package/test-projects/flask-app/.ai-dev/conventions.md +0 -51
  206. package/test-projects/flask-app/.ai-dev/dependencies.json +0 -298
  207. package/test-projects/flask-app/.ai-dev/entrypoints.md +0 -4
  208. package/test-projects/flask-app/.ai-dev/files.json +0 -194
  209. package/test-projects/flask-app/.ai-dev/graph/knowledge-graph.json +0 -60
  210. package/test-projects/flask-app/.ai-dev/graph/module-graph.json +0 -95
  211. package/test-projects/flask-app/.ai-dev/graph/symbol-graph.json +0 -1448
  212. package/test-projects/flask-app/.ai-dev/graph/symbol-references.json +0 -45
  213. package/test-projects/flask-app/.ai-dev/index-state.json +0 -273
  214. package/test-projects/flask-app/.ai-dev/modules.json +0 -21
  215. package/test-projects/flask-app/.ai-dev/project.json +0 -13
  216. package/test-projects/flask-app/.ai-dev/repo_map.json +0 -400
  217. package/test-projects/flask-app/.ai-dev/repo_map.md +0 -98
  218. package/test-projects/flask-app/.ai-dev/summary.md +0 -13
  219. package/test-projects/flask-app/.ai-dev/symbols.json +0 -1
  220. package/test-projects/flask-app/.ai-dev/tech_stack.md +0 -32
  221. package/test-projects/flask-app/.ai-dev/tools.json +0 -10
  222. package/test-projects/flask-app/README.md +0 -129
  223. package/test-projects/flask-app/app/__init__.py +0 -46
  224. package/test-projects/flask-app/app/api/__init__.py +0 -7
  225. package/test-projects/flask-app/app/api/routes.py +0 -122
  226. package/test-projects/flask-app/app/auth/__init__.py +0 -7
  227. package/test-projects/flask-app/app/auth/forms.py +0 -52
  228. package/test-projects/flask-app/app/auth/routes.py +0 -68
  229. package/test-projects/flask-app/app/blog/__init__.py +0 -7
  230. package/test-projects/flask-app/app/blog/forms.py +0 -35
  231. package/test-projects/flask-app/app/blog/routes.py +0 -140
  232. package/test-projects/flask-app/app/main/__init__.py +0 -7
  233. package/test-projects/flask-app/app/main/routes.py +0 -88
  234. package/test-projects/flask-app/app/models.py +0 -177
  235. package/test-projects/flask-app/config.py +0 -64
  236. package/test-projects/flask-app/requirements.txt +0 -10
  237. package/test-projects/laravel-app/.ai-dev/ai_context.md +0 -97
  238. package/test-projects/laravel-app/.ai-dev/ai_rules.md +0 -47
  239. package/test-projects/laravel-app/.ai-dev/architecture.md +0 -60
  240. package/test-projects/laravel-app/.ai-dev/cache.json +0 -161
  241. package/test-projects/laravel-app/.ai-dev/context/features/app.json +0 -21
  242. package/test-projects/laravel-app/.ai-dev/context/flows/.json +0 -9
  243. package/test-projects/laravel-app/.ai-dev/context/flows/category.json +0 -12
  244. package/test-projects/laravel-app/.ai-dev/context/flows/comment.json +0 -12
  245. package/test-projects/laravel-app/.ai-dev/context/flows/post.json +0 -12
  246. package/test-projects/laravel-app/.ai-dev/context/flows/unnamed.json +0 -9
  247. package/test-projects/laravel-app/.ai-dev/conventions.md +0 -51
  248. package/test-projects/laravel-app/.ai-dev/dependencies.json +0 -6
  249. package/test-projects/laravel-app/.ai-dev/entrypoints.md +0 -4
  250. package/test-projects/laravel-app/.ai-dev/files.json +0 -199
  251. package/test-projects/laravel-app/.ai-dev/graph/knowledge-graph.json +0 -98
  252. package/test-projects/laravel-app/.ai-dev/graph/module-graph.json +0 -30
  253. package/test-projects/laravel-app/.ai-dev/graph/symbol-graph.json +0 -5
  254. package/test-projects/laravel-app/.ai-dev/graph/symbol-references.json +0 -1
  255. package/test-projects/laravel-app/.ai-dev/index-state.json +0 -280
  256. package/test-projects/laravel-app/.ai-dev/modules.json +0 -29
  257. package/test-projects/laravel-app/.ai-dev/project.json +0 -17
  258. package/test-projects/laravel-app/.ai-dev/repo_map.json +0 -419
  259. package/test-projects/laravel-app/.ai-dev/repo_map.md +0 -106
  260. package/test-projects/laravel-app/.ai-dev/schema.json +0 -5
  261. package/test-projects/laravel-app/.ai-dev/summary.md +0 -15
  262. package/test-projects/laravel-app/.ai-dev/symbols.json +0 -1
  263. package/test-projects/laravel-app/.ai-dev/tech_stack.md +0 -34
  264. package/test-projects/laravel-app/.ai-dev/tools.json +0 -10
  265. package/test-projects/laravel-app/README.md +0 -107
  266. package/test-projects/laravel-app/app/Http/Controllers/Api/CategoryController.php +0 -88
  267. package/test-projects/laravel-app/app/Http/Controllers/Api/CommentController.php +0 -56
  268. package/test-projects/laravel-app/app/Http/Controllers/Api/PostController.php +0 -174
  269. package/test-projects/laravel-app/app/Http/Controllers/Controller.php +0 -12
  270. package/test-projects/laravel-app/app/Models/Category.php +0 -34
  271. package/test-projects/laravel-app/app/Models/Comment.php +0 -51
  272. package/test-projects/laravel-app/app/Models/Post.php +0 -108
  273. package/test-projects/laravel-app/app/Models/User.php +0 -85
  274. package/test-projects/laravel-app/bootstrap/app.php +0 -25
  275. package/test-projects/laravel-app/composer.json +0 -35
  276. package/test-projects/laravel-app/routes/api.php +0 -40
  277. package/test-projects/nestjs-backend/.ai-dev/ai_context.md +0 -111
  278. package/test-projects/nestjs-backend/.ai-dev/ai_rules.md +0 -52
  279. package/test-projects/nestjs-backend/.ai-dev/architecture.md +0 -49
  280. package/test-projects/nestjs-backend/.ai-dev/cache.json +0 -169
  281. package/test-projects/nestjs-backend/.ai-dev/context/features/src.json +0 -23
  282. package/test-projects/nestjs-backend/.ai-dev/context/flows/auth.controller.json +0 -14
  283. package/test-projects/nestjs-backend/.ai-dev/context/flows/auth.json +0 -10
  284. package/test-projects/nestjs-backend/.ai-dev/context/flows/users..json +0 -10
  285. package/test-projects/nestjs-backend/.ai-dev/context/flows/users.controller.json +0 -14
  286. package/test-projects/nestjs-backend/.ai-dev/context/flows/users.json +0 -10
  287. package/test-projects/nestjs-backend/.ai-dev/conventions.md +0 -52
  288. package/test-projects/nestjs-backend/.ai-dev/dependencies.json +0 -152
  289. package/test-projects/nestjs-backend/.ai-dev/entrypoints.md +0 -18
  290. package/test-projects/nestjs-backend/.ai-dev/files.json +0 -209
  291. package/test-projects/nestjs-backend/.ai-dev/graph/knowledge-graph.json +0 -132
  292. package/test-projects/nestjs-backend/.ai-dev/graph/module-graph.json +0 -29
  293. package/test-projects/nestjs-backend/.ai-dev/graph/symbol-graph.json +0 -304
  294. package/test-projects/nestjs-backend/.ai-dev/graph/symbol-references.json +0 -5
  295. package/test-projects/nestjs-backend/.ai-dev/index-state.json +0 -294
  296. package/test-projects/nestjs-backend/.ai-dev/modules.json +0 -19
  297. package/test-projects/nestjs-backend/.ai-dev/project.json +0 -18
  298. package/test-projects/nestjs-backend/.ai-dev/repo_map.json +0 -427
  299. package/test-projects/nestjs-backend/.ai-dev/repo_map.md +0 -104
  300. package/test-projects/nestjs-backend/.ai-dev/schema.json +0 -5
  301. package/test-projects/nestjs-backend/.ai-dev/summary.md +0 -13
  302. package/test-projects/nestjs-backend/.ai-dev/symbols.json +0 -1
  303. package/test-projects/nestjs-backend/.ai-dev/tech_stack.md +0 -38
  304. package/test-projects/nestjs-backend/.ai-dev/tools.json +0 -10
  305. package/test-projects/nestjs-backend/package.json +0 -22
  306. package/test-projects/nestjs-backend/src/app.module.ts +0 -8
  307. package/test-projects/nestjs-backend/src/auth/auth.controller.ts +0 -22
  308. package/test-projects/nestjs-backend/src/auth/auth.module.ts +0 -11
  309. package/test-projects/nestjs-backend/src/auth/auth.service.ts +0 -28
  310. package/test-projects/nestjs-backend/src/auth/dto/login.dto.ts +0 -4
  311. package/test-projects/nestjs-backend/src/auth/strategies/jwt.strategy.ts +0 -18
  312. package/test-projects/nestjs-backend/src/main.ts +0 -9
  313. package/test-projects/nestjs-backend/src/users/users.controller.ts +0 -32
  314. package/test-projects/nestjs-backend/src/users/users.module.ts +0 -10
  315. package/test-projects/nestjs-backend/src/users/users.service.ts +0 -42
  316. package/test-projects/nestjs-backend/tsconfig.json +0 -21
  317. package/test-projects/python-cli/.ai-dev/ai_context.md +0 -95
  318. package/test-projects/python-cli/.ai-dev/ai_rules.md +0 -47
  319. package/test-projects/python-cli/.ai-dev/architecture.md +0 -55
  320. package/test-projects/python-cli/.ai-dev/cache.json +0 -149
  321. package/test-projects/python-cli/.ai-dev/context/features/cli.json +0 -16
  322. package/test-projects/python-cli/.ai-dev/context/flows/list_.json +0 -9
  323. package/test-projects/python-cli/.ai-dev/context/flows/remove_.json +0 -9
  324. package/test-projects/python-cli/.ai-dev/conventions.md +0 -51
  325. package/test-projects/python-cli/.ai-dev/dependencies.json +0 -66
  326. package/test-projects/python-cli/.ai-dev/entrypoints.md +0 -4
  327. package/test-projects/python-cli/.ai-dev/files.json +0 -184
  328. package/test-projects/python-cli/.ai-dev/graph/knowledge-graph.json +0 -83
  329. package/test-projects/python-cli/.ai-dev/graph/module-graph.json +0 -31
  330. package/test-projects/python-cli/.ai-dev/graph/symbol-graph.json +0 -358
  331. package/test-projects/python-cli/.ai-dev/graph/symbol-references.json +0 -11
  332. package/test-projects/python-cli/.ai-dev/index-state.json +0 -259
  333. package/test-projects/python-cli/.ai-dev/modules.json +0 -21
  334. package/test-projects/python-cli/.ai-dev/project.json +0 -15
  335. package/test-projects/python-cli/.ai-dev/repo_map.json +0 -367
  336. package/test-projects/python-cli/.ai-dev/repo_map.md +0 -93
  337. package/test-projects/python-cli/.ai-dev/schema.json +0 -5
  338. package/test-projects/python-cli/.ai-dev/summary.md +0 -14
  339. package/test-projects/python-cli/.ai-dev/symbols.json +0 -1
  340. package/test-projects/python-cli/.ai-dev/tech_stack.md +0 -32
  341. package/test-projects/python-cli/.ai-dev/tools.json +0 -10
  342. package/test-projects/python-cli/__init__.py +0 -1
  343. package/test-projects/python-cli/cli/__init__.py +0 -1
  344. package/test-projects/python-cli/cli/add_command.py +0 -6
  345. package/test-projects/python-cli/cli/list_command.py +0 -7
  346. package/test-projects/python-cli/cli/remove_command.py +0 -6
  347. package/test-projects/python-cli/main.py +0 -34
  348. package/test-projects/python-cli/models/__init__.py +0 -2
  349. package/test-projects/python-cli/models/task.py +0 -19
  350. package/test-projects/python-cli/models/task_repository.py +0 -44
  351. package/test-projects/rails-app/.ai-dev/ai_context.md +0 -94
  352. package/test-projects/rails-app/.ai-dev/ai_rules.md +0 -47
  353. package/test-projects/rails-app/.ai-dev/architecture.md +0 -49
  354. package/test-projects/rails-app/.ai-dev/cache.json +0 -193
  355. package/test-projects/rails-app/.ai-dev/context/features/app.json +0 -24
  356. package/test-projects/rails-app/.ai-dev/context/features/config.json +0 -13
  357. package/test-projects/rails-app/.ai-dev/context/flows/application.json +0 -9
  358. package/test-projects/rails-app/.ai-dev/context/flows/application_.json +0 -9
  359. package/test-projects/rails-app/.ai-dev/context/flows/comments.json +0 -11
  360. package/test-projects/rails-app/.ai-dev/context/flows/comments_.json +0 -11
  361. package/test-projects/rails-app/.ai-dev/context/flows/posts.json +0 -11
  362. package/test-projects/rails-app/.ai-dev/context/flows/posts_.json +0 -11
  363. package/test-projects/rails-app/.ai-dev/context/flows/routes.json +0 -9
  364. package/test-projects/rails-app/.ai-dev/context/flows/users.json +0 -11
  365. package/test-projects/rails-app/.ai-dev/context/flows/users_.json +0 -11
  366. package/test-projects/rails-app/.ai-dev/conventions.md +0 -51
  367. package/test-projects/rails-app/.ai-dev/dependencies.json +0 -6
  368. package/test-projects/rails-app/.ai-dev/entrypoints.md +0 -4
  369. package/test-projects/rails-app/.ai-dev/files.json +0 -239
  370. package/test-projects/rails-app/.ai-dev/graph/knowledge-graph.json +0 -130
  371. package/test-projects/rails-app/.ai-dev/graph/module-graph.json +0 -27
  372. package/test-projects/rails-app/.ai-dev/graph/symbol-graph.json +0 -5
  373. package/test-projects/rails-app/.ai-dev/graph/symbol-references.json +0 -1
  374. package/test-projects/rails-app/.ai-dev/index-state.json +0 -336
  375. package/test-projects/rails-app/.ai-dev/modules.json +0 -26
  376. package/test-projects/rails-app/.ai-dev/project.json +0 -22
  377. package/test-projects/rails-app/.ai-dev/repo_map.json +0 -486
  378. package/test-projects/rails-app/.ai-dev/repo_map.md +0 -117
  379. package/test-projects/rails-app/.ai-dev/schema.json +0 -5
  380. package/test-projects/rails-app/.ai-dev/summary.md +0 -13
  381. package/test-projects/rails-app/.ai-dev/symbols.json +0 -1
  382. package/test-projects/rails-app/.ai-dev/tech_stack.md +0 -32
  383. package/test-projects/rails-app/.ai-dev/tools.json +0 -10
  384. package/test-projects/rails-app/Gemfile +0 -38
  385. package/test-projects/rails-app/README.md +0 -140
  386. package/test-projects/rails-app/Rakefile +0 -8
  387. package/test-projects/rails-app/app/controllers/api/comments_controller.rb +0 -75
  388. package/test-projects/rails-app/app/controllers/api/posts_controller.rb +0 -68
  389. package/test-projects/rails-app/app/controllers/api/users_controller.rb +0 -54
  390. package/test-projects/rails-app/app/controllers/application_controller.rb +0 -31
  391. package/test-projects/rails-app/app/models/comment.rb +0 -34
  392. package/test-projects/rails-app/app/models/post.rb +0 -36
  393. package/test-projects/rails-app/app/models/user.rb +0 -28
  394. package/test-projects/rails-app/app/services/post_service.rb +0 -92
  395. package/test-projects/rails-app/app/services/user_service.rb +0 -76
  396. package/test-projects/rails-app/config/application.rb +0 -27
  397. package/test-projects/rails-app/config/environment.rb +0 -7
  398. package/test-projects/rails-app/config/routes.rb +0 -15
  399. package/test-projects/react-app/.ai-dev/ai_context.md +0 -96
  400. package/test-projects/react-app/.ai-dev/architecture.md +0 -39
  401. package/test-projects/react-app/.ai-dev/cache.json +0 -153
  402. package/test-projects/react-app/.ai-dev/context/features/src.json +0 -18
  403. package/test-projects/react-app/.ai-dev/context/flows/UsersPage.json +0 -14
  404. package/test-projects/react-app/.ai-dev/context/flows/dashboard.json +0 -9
  405. package/test-projects/react-app/.ai-dev/context/flows/login.json +0 -9
  406. package/test-projects/react-app/.ai-dev/context/flows/users.json +0 -9
  407. package/test-projects/react-app/.ai-dev/dependencies.json +0 -128
  408. package/test-projects/react-app/.ai-dev/entrypoints.md +0 -4
  409. package/test-projects/react-app/.ai-dev/files.json +0 -189
  410. package/test-projects/react-app/.ai-dev/graph/knowledge-graph.json +0 -112
  411. package/test-projects/react-app/.ai-dev/graph/module-graph.json +0 -31
  412. package/test-projects/react-app/.ai-dev/graph/symbol-graph.json +0 -868
  413. package/test-projects/react-app/.ai-dev/graph/symbol-references.json +0 -31
  414. package/test-projects/react-app/.ai-dev/index-state.json +0 -266
  415. package/test-projects/react-app/.ai-dev/modules.json +0 -17
  416. package/test-projects/react-app/.ai-dev/project.json +0 -16
  417. package/test-projects/react-app/.ai-dev/repo_map.json +0 -391
  418. package/test-projects/react-app/.ai-dev/repo_map.md +0 -94
  419. package/test-projects/react-app/.ai-dev/schema.json +0 -5
  420. package/test-projects/react-app/.ai-dev/summary.md +0 -13
  421. package/test-projects/react-app/.ai-dev/symbols.json +0 -1
  422. package/test-projects/react-app/.ai-dev/tools.json +0 -10
  423. package/test-projects/react-app/package.json +0 -16
  424. package/test-projects/react-app/src/App.tsx +0 -21
  425. package/test-projects/react-app/src/context/AuthContext.tsx +0 -41
  426. package/test-projects/react-app/src/hooks/useAuth.ts +0 -10
  427. package/test-projects/react-app/src/main.tsx +0 -10
  428. package/test-projects/react-app/src/pages/DashboardPage.tsx +0 -17
  429. package/test-projects/react-app/src/pages/LoginPage.tsx +0 -41
  430. package/test-projects/react-app/src/pages/UsersPage.tsx +0 -36
  431. package/test-projects/react-app/src/services/userService.ts +0 -37
  432. package/test-projects/salesforce-cli/.ai-dev/ai_context.md +0 -89
  433. package/test-projects/salesforce-cli/.ai-dev/ai_rules.md +0 -47
  434. package/test-projects/salesforce-cli/.ai-dev/architecture.md +0 -39
  435. package/test-projects/salesforce-cli/.ai-dev/cache.json +0 -125
  436. package/test-projects/salesforce-cli/.ai-dev/context/features/force-app.json +0 -14
  437. package/test-projects/salesforce-cli/.ai-dev/context/flows/account.json +0 -9
  438. package/test-projects/salesforce-cli/.ai-dev/context/flows/opportunity.json +0 -9
  439. package/test-projects/salesforce-cli/.ai-dev/conventions.md +0 -51
  440. package/test-projects/salesforce-cli/.ai-dev/dependencies.json +0 -6
  441. package/test-projects/salesforce-cli/.ai-dev/entrypoints.md +0 -4
  442. package/test-projects/salesforce-cli/.ai-dev/files.json +0 -154
  443. package/test-projects/salesforce-cli/.ai-dev/graph/knowledge-graph.json +0 -64
  444. package/test-projects/salesforce-cli/.ai-dev/graph/module-graph.json +0 -13
  445. package/test-projects/salesforce-cli/.ai-dev/graph/symbol-graph.json +0 -148
  446. package/test-projects/salesforce-cli/.ai-dev/graph/symbol-references.json +0 -1
  447. package/test-projects/salesforce-cli/.ai-dev/index-state.json +0 -217
  448. package/test-projects/salesforce-cli/.ai-dev/modules.json +0 -12
  449. package/test-projects/salesforce-cli/.ai-dev/project.json +0 -14
  450. package/test-projects/salesforce-cli/.ai-dev/repo_map.json +0 -328
  451. package/test-projects/salesforce-cli/.ai-dev/repo_map.md +0 -80
  452. package/test-projects/salesforce-cli/.ai-dev/schema.json +0 -5
  453. package/test-projects/salesforce-cli/.ai-dev/summary.md +0 -13
  454. package/test-projects/salesforce-cli/.ai-dev/symbols.json +0 -1
  455. package/test-projects/salesforce-cli/.ai-dev/tech_stack.md +0 -31
  456. package/test-projects/salesforce-cli/.ai-dev/tools.json +0 -10
  457. package/test-projects/salesforce-cli/.forceignore +0 -27
  458. package/test-projects/salesforce-cli/force-app/main/default/classes/AccountController.cls +0 -24
  459. package/test-projects/salesforce-cli/force-app/main/default/classes/OpportunityController.cls +0 -25
  460. package/test-projects/salesforce-cli/force-app/main/default/objects/Project__c.object.xml +0 -45
  461. package/test-projects/salesforce-cli/force-app/main/default/triggers/AccountTrigger.trigger +0 -33
  462. package/test-projects/salesforce-cli/sfdx-project.json +0 -11
  463. package/test-projects/spring-boot-app/.ai-dev/ai_context.md +0 -91
  464. package/test-projects/spring-boot-app/.ai-dev/ai_rules.md +0 -48
  465. package/test-projects/spring-boot-app/.ai-dev/architecture.md +0 -39
  466. package/test-projects/spring-boot-app/.ai-dev/cache.json +0 -173
  467. package/test-projects/spring-boot-app/.ai-dev/context/features/src.json +0 -26
  468. package/test-projects/spring-boot-app/.ai-dev/context/flows/PostController.json +0 -19
  469. package/test-projects/spring-boot-app/.ai-dev/context/flows/UserController.json +0 -19
  470. package/test-projects/spring-boot-app/.ai-dev/context/flows/comment.json +0 -11
  471. package/test-projects/spring-boot-app/.ai-dev/context/flows/post.json +0 -14
  472. package/test-projects/spring-boot-app/.ai-dev/context/flows/user.json +0 -14
  473. package/test-projects/spring-boot-app/.ai-dev/conventions.md +0 -52
  474. package/test-projects/spring-boot-app/.ai-dev/dependencies.json +0 -326
  475. package/test-projects/spring-boot-app/.ai-dev/entrypoints.md +0 -4
  476. package/test-projects/spring-boot-app/.ai-dev/files.json +0 -214
  477. package/test-projects/spring-boot-app/.ai-dev/graph/knowledge-graph.json +0 -231
  478. package/test-projects/spring-boot-app/.ai-dev/graph/module-graph.json +0 -22
  479. package/test-projects/spring-boot-app/.ai-dev/graph/symbol-graph.json +0 -794
  480. package/test-projects/spring-boot-app/.ai-dev/graph/symbol-references.json +0 -70
  481. package/test-projects/spring-boot-app/.ai-dev/index-state.json +0 -301
  482. package/test-projects/spring-boot-app/.ai-dev/modules.json +0 -21
  483. package/test-projects/spring-boot-app/.ai-dev/project.json +0 -17
  484. package/test-projects/spring-boot-app/.ai-dev/repo_map.json +0 -461
  485. package/test-projects/spring-boot-app/.ai-dev/repo_map.md +0 -109
  486. package/test-projects/spring-boot-app/.ai-dev/schema.json +0 -5
  487. package/test-projects/spring-boot-app/.ai-dev/summary.md +0 -12
  488. package/test-projects/spring-boot-app/.ai-dev/symbols.json +0 -1
  489. package/test-projects/spring-boot-app/.ai-dev/tech_stack.md +0 -32
  490. package/test-projects/spring-boot-app/.ai-dev/tools.json +0 -10
  491. package/test-projects/spring-boot-app/.classpath +0 -57
  492. package/test-projects/spring-boot-app/.factorypath +0 -69
  493. package/test-projects/spring-boot-app/.project +0 -34
  494. package/test-projects/spring-boot-app/.settings/org.eclipse.core.resources.prefs +0 -4
  495. package/test-projects/spring-boot-app/.settings/org.eclipse.jdt.apt.core.prefs +0 -4
  496. package/test-projects/spring-boot-app/.settings/org.eclipse.jdt.core.prefs +0 -10
  497. package/test-projects/spring-boot-app/.settings/org.eclipse.m2e.core.prefs +0 -4
  498. package/test-projects/spring-boot-app/README.md +0 -122
  499. package/test-projects/spring-boot-app/pom.xml +0 -79
  500. package/test-projects/spring-boot-app/src/main/java/com/example/demo/DemoApplication.java +0 -12
  501. package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/CommentController.java +0 -89
  502. package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/PostController.java +0 -92
  503. package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/UserController.java +0 -84
  504. package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/Comment.java +0 -38
  505. package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/Post.java +0 -56
  506. package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/User.java +0 -44
  507. package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/CommentRepository.java +0 -21
  508. package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/PostRepository.java +0 -18
  509. package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/UserRepository.java +0 -15
  510. package/test-projects/spring-boot-app/src/main/java/com/example/demo/services/PostService.java +0 -83
  511. package/test-projects/spring-boot-app/src/main/java/com/example/demo/services/UserService.java +0 -62
  512. package/test-projects/spring-boot-app/src/main/resources/application.properties +0 -22
  513. package/test-projects/spring-boot-app/target/classes/com/example/demo/DemoApplication.class +0 -0
  514. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController$CommentCreateRequest.class +0 -0
  515. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController$CommentUpdateRequest.class +0 -0
  516. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController.class +0 -0
  517. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController$PostCreateRequest.class +0 -0
  518. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController$PostUpdateRequest.class +0 -0
  519. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController.class +0 -0
  520. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController$UserCreateRequest.class +0 -0
  521. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController$UserUpdateRequest.class +0 -0
  522. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController.class +0 -0
  523. package/test-projects/spring-boot-app/target/classes/com/example/demo/models/Comment.class +0 -0
  524. package/test-projects/spring-boot-app/target/classes/com/example/demo/models/Post.class +0 -0
  525. package/test-projects/spring-boot-app/target/classes/com/example/demo/models/User.class +0 -0
  526. package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/CommentRepository.class +0 -0
  527. package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/PostRepository.class +0 -0
  528. package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/UserRepository.class +0 -0
  529. package/test-projects/spring-boot-app/target/classes/com/example/demo/services/PostService.class +0 -0
  530. package/test-projects/spring-boot-app/target/classes/com/example/demo/services/UserService.class +0 -0
  531. package/tests/e2e/run-e2e.sh +0 -88
  532. /package/{test-projects/django-app/.ai-dev → ai-context}/tools.json +0 -0
@@ -0,0 +1,1125 @@
1
+ import { describe, it, expect, beforeAll } from "vitest";
2
+ import fs from "fs";
3
+ import path from "path";
4
+
5
+ const SALESFORCE_ENTERPRISE_PATH = path.join(process.cwd(), "test-projects/salesforce-enterprise");
6
+
7
+ describe("Salesforce SFDX Metadata and Integration Tests", () => {
8
+
9
+ // =========================================================================
10
+ // INTEGRATION TESTS - SFDX Project Detection
11
+ // =========================================================================
12
+
13
+ describe("Integration: SFDX Project Detection", () => {
14
+
15
+ it("should detect sfdx-project.json in project root", () => {
16
+ const sfdxProjectPath = path.join(SALESFORCE_ENTERPRISE_PATH, "sfdx-project.json");
17
+ expect(fs.existsSync(sfdxProjectPath)).toBe(true);
18
+ });
19
+
20
+ it("should detect package.xml in force-app/main/default", () => {
21
+ const packageXmlPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/package.xml");
22
+ expect(fs.existsSync(packageXmlPath)).toBe(true);
23
+ });
24
+
25
+ it("should detect Admin profile", () => {
26
+ const profilePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/profiles/Admin.profile-meta.xml");
27
+ expect(fs.existsSync(profilePath)).toBe(true);
28
+ });
29
+
30
+ it("should detect SalesRepresentative permission set", () => {
31
+ const permSetPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/permissionsets/SalesRepresentative.permissionset-meta.xml");
32
+ expect(fs.existsSync(permSetPath)).toBe(true);
33
+ });
34
+
35
+ it("should have complete SFDX project structure", () => {
36
+ // Verify key directories exist
37
+ expect(fs.existsSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app"))).toBe(true);
38
+ expect(fs.existsSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main"))).toBe(true);
39
+ expect(fs.existsSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default"))).toBe(true);
40
+ expect(fs.existsSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/classes"))).toBe(true);
41
+ expect(fs.existsSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/triggers"))).toBe(true);
42
+ expect(fs.existsSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc"))).toBe(true);
43
+ expect(fs.existsSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows"))).toBe(true);
44
+ expect(fs.existsSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/objects"))).toBe(true);
45
+ expect(fs.existsSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/profiles"))).toBe(true);
46
+ expect(fs.existsSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/permissionsets"))).toBe(true);
47
+ });
48
+ });
49
+
50
+ // =========================================================================
51
+ // SFDX-PROJECT.JSON DETECTION AND PARSING
52
+ // =========================================================================
53
+
54
+ describe("sfdx-project.json Detection and Parsing", () => {
55
+ let sfdxProjectContent: string;
56
+ let sfdxProjectJson: Record<string, unknown>;
57
+
58
+ beforeAll(() => {
59
+ const sfdxProjectPath = path.join(SALESFORCE_ENTERPRISE_PATH, "sfdx-project.json");
60
+ sfdxProjectContent = fs.readFileSync(sfdxProjectPath, "utf-8");
61
+ sfdxProjectJson = JSON.parse(sfdxProjectContent);
62
+ });
63
+
64
+ describe("File Detection", () => {
65
+ it("should be valid JSON", () => {
66
+ expect(() => JSON.parse(sfdxProjectContent)).not.toThrow();
67
+ });
68
+
69
+ it("should have correct XML declaration", () => {
70
+ // sfdx-project.json doesn't have XML declaration, it's pure JSON
71
+ expect(sfdxProjectContent.trim().startsWith("{")).toBe(true);
72
+ });
73
+ });
74
+
75
+ describe("packageDirectories Verification", () => {
76
+ it("should have packageDirectories array", () => {
77
+ expect(sfdxProjectJson).toHaveProperty("packageDirectories");
78
+ expect(Array.isArray(sfdxProjectJson.packageDirectories)).toBe(true);
79
+ });
80
+
81
+ it("should have force-app as package path", () => {
82
+ const packageDirs = sfdxProjectJson.packageDirectories as Array<Record<string, unknown>>;
83
+ expect(packageDirs[0]).toHaveProperty("path", "force-app");
84
+ });
85
+
86
+ it("should have default=true for force-app package", () => {
87
+ const packageDirs = sfdxProjectJson.packageDirectories as Array<Record<string, unknown>>;
88
+ expect(packageDirs[0]).toHaveProperty("default", true);
89
+ });
90
+
91
+ it("should have package name SalesforceEnterprise", () => {
92
+ const packageDirs = sfdxProjectJson.packageDirectories as Array<Record<string, unknown>>;
93
+ expect(packageDirs[0]).toHaveProperty("package", "SalesforceEnterprise");
94
+ });
95
+
96
+ it("should have versionName", () => {
97
+ const packageDirs = sfdxProjectJson.packageDirectories as Array<Record<string, unknown>>;
98
+ expect(packageDirs[0]).toHaveProperty("versionName", "ver 1.0");
99
+ });
100
+
101
+ it("should have versionNumber", () => {
102
+ const packageDirs = sfdxProjectJson.packageDirectories as Array<Record<string, unknown>>;
103
+ expect(packageDirs[0]).toHaveProperty("versionNumber", "1.0.0.NEXT");
104
+ });
105
+ });
106
+
107
+ describe("Project Properties Verification", () => {
108
+ it("should have name as SalesforceEnterprise", () => {
109
+ expect(sfdxProjectJson).toHaveProperty("name", "SalesforceEnterprise");
110
+ });
111
+
112
+ it("should have namespace as empty string", () => {
113
+ expect(sfdxProjectJson).toHaveProperty("namespace", "");
114
+ });
115
+
116
+ it("should have sfdcLoginUrl as https://login.salesforce.com", () => {
117
+ expect(sfdxProjectJson).toHaveProperty("sfdcLoginUrl", "https://login.salesforce.com");
118
+ });
119
+
120
+ it("should have singlePackage=false", () => {
121
+ expect(sfdxProjectJson).toHaveProperty("singlePackage", false);
122
+ });
123
+
124
+ it("should have sourceApiVersion as 59.0", () => {
125
+ expect(sfdxProjectJson).toHaveProperty("sourceApiVersion", "59.0");
126
+ });
127
+ });
128
+
129
+ describe("Complete JSON Structure", () => {
130
+ it("should have all required properties", () => {
131
+ expect(sfdxProjectJson).toHaveProperty("packageDirectories");
132
+ expect(sfdxProjectJson).toHaveProperty("name");
133
+ expect(sfdxProjectJson).toHaveProperty("namespace");
134
+ expect(sfdxProjectJson).toHaveProperty("sfdcLoginUrl");
135
+ expect(sfdxProjectJson).toHaveProperty("singlePackage");
136
+ expect(sfdxProjectJson).toHaveProperty("sourceApiVersion");
137
+ });
138
+
139
+ it("should match expected structure", () => {
140
+ expect(sfdxProjectContent).toContain('"packageDirectories"');
141
+ expect(sfdxProjectContent).toContain('"path": "force-app"');
142
+ expect(sfdxProjectContent).toContain('"default": true');
143
+ expect(sfdxProjectContent).toContain('"package": "SalesforceEnterprise"');
144
+ expect(sfdxProjectContent).toContain('"versionName": "ver 1.0"');
145
+ expect(sfdxProjectContent).toContain('"versionNumber": "1.0.0.NEXT"');
146
+ expect(sfdxProjectContent).toContain('"name": "SalesforceEnterprise"');
147
+ expect(sfdxProjectContent).toContain('"namespace": ""');
148
+ expect(sfdxProjectContent).toContain('"sfdcLoginUrl": "https://login.salesforce.com"');
149
+ expect(sfdxProjectContent).toContain('"singlePackage": false');
150
+ expect(sfdxProjectContent).toContain('"sourceApiVersion": "59.0"');
151
+ });
152
+ });
153
+ });
154
+
155
+ // =========================================================================
156
+ // PACKAGE.XML DETECTION AND COMPONENT LISTING
157
+ // =========================================================================
158
+
159
+ describe("package.xml Detection and Component Listing", () => {
160
+ let packageXmlContent: string;
161
+
162
+ beforeAll(() => {
163
+ const packageXmlPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/package.xml");
164
+ packageXmlContent = fs.readFileSync(packageXmlPath, "utf-8");
165
+ });
166
+
167
+ describe("File Detection", () => {
168
+ it("should have correct XML declaration", () => {
169
+ expect(packageXmlContent).toContain('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>');
170
+ });
171
+
172
+ it("should have Package as root element", () => {
173
+ expect(packageXmlContent).toContain("<Package xmlns=");
174
+ expect(packageXmlContent).toContain("http://soap.sforce.com/2006/04/metadata");
175
+ });
176
+ });
177
+
178
+ describe("Component Types Detection", () => {
179
+ it("should have ApexClass type with 9 members", () => {
180
+ expect(packageXmlContent).toContain("<name>ApexClass</name>");
181
+
182
+ // Verify all 9 ApexClass members
183
+ const apexClasses = [
184
+ "AccountController",
185
+ "AccountControllerTest",
186
+ "OpportunityBatch",
187
+ "OpportunityBatchTest",
188
+ "OpportunityTriggerHandler",
189
+ "OpportunityTriggerHelper",
190
+ "Logger",
191
+ "TriggerManagement",
192
+ "SessionManagement"
193
+ ];
194
+
195
+ for (const apexClass of apexClasses) {
196
+ expect(packageXmlContent).toContain(`<members>${apexClass}</members>`);
197
+ }
198
+ });
199
+
200
+ it("should have ApexTrigger type with 1 member", () => {
201
+ expect(packageXmlContent).toContain("<name>ApexTrigger</name>");
202
+ expect(packageXmlContent).toContain("<members>OpportunityTrigger</members>");
203
+ });
204
+
205
+ it("should have LightningComponentBundle type with 2 members", () => {
206
+ expect(packageXmlContent).toContain("<name>LightningComponentBundle</name>");
207
+ expect(packageXmlContent).toContain("<members>accountList</members>");
208
+ expect(packageXmlContent).toContain("<members>opportunityCard</members>");
209
+ });
210
+
211
+ it("should have Flow type with 2 members", () => {
212
+ expect(packageXmlContent).toContain("<name>Flow</name>");
213
+ expect(packageXmlContent).toContain("<members>Account_Create</members>");
214
+ expect(packageXmlContent).toContain("<members>Opportunity_Update</members>");
215
+ });
216
+
217
+ it("should have CustomObject type with 1 member", () => {
218
+ expect(packageXmlContent).toContain("<name>CustomObject</name>");
219
+ expect(packageXmlContent).toContain("<members>CustomObject__c</members>");
220
+ });
221
+
222
+ it("should have Profile type with 1 member", () => {
223
+ expect(packageXmlContent).toContain("<name>Profile</name>");
224
+ expect(packageXmlContent).toContain("<members>Admin</members>");
225
+ });
226
+
227
+ it("should have PermissionSet type with 1 member", () => {
228
+ expect(packageXmlContent).toContain("<name>PermissionSet</name>");
229
+ expect(packageXmlContent).toContain("<members>SalesRepresentative</members>");
230
+ });
231
+ });
232
+
233
+ describe("Component Count Verification", () => {
234
+ it("should have 7 type definitions", () => {
235
+ const typeMatches = packageXmlContent.match(/<name>\w+<\/name>/g);
236
+ expect(typeMatches).toHaveLength(7);
237
+ });
238
+
239
+ it("should have correct component counts", () => {
240
+ // ApexClass: 9 members
241
+ expect(packageXmlContent.match(/<name>ApexClass<\/name>/g)).toHaveLength(1);
242
+
243
+ // ApexTrigger: 1 member
244
+ expect(packageXmlContent.match(/<name>ApexTrigger<\/name>/g)).toHaveLength(1);
245
+
246
+ // LightningComponentBundle: 2 members
247
+ expect(packageXmlContent.match(/<name>LightningComponentBundle<\/name>/g)).toHaveLength(1);
248
+
249
+ // Flow: 2 members
250
+ expect(packageXmlContent.match(/<name>Flow<\/name>/g)).toHaveLength(1);
251
+
252
+ // CustomObject: 1 member
253
+ expect(packageXmlContent.match(/<name>CustomObject<\/name>/g)).toHaveLength(1);
254
+
255
+ // Profile: 1 member
256
+ expect(packageXmlContent.match(/<name>Profile<\/name>/g)).toHaveLength(1);
257
+
258
+ // PermissionSet: 1 member
259
+ expect(packageXmlContent.match(/<name>PermissionSet<\/name>/g)).toHaveLength(1);
260
+ });
261
+
262
+ it("should have version 59.0", () => {
263
+ expect(packageXmlContent).toContain("<version>59.0</version>");
264
+ });
265
+ });
266
+
267
+ describe("Package XML Structure", () => {
268
+ it("should contain all types sections", () => {
269
+ expect(packageXmlContent).toContain("<types>");
270
+ expect(packageXmlContent).toContain("</types>");
271
+ });
272
+
273
+ it("should have types in correct order", () => {
274
+ const apexClassIdx = packageXmlContent.indexOf("<name>ApexClass</name>");
275
+ const apexTriggerIdx = packageXmlContent.indexOf("<name>ApexTrigger</name>");
276
+ const lwcIdx = packageXmlContent.indexOf("<name>LightningComponentBundle</name>");
277
+ const flowIdx = packageXmlContent.indexOf("<name>Flow</name>");
278
+ const customObjIdx = packageXmlContent.indexOf("<name>CustomObject</name>");
279
+ const profileIdx = packageXmlContent.indexOf("<name>Profile</name>");
280
+ const permSetIdx = packageXmlContent.indexOf("<name>PermissionSet</name>");
281
+
282
+ expect(apexClassIdx).toBeLessThan(apexTriggerIdx);
283
+ expect(apexTriggerIdx).toBeLessThan(lwcIdx);
284
+ expect(lwcIdx).toBeLessThan(flowIdx);
285
+ expect(flowIdx).toBeLessThan(customObjIdx);
286
+ expect(customObjIdx).toBeLessThan(profileIdx);
287
+ expect(profileIdx).toBeLessThan(permSetIdx);
288
+ });
289
+ });
290
+ });
291
+
292
+ // =========================================================================
293
+ // PROFILE METADATA (Admin.profile-meta.xml)
294
+ // =========================================================================
295
+
296
+ describe("Profile Metadata (Admin.profile-meta.xml)", () => {
297
+ let profileContent: string;
298
+
299
+ beforeAll(() => {
300
+ const profilePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/profiles/Admin.profile-meta.xml");
301
+ profileContent = fs.readFileSync(profilePath, "utf-8");
302
+ });
303
+
304
+ describe("File Detection", () => {
305
+ it("should have correct XML declaration", () => {
306
+ expect(profileContent).toContain('<?xml version="1.0" encoding="UTF-8"?>');
307
+ });
308
+
309
+ it("should have Profile as root element", () => {
310
+ expect(profileContent).toContain("<Profile xmlns=");
311
+ expect(profileContent).toContain("http://soap.sforce.com/2006/04/metadata");
312
+ });
313
+
314
+ it("should have custom=false", () => {
315
+ expect(profileContent).toContain("<custom>false</custom>");
316
+ });
317
+ });
318
+
319
+ describe("User License", () => {
320
+ it("should have userLicense as Salesforce", () => {
321
+ expect(profileContent).toContain("<userLicense>Salesforce</userLicense>");
322
+ });
323
+ });
324
+
325
+ describe("Field Permissions", () => {
326
+ it("should have 12 fieldPermissions entries", () => {
327
+ const fieldPermissionMatches = profileContent.match(/<fieldPermissions>/g);
328
+ expect(fieldPermissionMatches).toHaveLength(12);
329
+ });
330
+
331
+ it("should have field permissions for Account.Active__c", () => {
332
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Active__c<\/field>[\s\S]*?<\/fieldPermissions>/);
333
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Active__c<\/field>[\s\S]*?<readable>true<\/readable>[\s\S]*?<\/fieldPermissions>/);
334
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Active__c<\/field>[\s\S]*?<editable>true<\/editable>[\s\S]*?<\/fieldPermissions>/);
335
+ });
336
+
337
+ it("should have field permissions for Account.CustomerPriority__c", () => {
338
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.CustomerPriority__c<\/field>[\s\S]*?<\/fieldPermissions>/);
339
+ });
340
+
341
+ it("should have field permissions for Account.SLA__c", () => {
342
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.SLA__c<\/field>[\s\S]*?<\/fieldPermissions>/);
343
+ });
344
+
345
+ it("should have field permissions for Account.Total_Opportunity_Amount__c (readable only)", () => {
346
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Total_Opportunity_Amount__c<\/field>[\s\S]*?<readable>true<\/readable>[\s\S]*?<editable>false<\/editable>[\s\S]*?<\/fieldPermissions>/);
347
+ });
348
+
349
+ it("should have field permissions for Opportunity standard fields", () => {
350
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Opportunity\.Amount<\/field>[\s\S]*?<\/fieldPermissions>/);
351
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Opportunity\.LeadSource<\/field>[\s\S]*?<\/fieldPermissions>/);
352
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Opportunity\.Probability<\/field>[\s\S]*?<\/fieldPermissions>/);
353
+ });
354
+
355
+ it("should have field permissions for CustomObject__c fields", () => {
356
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>CustomObject__c\.Amount__c<\/field>[\s\S]*?<\/fieldPermissions>/);
357
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>CustomObject__c\.Category__c<\/field>[\s\S]*?<\/fieldPermissions>/);
358
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>CustomObject__c\.CustomAccount__c<\/field>[\s\S]*?<\/fieldPermissions>/);
359
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>CustomObject__c\.IsActive__c<\/field>[\s\S]*?<\/fieldPermissions>/);
360
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>CustomObject__c\.Stage__c<\/field>[\s\S]*?<\/fieldPermissions>/);
361
+ });
362
+ });
363
+
364
+ describe("Object Permissions", () => {
365
+ it("should have 3 objectPermissions entries", () => {
366
+ const objectPermissionMatches = profileContent.match(/<objectPermissions>/g);
367
+ expect(objectPermissionMatches).toHaveLength(3);
368
+ });
369
+
370
+ it("should have full access to Account", () => {
371
+ expect(profileContent).toMatch(/<objectPermissions>[\s\S]*?<object>Account<\/object>[\s\S]*?<allowCreate>true<\/allowCreate>[\s\S]*?<allowDelete>true<\/allowDelete>[\s\S]*?<allowEdit>true<\/allowEdit>[\s\S]*?<allowRead>true<\/allowRead>[\s\S]*?<modifyAllRecords>true<\/modifyAllRecords>[\s\S]*?<\/objectPermissions>/);
372
+ });
373
+
374
+ it("should have full access to Opportunity", () => {
375
+ expect(profileContent).toMatch(/<objectPermissions>[\s\S]*?<object>Opportunity<\/object>[\s\S]*?<allowCreate>true<\/allowCreate>[\s\S]*?<allowDelete>true<\/allowDelete>[\s\S]*?<allowEdit>true<\/allowEdit>[\s\S]*?<allowRead>true<\/allowRead>[\s\S]*?<modifyAllRecords>true<\/modifyAllRecords>[\s\S]*?<\/objectPermissions>/);
376
+ });
377
+
378
+ it("should have full access to CustomObject__c", () => {
379
+ const customObjPermMatch = profileContent.match(/<objectPermissions>[\s\S]*?<object>CustomObject__c<\/object>[\s\S]*?<\/objectPermissions>/);
380
+ expect(customObjPermMatch).toBeTruthy();
381
+ const customObjSection = customObjPermMatch?.[0] || "";
382
+ expect(customObjSection).toContain("<allowCreate>true</allowCreate>");
383
+ expect(customObjSection).toContain("<allowDelete>true</allowDelete>");
384
+ expect(customObjSection).toContain("<allowEdit>true</allowEdit>");
385
+ expect(customObjSection).toContain("<allowRead>true</allowRead>");
386
+ expect(customObjSection).toContain("<modifyAllRecords>true</modifyAllRecords>");
387
+ });
388
+ });
389
+
390
+ describe("Class Accesses", () => {
391
+ it("should have 5 classAccesses entries", () => {
392
+ const classAccessMatches = profileContent.match(/<classAccesses>/g);
393
+ expect(classAccessMatches).toHaveLength(5);
394
+ });
395
+
396
+ it("should enable AccountController", () => {
397
+ expect(profileContent).toMatch(/<classAccesses>[\s\S]*?<apexClass>AccountController<\/apexClass>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/classAccesses>/);
398
+ });
399
+
400
+ it("should enable OpportunityBatch", () => {
401
+ expect(profileContent).toMatch(/<classAccesses>[\s\S]*?<apexClass>OpportunityBatch<\/apexClass>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/classAccesses>/);
402
+ });
403
+
404
+ it("should enable OpportunityTriggerHandler", () => {
405
+ expect(profileContent).toMatch(/<classAccesses>[\s\S]*?<apexClass>OpportunityTriggerHandler<\/apexClass>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/classAccesses>/);
406
+ });
407
+
408
+ it("should enable Logger", () => {
409
+ expect(profileContent).toMatch(/<classAccesses>[\s\S]*?<apexClass>Logger<\/apexClass>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/classAccesses>/);
410
+ });
411
+
412
+ it("should enable TriggerManagement", () => {
413
+ expect(profileContent).toMatch(/<classAccesses>[\s\S]*?<apexClass>TriggerManagement<\/apexClass>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/classAccesses>/);
414
+ });
415
+ });
416
+
417
+ describe("Flow Accesses", () => {
418
+ it("should have 2 flowAccesses entries", () => {
419
+ const flowAccessMatches = profileContent.match(/<flowAccesses>/g);
420
+ expect(flowAccessMatches).toHaveLength(2);
421
+ });
422
+
423
+ it("should enable Account_Create flow", () => {
424
+ expect(profileContent).toMatch(/<flowAccesses>[\s\S]*?<flow>Account_Create<\/flow>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/flowAccesses>/);
425
+ });
426
+
427
+ it("should enable Opportunity_Update flow", () => {
428
+ expect(profileContent).toMatch(/<flowAccesses>[\s\S]*?<flow>Opportunity_Update<\/flow>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/flowAccesses>/);
429
+ });
430
+ });
431
+
432
+ describe("Layout Assignments", () => {
433
+ it("should have 3 layoutAssignments", () => {
434
+ const layoutMatches = profileContent.match(/<layoutAssignments>/g);
435
+ expect(layoutMatches).toHaveLength(3);
436
+ });
437
+
438
+ it("should have Account layout assignment", () => {
439
+ expect(profileContent).toContain("<layout>Account-Account Layout</layout>");
440
+ });
441
+
442
+ it("should have Opportunity layout assignment", () => {
443
+ expect(profileContent).toContain("<layout>Opportunity-Opportunity Layout</layout>");
444
+ });
445
+
446
+ it("should have CustomObject__c layout assignment", () => {
447
+ expect(profileContent).toContain("<layout>CustomObject__c-Custom Object Layout</layout>");
448
+ });
449
+ });
450
+
451
+ describe("Tab Visibilities", () => {
452
+ it("should have 3 tabVisibilities entries", () => {
453
+ const tabMatches = profileContent.match(/<tabVisibilities>/g);
454
+ expect(tabMatches).toHaveLength(3);
455
+ });
456
+
457
+ it("should have Account tab visibility", () => {
458
+ expect(profileContent).toMatch(/<tabVisibilities>[\s\S]*?<tab>standard-Account<\/tab>[\s\S]*?<visibility>Available<\/visibility>[\s\S]*?<\/tabVisibilities>/);
459
+ });
460
+
461
+ it("should have Opportunity tab visibility", () => {
462
+ expect(profileContent).toMatch(/<tabVisibilities>[\s\S]*?<tab>standard-Opportunity<\/tab>[\s\S]*?<visibility>Available<\/visibility>[\s\S]*?<\/tabVisibilities>/);
463
+ });
464
+
465
+ it("should have CustomObject__c tab visibility", () => {
466
+ expect(profileContent).toMatch(/<tabVisibilities>[\s\S]*?<tab>CustomObject__c<\/tab>[\s\S]*?<visibility>Available<\/visibility>[\s\S]*?<\/tabVisibilities>/);
467
+ });
468
+ });
469
+
470
+ describe("Record Type Visibilities", () => {
471
+ it("should have 2 recordTypeVisibilities entries", () => {
472
+ const recordTypeMatches = profileContent.match(/<recordTypeVisibilities>/g);
473
+ expect(recordTypeMatches).toHaveLength(2);
474
+ });
475
+
476
+ it("should have Customer_Account record type visibility", () => {
477
+ expect(profileContent).toMatch(/<recordTypeVisibilities>[\s\S]*?<recordType>Account\.Customer_Account<\/recordType>[\s\S]*?<default>true<\/default>[\s\S]*?<visible>true<\/visible>[\s\S]*?<\/recordTypeVisibilities>/);
478
+ });
479
+
480
+ it("should have PersonAccount record type visibility", () => {
481
+ expect(profileContent).toMatch(/<recordTypeVisibilities>[\s\S]*?<recordType>Account\.PersonAccount<\/recordType>[\s\S]*?<default>false<\/default>[\s\S]*?<visible>false<\/visible>[\s\S]*?<\/recordTypeVisibilities>/);
482
+ });
483
+ });
484
+ });
485
+
486
+ // =========================================================================
487
+ // PERMISSION SET METADATA (SalesRepresentative.permissionset-meta.xml)
488
+ // =========================================================================
489
+
490
+ describe("PermissionSet Metadata (SalesRepresentative.permissionset-meta.xml)", () => {
491
+ let permSetContent: string;
492
+
493
+ beforeAll(() => {
494
+ const permSetPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/permissionsets/SalesRepresentative.permissionset-meta.xml");
495
+ permSetContent = fs.readFileSync(permSetPath, "utf-8");
496
+ });
497
+
498
+ describe("File Detection", () => {
499
+ it("should have correct XML declaration", () => {
500
+ expect(permSetContent).toContain('<?xml version="1.0" encoding="UTF-8"?>');
501
+ });
502
+
503
+ it("should have PermissionSet as root element", () => {
504
+ expect(permSetContent).toContain("<PermissionSet xmlns=");
505
+ expect(permSetContent).toContain("http://salesforce.com/2006/04/metadata");
506
+ });
507
+
508
+ it("should have custom=false", () => {
509
+ expect(permSetContent).toContain("<custom>false</custom>");
510
+ });
511
+ });
512
+
513
+ describe("Label and Description", () => {
514
+ it("should have label Sales Representative", () => {
515
+ expect(permSetContent).toContain("<label>Sales Representative</label>");
516
+ });
517
+
518
+ it("should have description", () => {
519
+ expect(permSetContent).toContain("<description>Permission set for Sales Representatives</description>");
520
+ });
521
+ });
522
+
523
+ describe("Field Permissions", () => {
524
+ it("should have 15 fieldPermissions entries", () => {
525
+ const fieldPermissionMatches = permSetContent.match(/<fieldPermissions>/g);
526
+ expect(fieldPermissionMatches).toHaveLength(15);
527
+ });
528
+
529
+ it("should have field permissions for Account standard fields", () => {
530
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Active__c<\/field>[\s\S]*?<\/fieldPermissions>/);
531
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.AnnualRevenue<\/field>[\s\S]*?<\/fieldPermissions>/);
532
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.BillingCity<\/field>[\s\S]*?<\/fieldPermissions>/);
533
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.BillingState<\/field>[\s\S]*?<\/fieldPermissions>/);
534
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Industry<\/field>[\s\S]*?<\/fieldPermissions>/);
535
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Name<\/field>[\s\S]*?<\/fieldPermissions>/);
536
+ });
537
+
538
+ it("should have field permissions for Opportunity standard fields", () => {
539
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Opportunity\.Amount<\/field>[\s\S]*?<\/fieldPermissions>/);
540
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Opportunity\.CloseDate<\/field>[\s\S]*?<\/fieldPermissions>/);
541
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Opportunity\.Description<\/field>[\s\S]*?<\/fieldPermissions>/);
542
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Opportunity\.StageName<\/field>[\s\S]*?<\/fieldPermissions>/);
543
+ });
544
+
545
+ it("should have field permissions for CustomObject__c fields", () => {
546
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>CustomObject__c\.Amount__c<\/field>[\s\S]*?<\/fieldPermissions>/);
547
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>CustomObject__c\.Category__c<\/field>[\s\S]*?<\/fieldPermissions>/);
548
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>CustomObject__c\.IsActive__c<\/field>[\s\S]*?<\/fieldPermissions>/);
549
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>CustomObject__c\.Name__c<\/field>[\s\S]*?<\/fieldPermissions>/);
550
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>CustomObject__c\.Stage__c<\/field>[\s\S]*?<\/fieldPermissions>/);
551
+ });
552
+ });
553
+
554
+ describe("Object Permissions", () => {
555
+ it("should have 3 objectPermissions entries", () => {
556
+ const objectPermissionMatches = permSetContent.match(/<objectPermissions>/g);
557
+ expect(objectPermissionMatches).toHaveLength(3);
558
+ });
559
+
560
+ it("should have correct permissions for Account (limited)", () => {
561
+ expect(permSetContent).toMatch(/<objectPermissions>[\s\S]*?<object>Account<\/object>[\s\S]*?<allowCreate>true<\/allowCreate>[\s\S]*?<allowDelete>false<\/allowDelete>[\s\S]*?<allowEdit>true<\/allowEdit>[\s\S]*?<allowRead>true<\/allowRead>[\s\S]*?<modifyAllRecords>false<\/modifyAllRecords>[\s\S]*?<viewAllRecords>false<\/viewAllRecords>[\s\S]*?<\/objectPermissions>/);
562
+ });
563
+
564
+ it("should have correct permissions for Opportunity (limited)", () => {
565
+ expect(permSetContent).toMatch(/<objectPermissions>[\s\S]*?<object>Opportunity<\/object>[\s\S]*?<allowCreate>true<\/allowCreate>[\s\S]*?<allowDelete>false<\/allowDelete>[\s\S]*?<allowEdit>true<\/allowEdit>[\s\S]*?<allowRead>true<\/allowRead>[\s\S]*?<modifyAllRecords>false<\/modifyAllRecords>[\s\S]*?<viewAllRecords>false<\/viewAllRecords>[\s\S]*?<\/objectPermissions>/);
566
+ });
567
+
568
+ it("should have correct permissions for CustomObject__c (limited)", () => {
569
+ const customObjPermMatch = permSetContent.match(/<objectPermissions>[\s\S]*?<object>CustomObject__c<\/object>[\s\S]*?<\/objectPermissions>/);
570
+ expect(customObjPermMatch).toBeTruthy();
571
+ const customObjSection = customObjPermMatch?.[0] || "";
572
+ expect(customObjSection).toContain("<allowCreate>true</allowCreate>");
573
+ expect(customObjSection).toContain("<allowDelete>false</allowDelete>");
574
+ expect(customObjSection).toContain("<allowEdit>true</allowEdit>");
575
+ expect(customObjSection).toContain("<allowRead>true</allowRead>");
576
+ expect(customObjSection).toContain("<modifyAllRecords>false</modifyAllRecords>");
577
+ expect(customObjSection).toContain("<viewAllRecords>false</viewAllRecords>");
578
+ });
579
+ });
580
+
581
+ describe("Class Accesses", () => {
582
+ it("should have 1 classAccesses entry", () => {
583
+ const classAccessMatches = permSetContent.match(/<classAccesses>/g);
584
+ expect(classAccessMatches).toHaveLength(1);
585
+ });
586
+
587
+ it("should enable AccountController", () => {
588
+ expect(permSetContent).toMatch(/<classAccesses>[\s\S]*?<apexClass>AccountController<\/apexClass>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/classAccesses>/);
589
+ });
590
+ });
591
+
592
+ describe("Flow Accesses", () => {
593
+ it("should have 1 flowAccesses entry", () => {
594
+ const flowAccessMatches = permSetContent.match(/<flowAccesses>/g);
595
+ expect(flowAccessMatches).toHaveLength(1);
596
+ });
597
+
598
+ it("should enable Account_Create flow", () => {
599
+ expect(permSetContent).toMatch(/<flowAccesses>[\s\S]*?<flow>Account_Create<\/flow>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/flowAccesses>/);
600
+ });
601
+ });
602
+
603
+ describe("User Permissions", () => {
604
+ it("should have 2 userPermissions entries", () => {
605
+ const userPermMatches = permSetContent.match(/<userPermissions>/g);
606
+ expect(userPermMatches).toHaveLength(2);
607
+ });
608
+
609
+ it("should have ViewReadonlyFields permission enabled", () => {
610
+ expect(permSetContent).toMatch(/<userPermissions>[\s\S]*?<name>ViewReadonlyFields<\/name>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/userPermissions>/);
611
+ });
612
+
613
+ it("should have AllowViewKnowledge permission enabled", () => {
614
+ expect(permSetContent).toMatch(/<userPermissions>[\s\S]*?<name>AllowViewKnowledge<\/name>[\s\S]*?<enabled>true<\/enabled>[\s\S]*?<\/userPermissions>/);
615
+ });
616
+ });
617
+
618
+ describe("hasActivationRequired", () => {
619
+ it("should have hasActivationRequired as false", () => {
620
+ expect(permSetContent).toContain("<hasActivationRequired>false</hasActivationRequired>");
621
+ });
622
+ });
623
+ });
624
+
625
+ // =========================================================================
626
+ // FULL SFDX PROJECT INTEGRATION (END-TO-END)
627
+ // =========================================================================
628
+
629
+ describe("Full SFDX Project Integration (End-to-End)", () => {
630
+
631
+ describe("SFDX File Structure Completeness", () => {
632
+ it("should have all required SFDX files", () => {
633
+ const requiredFiles = [
634
+ "sfdx-project.json",
635
+ "force-app/main/default/package.xml",
636
+ "force-app/main/default/profiles/Admin.profile-meta.xml",
637
+ "force-app/main/default/permissionsets/SalesRepresentative.permissionset-meta.xml"
638
+ ];
639
+
640
+ for (const file of requiredFiles) {
641
+ const filePath = path.join(SALESFORCE_ENTERPRISE_PATH, file);
642
+ expect(fs.existsSync(filePath)).toBe(true);
643
+ }
644
+ });
645
+
646
+ it("should have matching sourceApiVersion across SFDX files", () => {
647
+ const sfdxProjectPath = path.join(SALESFORCE_ENTERPRISE_PATH, "sfdx-project.json");
648
+ const packageXmlPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/package.xml");
649
+
650
+ const sfdxProjectContent = fs.readFileSync(sfdxProjectPath, "utf-8");
651
+ const packageXmlContent = fs.readFileSync(packageXmlPath, "utf-8");
652
+
653
+ const sfdxProjectJson = JSON.parse(sfdxProjectContent);
654
+ expect(sfdxProjectJson.sourceApiVersion).toBe("59.0");
655
+ expect(packageXmlContent).toContain("<version>59.0</version>");
656
+ });
657
+ });
658
+
659
+ describe("Component Cross-Reference Validation", () => {
660
+ let sfdxProjectContent: string;
661
+ let packageXmlContent: string;
662
+ let profileContent: string;
663
+ let permSetContent: string;
664
+
665
+ beforeAll(() => {
666
+ sfdxProjectContent = fs.readFileSync(path.join(SALESFORCE_ENTERPRISE_PATH, "sfdx-project.json"), "utf-8");
667
+ packageXmlContent = fs.readFileSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/package.xml"), "utf-8");
668
+ profileContent = fs.readFileSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/profiles/Admin.profile-meta.xml"), "utf-8");
669
+ permSetContent = fs.readFileSync(path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/permissionsets/SalesRepresentative.permissionset-meta.xml"), "utf-8");
670
+ });
671
+
672
+ it("should reference Apex classes consistently", () => {
673
+ // package.xml lists ApexClass members
674
+ expect(packageXmlContent).toContain("<members>AccountController</members>");
675
+
676
+ // Profile enables AccountController
677
+ expect(profileContent).toContain("<apexClass>AccountController</apexClass>");
678
+
679
+ // PermissionSet enables AccountController
680
+ expect(permSetContent).toContain("<apexClass>AccountController</apexClass>");
681
+ });
682
+
683
+ it("should reference flows consistently", () => {
684
+ // package.xml lists Flow members
685
+ expect(packageXmlContent).toContain("<members>Account_Create</members>");
686
+ expect(packageXmlContent).toContain("<members>Opportunity_Update</members>");
687
+
688
+ // Profile enables both flows
689
+ expect(profileContent).toContain("<flow>Account_Create</flow>");
690
+ expect(profileContent).toContain("<flow>Opportunity_Update</flow>");
691
+
692
+ // PermissionSet enables Account_Create
693
+ expect(permSetContent).toContain("<flow>Account_Create</flow>");
694
+ });
695
+
696
+ it("should reference CustomObject__c consistently", () => {
697
+ // package.xml has CustomObject with CustomObject__c
698
+ expect(packageXmlContent).toContain("<members>CustomObject__c</members>");
699
+
700
+ // Profile has object permissions for CustomObject__c
701
+ expect(profileContent).toMatch(/<objectPermissions>[\s\S]*?<object>CustomObject__c<\/object>[\s\S]*?<\/objectPermissions>/);
702
+
703
+ // PermissionSet has object permissions for CustomObject__c
704
+ expect(permSetContent).toMatch(/<objectPermissions>[\s\S]*?<object>CustomObject__c<\/object>[\s\S]*?<\/objectPermissions>/);
705
+
706
+ // Profile has field permissions for CustomObject__c fields
707
+ expect(profileContent).toContain("<field>CustomObject__c.Amount__c</field>");
708
+ expect(profileContent).toContain("<field>CustomObject__c.Category__c</field>");
709
+
710
+ // PermissionSet has field permissions for CustomObject__c fields
711
+ expect(permSetContent).toContain("<field>CustomObject__c.Amount__c</field>");
712
+ expect(permSetContent).toContain("<field>CustomObject__c.Category__c</field>");
713
+ });
714
+
715
+ it("should have Profile listed in package.xml", () => {
716
+ expect(packageXmlContent).toMatch(/<types>[\s\S]*?<members>Admin<\/members>[\s\S]*?<name>Profile<\/name>[\s\S]*?<\/types>/);
717
+ });
718
+
719
+ it("should have PermissionSet listed in package.xml", () => {
720
+ expect(packageXmlContent).toMatch(/<types>[\s\S]*?<members>SalesRepresentative<\/members>[\s\S]*?<name>PermissionSet<\/name>[\s\S]*?<\/types>/);
721
+ });
722
+ });
723
+
724
+ describe("Metadata Component File Existence", () => {
725
+ it("should have all Apex class files", () => {
726
+ const apexClasses = [
727
+ "AccountController.cls",
728
+ "AccountControllerTest.cls",
729
+ "OpportunityBatch.cls",
730
+ "OpportunityBatchTest.cls",
731
+ "OpportunityTriggerHandler.cls",
732
+ "OpportunityTriggerHelper.cls",
733
+ "Logger.cls",
734
+ "TriggerManagement.cls"
735
+ ];
736
+
737
+ for (const apexClass of apexClasses) {
738
+ const filePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/classes", apexClass);
739
+ expect(fs.existsSync(filePath)).toBe(true);
740
+ }
741
+ });
742
+
743
+ it("should have Apex trigger file", () => {
744
+ const triggerPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/triggers/OpportunityTrigger.trigger");
745
+ expect(fs.existsSync(triggerPath)).toBe(true);
746
+ });
747
+
748
+ it("should have LWC component files", () => {
749
+ const lwcComponents = ["accountList", "opportunityCard"];
750
+
751
+ for (const component of lwcComponents) {
752
+ const componentDir = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc", component);
753
+ expect(fs.existsSync(path.join(componentDir, `${component}.js`))).toBe(true);
754
+ expect(fs.existsSync(path.join(componentDir, `${component}.html`))).toBe(true);
755
+ expect(fs.existsSync(path.join(componentDir, `${component}.css`))).toBe(true);
756
+ expect(fs.existsSync(path.join(componentDir, `${component}.js-meta.xml`))).toBe(true);
757
+ }
758
+ });
759
+
760
+ it("should have Flow metadata files", () => {
761
+ const flows = ["Account_Create.flow-meta.xml", "Opportunity_Update.flow-meta.xml"];
762
+
763
+ for (const flow of flows) {
764
+ const flowPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows", flow);
765
+ expect(fs.existsSync(flowPath)).toBe(true);
766
+ }
767
+ });
768
+
769
+ it("should have CustomObject metadata file", () => {
770
+ const objectPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/objects/CustomObject__c/CustomObject__c.object-meta.xml");
771
+ expect(fs.existsSync(objectPath)).toBe(true);
772
+ });
773
+ });
774
+
775
+ describe("SFDX API Version Consistency", () => {
776
+ it("should have consistent API version across project", () => {
777
+ const sfdxProjectPath = path.join(SALESFORCE_ENTERPRISE_PATH, "sfdx-project.json");
778
+ const packageXmlPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/package.xml");
779
+
780
+ const sfdxProjectContent = fs.readFileSync(sfdxProjectPath, "utf-8");
781
+ const packageXmlContent = fs.readFileSync(packageXmlPath, "utf-8");
782
+
783
+ const sfdxProjectJson = JSON.parse(sfdxProjectContent);
784
+ const sourceApiVersion = sfdxProjectJson.sourceApiVersion;
785
+
786
+ // package.xml version
787
+ expect(packageXmlContent).toContain(`<version>${sourceApiVersion}</version>`);
788
+
789
+ // Flow API versions
790
+ const accountCreateFlowPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
791
+ const opportunityUpdateFlowPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
792
+ const accountCreateFlowContent = fs.readFileSync(accountCreateFlowPath, "utf-8");
793
+ const opportunityUpdateFlowContent = fs.readFileSync(opportunityUpdateFlowPath, "utf-8");
794
+
795
+ expect(accountCreateFlowContent).toContain(`<apiVersion>${sourceApiVersion}</apiVersion>`);
796
+ expect(opportunityUpdateFlowContent).toContain(`<apiVersion>${sourceApiVersion}</apiVersion>`);
797
+ });
798
+ });
799
+ });
800
+
801
+ // =========================================================================
802
+ // UNIT TESTS - SFDX Metadata XML parsing patterns
803
+ // =========================================================================
804
+
805
+ describe("Unit: SFDX Metadata XML parsing patterns", () => {
806
+
807
+ describe("sfdx-project.json parsing", () => {
808
+ it("should parse valid sfdx-project.json structure", () => {
809
+ const sfdxJson = {
810
+ packageDirectories: [{
811
+ path: "force-app",
812
+ default: true,
813
+ package: "TestPackage",
814
+ versionName: "ver 1.0",
815
+ versionNumber: "1.0.0.NEXT"
816
+ }],
817
+ name: "TestProject",
818
+ namespace: "",
819
+ sfdcLoginUrl: "https://login.salesforce.com",
820
+ singlePackage: false,
821
+ sourceApiVersion: "59.0"
822
+ };
823
+
824
+ expect(sfdxJson.packageDirectories[0].path).toBe("force-app");
825
+ expect(sfdxJson.packageDirectories[0].default).toBe(true);
826
+ expect(sfdxJson.name).toBe("TestProject");
827
+ expect(sfdxJson.sourceApiVersion).toBe("59.0");
828
+ });
829
+
830
+ it("should handle namespace correctly", () => {
831
+ const sfdxJson = {
832
+ namespace: "my_namespace"
833
+ };
834
+ expect(sfdxJson.namespace).toBe("my_namespace");
835
+ });
836
+
837
+ it("should handle empty namespace", () => {
838
+ const sfdxJson = {
839
+ namespace: ""
840
+ };
841
+ expect(sfdxJson.namespace).toBe("");
842
+ });
843
+ });
844
+
845
+ describe("package.xml parsing", () => {
846
+ it("should parse package.xml type structure", () => {
847
+ const packageXml = `<?xml version="1.0" encoding="UTF-8"?>
848
+ <Package xmlns="http://soap.sforce.com/2006/04/metadata">
849
+ <types>
850
+ <members>TestClass</members>
851
+ <name>ApexClass</name>
852
+ </types>
853
+ <version>59.0</version>
854
+ </Package>`;
855
+
856
+ expect(packageXml).toContain("<name>ApexClass</name>");
857
+ expect(packageXml).toContain("<members>TestClass</members>");
858
+ expect(packageXml).toContain("<version>59.0</version>");
859
+ });
860
+
861
+ it("should parse multiple type members", () => {
862
+ const packageXml = `<?xml version="1.0" encoding="UTF-8"?>
863
+ <Package xmlns="http://soap.sforce.com/2006/04/metadata">
864
+ <types>
865
+ <members>Class1</members>
866
+ <members>Class2</members>
867
+ <members>Class3</members>
868
+ <name>ApexClass</name>
869
+ </types>
870
+ </Package>`;
871
+
872
+ const memberMatches = packageXml.match(/<members>\w+<\/members>/g);
873
+ expect(memberMatches).toHaveLength(3);
874
+ });
875
+ });
876
+
877
+ describe("Profile XML parsing", () => {
878
+ it("should parse fieldPermissions structure", () => {
879
+ const profileXml = `<?xml version="1.0" encoding="UTF-8"?>
880
+ <Profile xmlns="http://soap.sforce.com/2006/04/metadata">
881
+ <fieldPermissions>
882
+ <field>Account.Name</field>
883
+ <readable>true</readable>
884
+ <editable>true</editable>
885
+ </fieldPermissions>
886
+ </Profile>`;
887
+
888
+ expect(profileXml).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Name<\/field>[\s\S]*?<\/fieldPermissions>/);
889
+ expect(profileXml).toContain("<readable>true</readable>");
890
+ expect(profileXml).toContain("<editable>true</editable>");
891
+ });
892
+
893
+ it("should parse objectPermissions structure", () => {
894
+ const profileXml = `<?xml version="1.0" encoding="UTF-8"?>
895
+ <Profile xmlns="http://soap.sforce.com/2006/04/metadata">
896
+ <objectPermissions>
897
+ <allowCreate>true</allowCreate>
898
+ <allowDelete>true</allowDelete>
899
+ <allowEdit>true</allowEdit>
900
+ <allowRead>true</allowRead>
901
+ <modifyAllRecords>true</modifyAllRecords>
902
+ <object>Account</object>
903
+ </objectPermissions>
904
+ </Profile>`;
905
+
906
+ expect(profileXml).toMatch(/<objectPermissions>[\s\S]*?<object>Account<\/object>[\s\S]*?<\/objectPermissions>/);
907
+ expect(profileXml).toContain("<allowCreate>true</allowCreate>");
908
+ expect(profileXml).toContain("<modifyAllRecords>true</modifyAllRecords>");
909
+ });
910
+
911
+ it("should parse classAccesses structure", () => {
912
+ const profileXml = `<?xml version="1.0" encoding="UTF-8"?>
913
+ <Profile xmlns="http://soap.sforce.com/2006/04/metadata">
914
+ <classAccesses>
915
+ <apexClass>TestClass</apexClass>
916
+ <enabled>true</enabled>
917
+ </classAccesses>
918
+ </Profile>`;
919
+
920
+ expect(profileXml).toMatch(/<classAccesses>[\s\S]*?<apexClass>TestClass<\/apexClass>[\s\S]*?<\/classAccesses>/);
921
+ expect(profileXml).toContain("<enabled>true</enabled>");
922
+ });
923
+ });
924
+
925
+ describe("PermissionSet XML parsing", () => {
926
+ it("should parse PermissionSet basic structure", () => {
927
+ const permSetXml = `<?xml version="1.0" encoding="UTF-8"?>
928
+ <PermissionSet xmlns="http://salesforce.com/2006/04/metadata">
929
+ <custom>false</custom>
930
+ <label>Test Permission Set</label>
931
+ <description>Test description</description>
932
+ </PermissionSet>`;
933
+
934
+ expect(permSetXml).toContain("<label>Test Permission Set</label>");
935
+ expect(permSetXml).toContain("<description>Test description</description>");
936
+ expect(permSetXml).toContain("<custom>false</custom>");
937
+ });
938
+
939
+ it("should parse fieldPermissions with readable and editable", () => {
940
+ const permSetXml = `<?xml version="1.0" encoding="UTF-8"?>
941
+ <PermissionSet xmlns="http://salesforce.com/2006/04/metadata">
942
+ <fieldPermissions>
943
+ <field>Account.Name</field>
944
+ <readable>true</readable>
945
+ <editable>false</editable>
946
+ </fieldPermissions>
947
+ </PermissionSet>`;
948
+
949
+ expect(permSetXml).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Name<\/field>[\s\S]*?<\/fieldPermissions>/);
950
+ expect(permSetXml).toContain("<readable>true</readable>");
951
+ expect(permSetXml).toContain("<editable>false</editable>");
952
+ });
953
+
954
+ it("should parse objectPermissions with viewAllRecords and modifyAllRecords", () => {
955
+ const permSetXml = `<?xml version="1.0" encoding="UTF-8"?>
956
+ <PermissionSet xmlns="http://salesforce.com/2006/04/metadata">
957
+ <objectPermissions>
958
+ <allowCreate>true</allowCreate>
959
+ <allowEdit>true</allowEdit>
960
+ <allowRead>true</allowRead>
961
+ <viewAllRecords>false</viewAllRecords>
962
+ <modifyAllRecords>false</modifyAllRecords>
963
+ <object>Account</object>
964
+ </objectPermissions>
965
+ </PermissionSet>`;
966
+
967
+ expect(permSetXml).toContain("<viewAllRecords>false</viewAllRecords>");
968
+ expect(permSetXml).toContain("<modifyAllRecords>false</modifyAllRecords>");
969
+ });
970
+
971
+ it("should parse userPermissions", () => {
972
+ const permSetXml = `<?xml version="1.0" encoding="UTF-8"?>
973
+ <PermissionSet xmlns="http://salesforce.com/2006/04/metadata">
974
+ <userPermissions>
975
+ <name>ViewReadonlyFields</name>
976
+ <enabled>true</enabled>
977
+ </userPermissions>
978
+ </PermissionSet>`;
979
+
980
+ expect(permSetXml).toMatch(/<userPermissions>[\s\S]*?<name>ViewReadonlyFields<\/name>[\s\S]*?<\/userPermissions>/);
981
+ expect(permSetXml).toContain("<enabled>true</enabled>");
982
+ });
983
+ });
984
+ });
985
+
986
+ // =========================================================================
987
+ // EDGE CASES
988
+ // =========================================================================
989
+
990
+ describe("Edge Cases", () => {
991
+
992
+ describe("SFDX Project Edge Cases", () => {
993
+ it("should handle empty namespace", () => {
994
+ const sfdxProjectPath = path.join(SALESFORCE_ENTERPRISE_PATH, "sfdx-project.json");
995
+ const content = fs.readFileSync(sfdxProjectPath, "utf-8");
996
+ const json = JSON.parse(content);
997
+ expect(json.namespace).toBe("");
998
+ });
999
+
1000
+ it("should handle singlePackage=false", () => {
1001
+ const sfdxProjectPath = path.join(SALESFORCE_ENTERPRISE_PATH, "sfdx-project.json");
1002
+ const content = fs.readFileSync(sfdxProjectPath, "utf-8");
1003
+ const json = JSON.parse(content);
1004
+ expect(json.singlePackage).toBe(false);
1005
+ });
1006
+
1007
+ it("should handle versionNumber with NEXT", () => {
1008
+ const sfdxProjectPath = path.join(SALESFORCE_ENTERPRISE_PATH, "sfdx-project.json");
1009
+ const content = fs.readFileSync(sfdxProjectPath, "utf-8");
1010
+ const json = JSON.parse(content);
1011
+ expect(json.packageDirectories[0].versionNumber).toBe("1.0.0.NEXT");
1012
+ });
1013
+ });
1014
+
1015
+ describe("Profile Edge Cases", () => {
1016
+ let profileContent: string;
1017
+
1018
+ beforeAll(() => {
1019
+ const profilePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/profiles/Admin.profile-meta.xml");
1020
+ profileContent = fs.readFileSync(profilePath, "utf-8");
1021
+ });
1022
+
1023
+ it("should handle read-only field permissions", () => {
1024
+ // Account.Total_Opportunity_Amount__c has readable=true, editable=false
1025
+ expect(profileContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Total_Opportunity_Amount__c<\/field>[\s\S]*?<readable>true<\/readable>[\s\S]*?<editable>false<\/editable>[\s\S]*?<\/fieldPermissions>/);
1026
+ });
1027
+
1028
+ it("should handle multiple layoutAssignments", () => {
1029
+ const layoutMatches = profileContent.match(/<layoutAssignments>[\s\S]*?<\/layoutAssignments>/g);
1030
+ expect(layoutMatches).toHaveLength(3);
1031
+ });
1032
+
1033
+ it("should handle recordTypeVisibilities with different default/visible settings", () => {
1034
+ // Customer_Account: default=true, visible=true
1035
+ // PersonAccount: default=false, visible=false
1036
+ expect(profileContent).toMatch(/<recordTypeVisibilities>[\s\S]*?<recordType>Account\.Customer_Account<\/recordType>[\s\S]*?<default>true<\/default>[\s\S]*?<visible>true<\/visible>[\s\S]*?<\/recordTypeVisibilities>/);
1037
+ expect(profileContent).toMatch(/<recordTypeVisibilities>[\s\S]*?<recordType>Account\.PersonAccount<\/recordType>[\s\S]*?<default>false<\/default>[\s\S]*?<visible>false<\/visible>[\s\S]*?<\/recordTypeVisibilities>/);
1038
+ });
1039
+ });
1040
+
1041
+ describe("PermissionSet Edge Cases", () => {
1042
+ let permSetContent: string;
1043
+
1044
+ beforeAll(() => {
1045
+ const permSetPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/permissionsets/SalesRepresentative.permissionset-meta.xml");
1046
+ permSetContent = fs.readFileSync(permSetPath, "utf-8");
1047
+ });
1048
+
1049
+ it("should handle hasActivationRequired=false", () => {
1050
+ expect(permSetContent).toContain("<hasActivationRequired>false</hasActivationRequired>");
1051
+ });
1052
+
1053
+ it("should handle limited object permissions", () => {
1054
+ // PermissionSet has allowCreate=true, allowDelete=false, allowEdit=true, allowRead=true
1055
+ // modifyAllRecords=false, viewAllRecords=false
1056
+ expect(permSetContent).toMatch(/<objectPermissions>[\s\S]*?<allowDelete>false<\/allowDelete>[\s\S]*?<\/objectPermissions>/);
1057
+ expect(permSetContent).toMatch(/<objectPermissions>[\s\S]*?<modifyAllRecords>false<\/modifyAllRecords>[\s\S]*?<\/objectPermissions>/);
1058
+ expect(permSetContent).toMatch(/<objectPermissions>[\s\S]*?<viewAllRecords>false<\/viewAllRecords>[\s\S]*?<\/objectPermissions>/);
1059
+ });
1060
+
1061
+ it("should handle multiple field permissions with different editable settings", () => {
1062
+ // Account.AnnualRevenue: readable=true, editable=false
1063
+ // Account.Name: readable=true, editable=true
1064
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.AnnualRevenue<\/field>[\s\S]*?<readable>true<\/readable>[\s\S]*?<editable>false<\/editable>[\s\S]*?<\/fieldPermissions>/);
1065
+ expect(permSetContent).toMatch(/<fieldPermissions>[\s\S]*?<field>Account\.Name<\/field>[\s\S]*?<readable>true<\/readable>[\s\S]*?<editable>true<\/editable>[\s\S]*?<\/fieldPermissions>/);
1066
+ });
1067
+ });
1068
+
1069
+ describe("Package.xml Edge Cases", () => {
1070
+ it("should handle mixed component types", () => {
1071
+ const packageXmlPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/package.xml");
1072
+ const content = fs.readFileSync(packageXmlPath, "utf-8");
1073
+
1074
+ // 7 different type elements
1075
+ const typeNames = content.match(/<name>\w+<\/name>/g);
1076
+ expect(typeNames).toHaveLength(7);
1077
+
1078
+ // All types should be unique
1079
+ const uniqueTypes = [...new Set(typeNames)];
1080
+ expect(uniqueTypes).toHaveLength(7);
1081
+ });
1082
+
1083
+ it("should handle types with single member", () => {
1084
+ const packageXmlPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/package.xml");
1085
+ const content = fs.readFileSync(packageXmlPath, "utf-8");
1086
+
1087
+ // ApexTrigger has 1 member
1088
+ expect(content).toMatch(/<members>OpportunityTrigger<\/members>[\s\S]*?<name>ApexTrigger<\/name>[\s\S]*?<\/types>/);
1089
+
1090
+ // CustomObject has 1 member
1091
+ expect(content).toMatch(/<members>CustomObject__c<\/members>[\s\S]*?<name>CustomObject<\/name>[\s\S]*?<\/types>/);
1092
+
1093
+ // Profile has 1 member
1094
+ expect(content).toMatch(/<members>Admin<\/members>[\s\S]*?<name>Profile<\/name>[\s\S]*?<\/types>/);
1095
+
1096
+ // PermissionSet has 1 member
1097
+ expect(content).toMatch(/<members>SalesRepresentative<\/members>[\s\S]*?<name>PermissionSet<\/name>[\s\S]*?<\/types>/);
1098
+ });
1099
+
1100
+ it("should handle types with multiple members", () => {
1101
+ const packageXmlPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/package.xml");
1102
+ const content = fs.readFileSync(packageXmlPath, "utf-8");
1103
+
1104
+ // ApexClass has 9 members - extract by finding the section between types tags
1105
+ const apexClassSection = content.substring(content.indexOf("<members>AccountController</members>"), content.indexOf("</types>"));
1106
+ const apexMembers = apexClassSection.match(/<members>\w+<\/members>/g);
1107
+ expect(apexMembers).toHaveLength(9);
1108
+
1109
+ // LightningComponentBundle has 2 members
1110
+ const lwcStart = content.indexOf("<members>accountList</members>");
1111
+ const lwcEnd = content.indexOf("</types>", lwcStart);
1112
+ const lwcSection = content.substring(lwcStart - 100, lwcEnd);
1113
+ const lwcMembers = lwcSection.match(/<members>\w+<\/members>/g);
1114
+ expect(lwcMembers).toHaveLength(2);
1115
+
1116
+ // Flow has 2 members
1117
+ const flowStart = content.indexOf("<members>Account_Create</members>");
1118
+ const flowEnd = content.indexOf("</types>", flowStart);
1119
+ const flowSection = content.substring(flowStart - 100, flowEnd);
1120
+ const flowMembers = flowSection.match(/<members>\w+<\/members>/g);
1121
+ expect(flowMembers).toHaveLength(2);
1122
+ });
1123
+ });
1124
+ });
1125
+ });